1 /**
2 * Copyright 2003-2006 Greg Luck
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.distribution;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21
22 import java.util.List;
23 import java.util.zip.GZIPOutputStream;
24 import java.util.zip.GZIPInputStream;
25 import java.rmi.RemoteException;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.ByteArrayInputStream;
29
30 /**
31 * This class provides utility methods for assembling and disassembling a heartbeat payload.
32 * <p/>
33 * Care is taken to fit the payload into the MTU of ethernet, which is 1500 bytes.
34 * The algorithms in this class are capable of creating payloads for CacheManagers containing
35 * approximately 500 caches to be replicated.
36 *
37 * @author <a href="mailto:gluck@thoughtworks.com">Greg Luck</a>
38 * @version $Id: PayloadUtil.java 52 2006-04-24 14:50:03Z gregluck $
39 */
40 final class PayloadUtil {
41
42 /**
43 * The maximum transmission unit. This varies by link layer. For ethernet, fast ethernet and
44 * gigabit ethernet it is 1500 bytes, the value chosen.
45 * <p/>
46 * Payloads are limited to this so that there is no fragmentation and no necessity for a complex
47 * reassembly protocol.
48 */
49 public static final int MTU = 1500;
50
51 /**
52 * Delmits URLS sent via heartbeats over sockets
53 */
54 public static final String URL_DELIMITER = "|";
55
56 private static final Log LOG = LogFactory.getLog(PayloadUtil.class.getName());
57
58
59 /**
60 * Utility class therefore precent construction
61 */
62 private PayloadUtil() {
63
64 }
65
66 /**
67 * Assembles a list of URLs
68 *
69 * @param localCachePeers
70 * @return an uncompressed payload with catenated rmiUrls.
71 */
72 public static byte[] assembleUrlList(List localCachePeers) {
73 StringBuffer sb = new StringBuffer();
74 for (int i = 0; i < localCachePeers.size(); i++) {
75 CachePeer cachePeer = (CachePeer) localCachePeers.get(i);
76 String rmiUrl = null;
77 try {
78 rmiUrl = cachePeer.getUrl();
79 } catch (RemoteException e) {
80 LOG.error("This should never be thrown as it is called locally");
81 }
82 if (i != localCachePeers.size() - 1) {
83 sb.append(rmiUrl).append(URL_DELIMITER);
84 } else {
85 sb.append(rmiUrl);
86 }
87 }
88 if (LOG.isDebugEnabled()) {
89 LOG.debug("Cache peers: " + sb);
90 }
91 return sb.toString().getBytes();
92 }
93
94 /**
95 * Gzips a byte[]. For text, approximately 10:1 compression is achieved.
96 * @param ungzipped the bytes to be gzipped
97 * @return gzipped bytes
98 */
99 public static byte[] gzip(byte[] ungzipped) {
100 final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
101 try {
102 final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(bytes);
103 gzipOutputStream.write(ungzipped);
104 gzipOutputStream.close();
105 } catch (IOException e) {
106 LOG.fatal("Could not gzip " + ungzipped);
107 }
108 return bytes.toByteArray();
109 }
110
111 /**
112 * The fastest Ungzip implementation. See PageInfoTest in ehcache-constructs.
113 * A high performance implementation, although not as fast as gunzip3.
114 * gunzips 100000 of ungzipped content in 9ms on the reference machine.
115 * It does not use a fixed size buffer and is therefore suitable for arbitrary
116 * length arrays.
117 *
118 * @param gzipped
119 * @return a plain, uncompressed byte[]
120 */
121 public static byte[] ungzip(final byte[] gzipped) {
122 byte[] ungzipped = new byte[0];
123 try {
124 final GZIPInputStream inputStream = new GZIPInputStream(new ByteArrayInputStream(gzipped));
125 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(gzipped.length);
126 final byte[] buffer = new byte[PayloadUtil.MTU];
127 int bytesRead = 0;
128 while (bytesRead != -1) {
129 bytesRead = inputStream.read(buffer, 0, PayloadUtil.MTU);
130 if (bytesRead != -1) {
131 byteArrayOutputStream.write(buffer, 0, bytesRead);
132 }
133 }
134 ungzipped = byteArrayOutputStream.toByteArray();
135 inputStream.close();
136 byteArrayOutputStream.close();
137 } catch (IOException e) {
138 LOG.fatal("Could not ungzip. Heartbeat will not be working. " + e.getMessage());
139 }
140 return ungzipped;
141 }
142
143
144
145 }