KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > commons > cbutil > CBJarResource


1 package com.ca.commons.cbutil;
2
3 import java.awt.*;
4 import java.io.*;
5 import java.util.*;
6 import java.util.logging.Level JavaDoc;
7 import java.util.logging.Logger JavaDoc;
8 import java.util.zip.*;
9
10 /**
11  * CBJarResources: CBJarResources maps all resources included in a
12  * Zip or Jar file. Additionaly, it provides methods to extract
13  * them as byte arrays, images, or input streams.<p>
14  * This class makes no distinction between jar and zip files, and
15  * makes no use of any jar manifest file, should it exist.
16  */

17
18 public final class CBJarResource
19 {
20     /**
21      * The contents of the zip file are cached the first time they are used, to
22      * speed any subsequent access of the same resource.
23      */

24     protected Hashtable contents = new Hashtable();
25
26     /**
27      * When the CBJarResource object is created, the referenced zip file's catalogue
28      * is read. Later, individual zipped files are read using this cache of catalogue entries.
29      */

30     protected Hashtable entries = new Hashtable();
31
32     /**
33      * The name of this object's jar/zip file
34      */

35     protected String JavaDoc zipFileName;
36
37     /**
38      * The actual zip or jar file
39      */

40     protected ZipFile zipFile;
41
42
43     private static Logger JavaDoc log = Logger.getLogger(CBJarResource.class.getName());
44
45     /*/ temp - debug
46     {
47         Handler handler = new ConsoleHandler();
48         handler.setLevel(Level.FINEST);
49         log.addHandler(handler);
50         log.setLevel(Level.FINE);
51         log.fine("CBJarResource log active");
52     }
53     //*/

54
55     /**
56      * creates a CBJarResources. It extracts all resources from a Jar
57      * into an internal hashtable, keyed by resource names.
58      * @param zipFileName a jar or zip file
59      */

60
61     /**
62      * Returns the raw name of the zip/jar file.
63      *
64      * @return the name of the zip file, e.g. 'help/local/fnord.zip'
65      */

66
67     public String JavaDoc getZipFileName()
68     {
69         return zipFileName;
70     }
71
72     /**
73      * Returns the last modified date of the zip file.
74      */

75
76     public long getLastModified()
77     {
78         File zip = new File(zipFileName);
79         if (zip == null)
80             return 0;
81         else
82             return zip.lastModified();
83     }
84
85     /**
86      * creates a CBJarResources. It extracts all resources from a Jar
87      * into an internal hashtable, keyed by resource names.
88      *
89      * @param zipFileName a jar or zip file
90      */

91
92     public CBJarResource(String JavaDoc zipFileName)
93     {
94         this.zipFileName = zipFileName;
95         init();
96         log.fine("INITIALIZED JAR " + zipFileName);
97     }
98
99     /**
100      * Prints a simple identifying string for debugging purposes.
101      */

102
103     public String JavaDoc toString()
104     {
105         return "CBJarResource (" + zipFileName + ")";
106     }
107
108     /**
109      * returns whether a particular resource
110      * exists in the archive. These names are preloaded into a hashtable, so this should be a lightweight operation.
111      *
112      * @param name the name of the resource (e.g. a class com/ca/od/util/CBJarResources, or an image file myimages/winona.gif)
113      */

114
115     public boolean hasResource(String JavaDoc name)
116     {
117         return entries.containsKey(name);
118     }
119
120     /**
121      * Extracts a jar resource as a blob. Note that this basic method throws no exceptions, but simply returns null on failure.
122      *
123      * @param name a resource name.
124      * @return a resource, or null if no resource available for any reason.
125      */

126
127     public byte[] getResource(String JavaDoc name) throws ZipException
128     {
129         return getRawResource(name);
130     }
131
132     /**
133      * Extracts a file from a jar or zip, returning it as a raw byte array.
134      */

135
136     protected byte[] getRawResource(String JavaDoc name) throws ZipException
137     {
138         try
139         {
140             ZipEntry entry = (ZipEntry) entries.get(name);
141             InputStream in = zipFile.getInputStream(entry);
142
143             if (entry == null)
144             {
145                 throw new ZipException("Unable to find: " + name + " in zip file " + zipFileName);
146             }
147
148             return readZipEntryData(in, entry);
149         }
150         catch (IOException e)
151         {
152             throw new ZipException("Error reading zip file: " + e);
153         }
154     }
155
156
157     /**
158      * Returns an Image from a zip file.
159      *
160      * @param imageName the name of the image (including path) as saved in the zip file
161      * @param imageCreator a java.awt.Component used to get a Toolkit to construct the Image.
162      * @return a usable java.awt.Image file.
163      */

164
165     public Image getImage(String JavaDoc imageName, Toolkit imageCreator)
166             throws ZipException
167     {
168         if (hasResource(imageName) == false)
169             throw new ZipException("resource: " + imageName + " not found in zip file: " + zipFileName);
170
171
172         Image ret = imageCreator.createImage(getRawResource(imageName));
173         return ret;
174     }
175
176     /**
177      * Allows a zipped file to be accessed with a (uncompressed) input stream, not unlike
178      * a normal FileInputStream.
179      *
180      * @param resourceName the fully qualified name of the object (i.e. with the path of the file as it exists in the zip file)
181      */

182     public InputStream getInputStream(String JavaDoc resourceName)
183             throws ZipException
184     {
185         try
186         {
187             ZipEntry entry = (ZipEntry) entries.get(resourceName);
188             InputStream in = zipFile.getInputStream(entry);
189             return in;
190         }
191         catch (IOException e)
192         {
193             throw new ZipException("Error getting input stream: " + e.toString());
194         }
195     }
196
197     /**
198      * initializes internal hash tables with Jar file resources.
199      */

200     protected void init()
201     {
202         try
203         {
204             // extracts just sizes only.
205
zipFile = new ZipFile(zipFileName);
206             Enumeration e = zipFile.entries();
207             while (e.hasMoreElements())
208             {
209                 ZipEntry ze = (ZipEntry) e.nextElement();
210                 //if (debug)
211
String JavaDoc name = ze.getName();
212                 log.fine("added zip entry: " + name);
213                 entries.put(name, ze);
214
215                 // add editor classes a second time, in canonical lower case form. (This solves problems with loading classes by attribute / object class names
216
// with directory dependant capitalization)
217

218                 if (name.endsWith("Editor") || name.endsWith("editor"))
219                 {
220                     log.fine("double loading " + name.toLowerCase());
221                     entries.put(name.toLowerCase(), ze);
222                 }
223             }
224         }
225         catch (NullPointerException JavaDoc e)
226         {
227             log.warning("unable to init zip file " + zipFileName + " - no entries?");
228         }
229         catch (FileNotFoundException e)
230         {
231             log.log(Level.WARNING, "can't find zip file", e);
232         }
233         catch (IOException e)
234         {
235             log.log(Level.WARNING, "error reading zip file", e);
236         }
237     }
238
239     /**
240      * Reads a specific zip entry from the input stream...
241      *
242      * @param is the decrypted (important!) input stream to construct an object out of. May be a ZipInputStream, but remember that
243      * ZipInputStream is *not* idempotent (i.e. don't call it on itself!). For the record, ZipFile.getInputStream() is a decrypted stream.
244      * @param ze the single zip entry to extract from the file.
245      */

246
247     protected byte[] readZipEntryData(InputStream is, ZipEntry ze)
248             throws IOException
249     {
250         int size = (int) ze.getSize();
251
252         if (size == -1)
253         {
254             log.warning("bizarre size error in zip entry reading = corrupt zip file?");
255             return null;
256         }
257
258         byte[] b = new byte[(int) size];
259         int rb = 0;
260         int chunk = 0;
261         while (((int) size - rb) > 0)
262         {
263             chunk = is.read(b, rb, (int) size - rb);
264             if (chunk == -1)
265             {
266                 break;
267             }
268             rb += chunk;
269         }
270
271         /* DEBUG
272             System.out.println("successfully read: " + ze.getName()+" rb="+rb+",size="+size+",csize="+ze.getCompressedSize());
273             System.out.println("successfully read value:\n" + new String(b));
274             for (int i=0; i<10; i++)
275                 System.out.print(CBUtility.byte2Hex(b[i]) + " ");
276             System.out.println("\n");
277         /* */

278
279         return b;
280     }
281
282     /**
283      * Dumps a zip entry into a string.
284      *
285      * @param ze a ZipEntry
286      */

287     protected String JavaDoc dumpZipEntry(ZipEntry ze)
288     {
289         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
290         if (ze.isDirectory())
291         {
292             sb.append("dir: ");
293         }
294         else
295         {
296             sb.append("file: ");
297         }
298         if (ze.getMethod() == ZipEntry.STORED)
299         {
300             sb.append("stored ");
301         }
302         else
303         {
304             sb.append("deflated ");
305         }
306         sb.append(ze.getName());
307         sb.append("\t\t");
308         sb.append("" + ze.getSize());
309         if (ze.getMethod() == ZipEntry.DEFLATED)
310         {
311             sb.append("/" + ze.getCompressedSize());
312         }
313         return (sb.toString());
314     }
315
316     /**
317      * Is a test driver. Given a jar file and a resource name, it trys to
318      * extract the resource and then tells us whether it could or not.
319      * <p/>
320      * <strong>Example</strong>
321      * Let's say you have a JAR file which jarred up a bunch of gif image
322      * files. Now, by using CBJarResources, you could extract, create, and display
323      * those images on-the-fly.
324      * <pre>
325      * ...
326      * CBJarResources JR=new CBJarResources("GifBundle.jar");
327      * Image image=Toolkit.createImage(JR.getResource("logo.gif");
328      * Image logo=Toolkit.getDefaultToolkit().createImage(
329      * JR.getResources("logo.gif")
330      * );
331      * ...
332      * </pre>
333      */

334
335     public static void main(String JavaDoc[] args) throws IOException
336     {
337         if (args.length != 2)
338         {
339             System.out.println("usage: java CBJarResources <jar file name> <resource name>");
340             System.exit(1);
341         }
342         CBJarResource jr = new CBJarResource(args[0]);
343         byte[] buff = jr.getResource(args[1]);
344         if (buff == null)
345         {
346             System.out.println("Could not find " + args[1] + ".");
347         }
348         else
349         {
350             System.out.println("Found " + args[1] + " (length=" + buff.length + ").");
351         }
352     }
353
354     protected void finalize()
355     {
356         try
357         {
358             zipFile.close();
359         }
360         catch (Exception JavaDoc e)
361         {
362         }
363     }
364
365     /**
366      * Returns the *names* only of any resources with a particular prefix (such as 'images/').
367      * This is similar the wildcard search 'prefix*', but no actual '*' character
368      * is used. The search is case insensitive.
369      */

370
371     public String JavaDoc[] getPrefixedResources(String JavaDoc prefix)
372     {
373         prefix = prefix.toLowerCase();
374         Vector results = new Vector();
375         Enumeration keys = entries.keys();
376
377         // cycle through all available entry names (keys) looking for prefixed entries
378
while (keys.hasMoreElements())
379         {
380             String JavaDoc name = (String JavaDoc) keys.nextElement();
381             if (name.toLowerCase().startsWith(prefix))
382             {
383                 results.add(name);
384             }
385         }
386
387
388         // laboriously cast to strings for returning.
389
if (results.size() == 0)
390         {
391             return new String JavaDoc[]{};
392         }
393         else
394         {
395             // ???? return (String[]) (results.toArray);
396

397             return (String JavaDoc[]) results.toArray(new String JavaDoc[results.size()]);
398             
399 /*
400             Object[] temp = results.toArray();
401             String[] ret = new String[temp.length];
402             for (int i=0; i<temp.length; i++)
403                 ret[i] = (String) temp[i];
404             return ret;
405 */

406         }
407     }
408
409 } // End of CBJarResources class.
Popular Tags