KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > faceless > pdf2 > DiskCache


1 // $Id: DiskCache.java,v 1.11 2005/02/17 14:46:59 mike Exp $
2

3 package org.faceless.pdf2;
4
5 import java.io.*;
6
7 /**
8  * A general purpose {@link Cache} which optionally writes closed streams
9  * to files on disk. This class has been tested on UNIX and Windows under
10  * multi-threaded environments, and we see no reason why it shouldn't work
11  * under other platforms as well.
12  * @see PDF#setCache
13  * @since 2.2.2
14  */

15 public class DiskCache implements Cache
16 {
17     private static int next; // The next number. Static just in case two DiskCaches
18
// are created on the same directory.
19

20     private final String JavaDoc prefix; // The directory to store the cached files in
21
private final int threshold; // The smallest stream to write to disk
22

23     /**
24      * Create a new DiskCache
25      *
26      * @param prefix The prefix to begin the cached filenames with. For instance, if
27      * prefix was "/tmp/cache/mycache.", the cache files would be "/tmp/cache/mycache.0",
28      * "/tmp/cache/mycache.1" etc.
29      *
30      * @param threshold the minimum number of bytes that are considered worth caching to
31      * disk, or 0 to prevent caching altogether
32      */

33     public DiskCache(String JavaDoc prefix, int threshold)
34     {
35         this.prefix = prefix;
36         this.threshold = threshold==0 || prefix==null ? Integer.MAX_VALUE : threshold;
37     }
38
39
40     public Cache.Entry newEntry(int size)
41     {
42         return new DiskCacheEntry(size);
43     }
44
45     /**
46      * Return the next filename to be used in the cache (of the form "prefixnnn")
47      */

48     private synchronized File nextFileName()
49     {
50         return prefix==null ? null : new File(prefix+(next++));
51     }
52
53
54     private class DiskCacheEntry extends OutputStream implements Cache.Entry
55     {
56         private OutputStream out;
57         private File file; // null if data held in memory
58
private int count;
59         private boolean closed;
60
61         public DiskCacheEntry(int size)
62         {
63             if (prefix!=null && size>threshold) {
64                 try {
65                     toDisk();
66                 } catch (IOException e) {
67                     throw new Error JavaDoc("Cannot create File \""+file+"\": "+e);
68                 }
69             } else {
70                 out = new MyByteArrayOutputStream(size);
71             }
72         }
73
74         public OutputStream getOutputStream()
75         {
76             if (closed) throw new IllegalStateException JavaDoc("Can't write to closed stream \""+file+"\"");
77             return this;
78         }
79
80         public InputStream getInputStream()
81         {
82             if (file!=null) {
83                 try {
84                     if (!closed) out.flush();
85                     return new BufferedInputStream(new FileInputStream(file));
86                 } catch (IOException e) {
87                     throw new Error JavaDoc("Cannot create FileInputStream for \""+file+"\": "+e);
88                 }
89             } else {
90                 return new ByteArrayInputStream(((MyByteArrayOutputStream)out).buf, 0, count);
91             }
92         }
93
94         public int size()
95         {
96             return count;
97         }
98
99         public void writeTo(OutputStream stream)
100             throws IOException
101         {
102             if (out instanceof MyByteArrayOutputStream) {
103                 stream.write(((MyByteArrayOutputStream)out).buf,0,count);
104             } else {
105                 InputStream in = getInputStream();
106                 byte[] b = new byte[8192];
107                 int l;
108                 while ((l = in.read(b))>=0) {
109                     stream.write(b,0,l);
110                 }
111                 in.close();
112             }
113         }
114
115         public Cache.Entry cloneEntry()
116         {
117             if (closed) {
118                 return this;
119             } else {
120                 DiskCacheEntry copy = new DiskCacheEntry(count);
121                 try {
122                     writeTo(copy.getOutputStream());
123                 } catch (IOException e) {
124                     throw new Error JavaDoc("Cannot clone stream to \""+copy.file+"\": "+e);
125                 }
126                 return copy;
127             }
128         }
129
130         public void close()
131         {
132             if (!closed) {
133                 try {
134                     out.close();
135                 } catch (IOException e) {
136                     throw new Error JavaDoc("Cannot close \""+file+"\": "+e);
137                 }
138                 closed=true;
139             }
140         }
141
142         public String JavaDoc toString()
143         {
144             return "<filecache size="+size()+" file="+file+">";
145         }
146
147         public void finalize()
148         {
149             if (file!=null) file.delete();
150         }
151
152         //----- OutputStream methods from here on ----
153

154         public void write(int b) throws IOException
155         {
156             out.write(b);
157             count++;
158             if (prefix!=null && file==null && count>threshold) toDisk();
159         }
160
161         public void write(byte[] b, int off, int len) throws IOException
162         {
163             if (prefix!=null && file==null && count+len>threshold) toDisk();
164             out.write(b,off,len);
165             count+=len;
166         }
167
168         public void write(byte[] b) throws IOException
169         {
170             write(b,0,b.length);
171         }
172
173         private void toDisk()
174             throws IOException
175         {
176             file = nextFileName();
177             file.deleteOnExit();
178             byte[] buf = out==null ? null : ((MyByteArrayOutputStream)out).buf;
179             out = new BufferedOutputStream(new FileOutputStream(file));
180             if (buf!=null) out.write(buf, 0, count);
181         }
182     }
183
184     private final class MyByteArrayOutputStream extends OutputStream
185     {
186         private int count;
187         byte[] buf;
188
189         MyByteArrayOutputStream(int size)
190         {
191             buf = new byte[size==0 ? 16 : size];
192         }
193
194         public void write(int b)
195         {
196             if (count==buf.length) extend(count+8);
197             buf[count++] = (byte)b;
198         }
199
200         public void write(byte[] b, int off, int len)
201         {
202             if (len==0) {
203                 return;
204             } else if (off<0 || len<0 || off+len > b.length) {
205                 throw new IndexOutOfBoundsException JavaDoc(off+"+"+len+" outside "+b.length);
206             }
207             if (count+len > buf.length) extend(count+len);
208             System.arraycopy(b, off, buf, count, len);
209             count+=len;
210         }
211
212         public void write(byte[] b)
213         {
214             write(b,0,b.length);
215         }
216
217         /**
218          * Increase the capacity of the internal buffer
219          */

220         private final void extend(int newlen)
221         {
222             if (newlen>buf.length) {
223                 if (newlen<buf.length+(buf.length>>1)) newlen=buf.length+(buf.length>>1);
224                 byte[] newbuf = new byte[newlen];
225                 System.arraycopy(buf, 0, newbuf, 0, count);
226                 buf=newbuf;
227             }
228         }
229     }
230 }
231
Popular Tags