View Javadoc

1   /* (c) Copyright 2003 Caleigo AB, All rights reserved. 
2    * 
3    * This library is free software; you can redistribute it and/or
4    * modify it under the terms of the GNU Lesser General Public
5    * License as published by the Free Software Foundation; either
6    * version 2.1 of the License, or (at your option) any later version.
7    * 
8    * This library is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   * Lesser General Public License for more details.
12   * 
13   * You should have received a copy of the GNU Lesser General Public
14   * License along with this library; if not, write to the Free Software
15   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   *  
17   */
18  
19  package org.caleigo.toolkit.tunnel;
20  
21  
22  import java.io.*;
23  import java.util.zip.*;
24  
25  import org.caleigo.toolkit.log.*;
26  import org.caleigo.toolkit.util.CircularByteBuffer;
27  
28  /***
29   *
30   * @author  Mattias Hagstrand
31   * @version 1.00
32   * 
33   *//* 
34   *
35   * WHEN        WHO               WHY & WHAT
36   * -----------------------------------------------------------------------------
37   * 2002-07-05  Mattias Hagstrand Creation
38   */
39  public class ZipPacker implements ITunnelPacker
40  {
41      // Constructors ------------------------------------------------------------
42      public ZipPacker()
43      {
44      }
45      
46      // ITunnelPacker implementation --------------------------------------------
47      
48      /***
49       * Creates and returns an InputStream that wrapps the provided InputStream.
50       * The returned InputStream can then be used to unpack messages. The returned
51       * InputStream must be stateless.
52       */
53      public InputStream createInputStream(InputStream in)
54      {
55          return new ZipPackerInputStream(in, 1024 * 64);
56      }
57      
58      /***
59       * Creates and returns an OutputStream that wrapps the provided OutputStream.
60       * The returned OutputStream can then be used to pack messages. The returned
61       * OutputStream must be stateless.
62       */
63      public OutputStream createOutputStream(OutputStream out)
64      {
65          return new ZipPackerOutputStream(out, 1024 * 64);
66      }
67      
68      // Nested classes ----------------------------------------------------------
69      protected class ZipPackerOutputStream extends FilterOutputStream
70      {
71          // Data members --------------------------------------------------------
72          protected byte[] mByteBuffer;
73          protected int mBufferSize;
74          protected int mCurrentPosition;
75          
76          protected ZipOutputStream mZipOutputStream;
77          protected int mZipEntryID;
78          
79          // Constructors --------------------------------------------------------
80          
81          /***
82           * Creates a ZipPackerOutputStream that wrapps an OutputStream.
83           *
84           * @param out   the OutputStream that should be used to write the zipped
85           *              data to.
86           * @param bufferSize    the initial size of the internal buffer. The size
87           *                      of the buffer is increased as needed. Each time
88           *                      the buffer needs to be resized its size is increased
89           *                      by bufferSize / 2 bytes.
90           */
91          public ZipPackerOutputStream(OutputStream out, int bufferSize)
92          {
93              super(out);
94              mByteBuffer = new byte[bufferSize];
95              mBufferSize = bufferSize;
96              mZipOutputStream = new ZipOutputStream(out);
97              mZipOutputStream.setLevel(Deflater.BEST_COMPRESSION);
98          }
99          
100         // Superclass overrides ------------------------------------------------
101         /*public void close()
102             throws IOException
103         {
104             try
105             {
106                 mZipOutputStream.close();
107             }
108             catch (IOException e) {}
109             out.close();
110         }*/
111         
112         public void write(int b)
113             throws IOException
114         {
115             // If the buffer is full increase the size of the buffer
116             if (mCurrentPosition >= mByteBuffer.length)
117             {
118                 byte[] newBuffer = new byte[mByteBuffer.length + mBufferSize / 2];
119                 System.arraycopy(mByteBuffer, 0, newBuffer, 0, mByteBuffer.length);
120                 mByteBuffer = newBuffer;
121             }
122                 
123             // Save the byte in the buffer
124             mByteBuffer[mCurrentPosition] = (byte) b;
125             mCurrentPosition++;
126         }
127         
128         public void flush()
129             throws IOException
130         {
131             Log.print(this, "flush(): " + mCurrentPosition + " bytes");
132             ZipEntry entry = new ZipEntry(Integer.toString(this.getNextZipEntryID()));
133             mZipOutputStream.putNextEntry(entry);
134             mZipOutputStream.write(mByteBuffer, 0, mCurrentPosition);
135             mZipOutputStream.closeEntry();
136             mZipOutputStream.flush();
137             mCurrentPosition = 0;
138         }
139         
140         // Help methods --------------------------------------------------------
141         protected int getNextZipEntryID()
142         {
143             mZipEntryID = (mZipEntryID < Integer.MAX_VALUE ? mZipEntryID + 1 : 0);
144             return mZipEntryID;
145         }
146     }
147     
148     /***
149      * Uses a ZipInputStream to read and unzip data from an InputStream. It uses
150      * a circular buffer to store the unziped data.
151      */
152     protected class ZipPackerInputStream extends FilterInputStream
153     {
154         // Data members --------------------------------------------------------
155         protected byte[] mInByteBuffer;
156         protected byte[] mSingleByteBuffer = new byte[1];
157         protected CircularByteBuffer mDecompressedByteBuffer;
158         
159         protected ZipInputStream mZipInputStream;
160         
161         // Constructors --------------------------------------------------------
162         
163         /***
164          * Creates a ZipPackerInputStream that wrapps an InputStream.
165          *
166          * @param in   the InputStream that should be used to read the zipped
167          *              data to from.
168          * @param bufferSize    the initial size of the internal buffer. The size
169          *                      of the buffer is increased as needed. Each time
170          *                      the buffer needs to be resized its size is increased
171          *                      by bufferSize / 2 bytes.
172          */
173         public ZipPackerInputStream(InputStream in, int bufferSize)
174         {
175             super(in);
176             mInByteBuffer = new byte[bufferSize];
177             mDecompressedByteBuffer = new CircularByteBuffer(bufferSize);
178             mZipInputStream = new ZipInputStream(in);
179         }
180         
181         // Superclass overrides ------------------------------------------------
182         public int available()
183             throws IOException
184         {
185             Log.print(this, "return from available(): " + mDecompressedByteBuffer.getBufferSize());
186             return mDecompressedByteBuffer.getBufferSize();
187         }
188         
189         /*public void close()
190             throws IOException
191         {
192             try
193             {
194                 in.close();
195             }
196             catch (IOException e) {}
197             mZipInputStream.close();
198         }*/
199         
200         public int read()
201             throws IOException
202         {
203             this.read(mSingleByteBuffer, 0, 1);
204             return mSingleByteBuffer[0];
205         }
206         
207         public int read(byte[] b, int off, int len)
208             throws IOException
209         {
210             while (mDecompressedByteBuffer.getBufferSize() == 0)
211                 this.readFromZipStream();
212             
213             return mDecompressedByteBuffer.getFromBuffer(b, off, len);
214         }
215         
216         // Help methods --------------------------------------------------------
217         protected void readFromZipStream()
218             throws IOException
219         {
220             ZipEntry zipEntry = mZipInputStream.getNextEntry();
221             if (zipEntry == null)
222                 throw new IOException("Couldn't read zip entry");
223             int nbrOfBytesRead = 0;
224             while ((nbrOfBytesRead = mZipInputStream.read(mInByteBuffer, 0, mInByteBuffer.length)) > -1)
225             {
226                 mDecompressedByteBuffer.addToBuffer(mInByteBuffer, 0, nbrOfBytesRead);
227             }
228             Log.print(this, "Unzip message successfully: " + zipEntry.getSize() + "(" + zipEntry.getCompressedSize() + ")");
229             mZipInputStream.closeEntry();
230         }
231     }
232 }