View Javadoc

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          //noop
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 }