001: /**
002: * Copyright 2003-2007 Luck Consulting Pty Ltd
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package net.sf.ehcache.distribution;
016:
017: import org.apache.commons.logging.Log;
018: import org.apache.commons.logging.LogFactory;
019:
020: import java.io.ByteArrayInputStream;
021: import java.io.ByteArrayOutputStream;
022: import java.io.IOException;
023: import java.rmi.RemoteException;
024: import java.util.List;
025: import java.util.zip.GZIPInputStream;
026: import java.util.zip.GZIPOutputStream;
027:
028: /**
029: * This class provides utility methods for assembling and disassembling a heartbeat payload.
030: * <p/>
031: * Care is taken to fit the payload into the MTU of ethernet, which is 1500 bytes.
032: * The algorithms in this class are capable of creating payloads for CacheManagers containing
033: * approximately 500 cache peers to be replicated.
034: *
035: * @author <a href="mailto:gluck@thoughtworks.com">Greg Luck</a>
036: * @version $Id: PayloadUtil.java 519 2007-07-27 07:11:45Z gregluck $
037: */
038: final class PayloadUtil {
039:
040: /**
041: * The maximum transmission unit. This varies by link layer. For ethernet, fast ethernet and
042: * gigabit ethernet it is 1500 bytes, the value chosen.
043: * <p/>
044: * Payloads are limited to this so that there is no fragmentation and no necessity for a complex
045: * reassembly protocol.
046: */
047: public static final int MTU = 1500;
048:
049: /**
050: * Delmits URLS sent via heartbeats over sockets
051: */
052: public static final String URL_DELIMITER = "|";
053:
054: private static final Log LOG = LogFactory.getLog(PayloadUtil.class
055: .getName());
056:
057: /**
058: * Utility class therefore precent construction
059: */
060: private PayloadUtil() {
061: //noop
062: }
063:
064: /**
065: * Assembles a list of URLs
066: *
067: * @param localCachePeers
068: * @return an uncompressed payload with catenated rmiUrls.
069: */
070: public static byte[] assembleUrlList(List localCachePeers) {
071: StringBuffer sb = new StringBuffer();
072: for (int i = 0; i < localCachePeers.size(); i++) {
073: CachePeer cachePeer = (CachePeer) localCachePeers.get(i);
074: String rmiUrl = null;
075: try {
076: rmiUrl = cachePeer.getUrl();
077: } catch (RemoteException e) {
078: LOG
079: .error("This should never be thrown as it is called locally");
080: }
081: if (i != localCachePeers.size() - 1) {
082: sb.append(rmiUrl).append(URL_DELIMITER);
083: } else {
084: sb.append(rmiUrl);
085: }
086: }
087: if (LOG.isDebugEnabled()) {
088: LOG
089: .debug("Cache peers for this CacheManager to be advertised: "
090: + sb);
091: }
092: return sb.toString().getBytes();
093: }
094:
095: /**
096: * Gzips a byte[]. For text, approximately 10:1 compression is achieved.
097: * @param ungzipped the bytes to be gzipped
098: * @return gzipped bytes
099: */
100: public static byte[] gzip(byte[] ungzipped) {
101: final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
102: try {
103: final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(
104: bytes);
105: gzipOutputStream.write(ungzipped);
106: gzipOutputStream.close();
107: } catch (IOException e) {
108: LOG.fatal("Could not gzip " + ungzipped);
109: }
110: return bytes.toByteArray();
111: }
112:
113: /**
114: * The fastest Ungzip implementation. See PageInfoTest in ehcache-constructs.
115: * A high performance implementation, although not as fast as gunzip3.
116: * gunzips 100000 of ungzipped content in 9ms on the reference machine.
117: * It does not use a fixed size buffer and is therefore suitable for arbitrary
118: * length arrays.
119: *
120: * @param gzipped
121: * @return a plain, uncompressed byte[]
122: */
123: public static byte[] ungzip(final byte[] gzipped) {
124: byte[] ungzipped = new byte[0];
125: try {
126: final GZIPInputStream inputStream = new GZIPInputStream(
127: new ByteArrayInputStream(gzipped));
128: ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(
129: gzipped.length);
130: final byte[] buffer = new byte[PayloadUtil.MTU];
131: int bytesRead = 0;
132: while (bytesRead != -1) {
133: bytesRead = inputStream
134: .read(buffer, 0, PayloadUtil.MTU);
135: if (bytesRead != -1) {
136: byteArrayOutputStream.write(buffer, 0, bytesRead);
137: }
138: }
139: ungzipped = byteArrayOutputStream.toByteArray();
140: inputStream.close();
141: byteArrayOutputStream.close();
142: } catch (IOException e) {
143: LOG
144: .fatal("Could not ungzip. Heartbeat will not be working. "
145: + e.getMessage());
146: }
147: return ungzipped;
148: }
149:
150: }
|