KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > virtual > plugins > context > jar > AbstractJarHandler


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2006, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.virtual.plugins.context.jar;
23
24 import java.io.FileNotFoundException JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.ObjectInputStream JavaDoc;
27 import java.net.JarURLConnection JavaDoc;
28 import java.net.MalformedURLException JavaDoc;
29 import java.net.URISyntaxException JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.net.URLConnection JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Collections JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.jar.JarEntry JavaDoc;
39 import java.util.jar.JarFile JavaDoc;
40
41 import org.jboss.virtual.plugins.context.AbstractURLHandler;
42 import org.jboss.virtual.plugins.context.StructuredVirtualFileHandler;
43 import org.jboss.virtual.plugins.vfs.helpers.PathTokenizer;
44 import org.jboss.virtual.spi.VFSContext;
45 import org.jboss.virtual.spi.VirtualFileHandler;
46
47 /**
48  * AbstractJarHandler.
49  *
50  * @author <a HREF="adrian@jboss.com">Adrian Brock</a>
51  * @author Scott.Stark@jboss.org
52  * @version $Revision: 1.1 $
53  */

54 public class AbstractJarHandler extends AbstractURLHandler
55    implements StructuredVirtualFileHandler
56 {
57    /** serialVersionUID */
58    private static final long serialVersionUID = 1;
59
60    /** The jar file */
61    private transient JarFile JavaDoc jar;
62
63    /** The jar entries */
64    private transient List JavaDoc<VirtualFileHandler> entries;
65    private transient Map JavaDoc<String JavaDoc, VirtualFileHandler> entryMap;
66
67    /**
68     * Get a jar entry name
69     *
70     * @param entry the entry
71     * @return the name
72     * @throws IllegalArgumentException for a null entry
73     */

74    protected static String JavaDoc getEntryName(JarEntry JavaDoc entry)
75    {
76       if (entry == null)
77          throw new IllegalArgumentException JavaDoc("Null entry");
78       return entry.getName();
79    }
80    
81    /**
82     * Create a new JarHandler.
83     *
84     * @param context the context
85     * @param parent the parent
86     * @param url the url
87     * @param name the name
88     * @throws IOException for an error accessing the file system
89     * @throws IllegalArgumentException for a null context, url or vfsPath
90     */

91    protected AbstractJarHandler(VFSContext context, VirtualFileHandler parent, URL JavaDoc url, String JavaDoc name) throws IOException JavaDoc
92    {
93       super(context, parent, url, name);
94    }
95
96    /**
97     * Get the jar.
98     *
99     * @return the jar.
100     */

101    public JarFile JavaDoc getJar()
102    {
103       return jar;
104    }
105
106    /**
107     * Initialise the jar file
108     *
109     * @param jarFile the jar file
110     * @throws IOException for any error reading the jar file
111     * @throws IllegalArgumentException for a null jarFile
112     */

113    protected void initJarFile(JarFile JavaDoc jarFile) throws IOException JavaDoc
114    {
115       /* This cannot be checked because of serialization
116       if (this.jar != null)
117          throw new IllegalStateException("jarFile has already been set");
118       */

119
120       this.jar = jarFile;
121
122       Enumeration JavaDoc<JarEntry JavaDoc> enumeration = jar.entries();
123       if (enumeration.hasMoreElements() == false)
124       {
125          entries = Collections.emptyList();
126          entryMap = Collections.emptyMap();
127          return;
128       }
129
130       // Go through and create a structured representation of the jar
131
Map JavaDoc<String JavaDoc, VirtualFileHandler> parentMap = new HashMap JavaDoc<String JavaDoc, VirtualFileHandler>();
132       ArrayList JavaDoc<ArrayList JavaDoc<JarEntry JavaDoc>> levelMapList = new ArrayList JavaDoc<ArrayList JavaDoc<JarEntry JavaDoc>>();
133       entries = new ArrayList JavaDoc<VirtualFileHandler>();
134       entryMap = new HashMap JavaDoc<String JavaDoc, VirtualFileHandler>();
135       boolean trace = log.isTraceEnabled();
136       while (enumeration.hasMoreElements())
137       {
138          JarEntry JavaDoc entry = enumeration.nextElement();
139          String JavaDoc[] paths = entry.getName().split("/");
140          int depth = paths.length;
141          if( depth >= levelMapList.size() )
142          {
143             for(int n = levelMapList.size(); n <= depth; n ++)
144                levelMapList.add(new ArrayList JavaDoc<JarEntry JavaDoc>());
145          }
146          ArrayList JavaDoc<JarEntry JavaDoc> levelMap = levelMapList.get(depth);
147          levelMap.add(entry);
148          if( trace )
149             log.trace("added "+entry.getName()+" at depth "+depth);
150       }
151       // Process each level to build the handlers in parent first order
152
int level = 0;
153       for(ArrayList JavaDoc<JarEntry JavaDoc> levels : levelMapList)
154       {
155          if( trace )
156             log.trace("Level("+level++ +"): "+levels);
157          for(JarEntry JavaDoc entry : levels)
158          {
159             String JavaDoc name = entry.getName();
160             int slash = entry.isDirectory() ? name.lastIndexOf('/', name.length()-2) :
161                name.lastIndexOf('/', name.length()-1);
162             VirtualFileHandler parent = this;
163             String JavaDoc entryName = name;
164             if( slash >= 0 )
165             {
166                // Need to include the slash in the name to match the JarEntry.name
167
String JavaDoc parentName = name.substring(0, slash+1);
168                parent = parentMap.get(parentName);
169                if( parent == null )
170                {
171                   // Build up the parent(s)
172
parent = buildParents(parentName, parentMap, entry);
173                }
174             }
175             // Get the entry name without any directory '/' ending
176
int start = slash+1;
177             int end = entry.isDirectory() ? name.length()-1 : name.length();
178             entryName = name.substring(start, end);
179             VirtualFileHandler handler = this.createVirtualFileHandler(parent, entry, entryName);
180             if( entry.isDirectory() )
181             {
182                parentMap.put(name, handler);
183                if( trace )
184                   log.trace("Added parent: "+name);
185             }
186             if( parent == this )
187             {
188                // This is an immeadiate child of the jar handler
189
entries.add(handler);
190                entryMap.put(entryName, handler);
191             }
192             else if( parent instanceof JarEntryHandler )
193             {
194                // This is a child of the jar entry handler
195
JarEntryHandler ehandler = (JarEntryHandler) parent;
196                ehandler.addChild(handler);
197             }
198             else if( parent instanceof SynthenticDirEntryHandler )
199             {
200                // This is a child of the jar entry handler
201
SynthenticDirEntryHandler ehandler = (SynthenticDirEntryHandler) parent;
202                ehandler.addChild(handler);
203             }
204          }
205       }
206    }
207
208    /**
209     * Create any missing parents.
210     *
211     * @param parentName full vfs path name of parent
212     * @param parentMap initJarFile parentMap
213     * @param entry JarEntry missing a parent
214     * @return the VirtualFileHandler for the parent
215     * @throws IOException
216     */

217    protected VirtualFileHandler buildParents(String JavaDoc parentName,
218          Map JavaDoc<String JavaDoc, VirtualFileHandler> parentMap, JarEntry JavaDoc entry)
219       throws IOException JavaDoc
220    {
221       VirtualFileHandler parent = this;
222       String JavaDoc[] paths = PathTokenizer.getTokens(parentName);
223       StringBuilder JavaDoc pathName = new StringBuilder JavaDoc();
224       for(String JavaDoc path : paths)
225       {
226          VirtualFileHandler next = null;
227          pathName.append(path);
228          pathName.append('/');
229          try
230          {
231             next = parent.findChild(path);
232          }
233          catch (IOException JavaDoc e)
234          {
235             // Create a synthetic parent
236
URL JavaDoc url = getURL(parent, path);
237             next = new SynthenticDirEntryHandler(getVFSContext(), parent, path,
238                   entry.getTime(), url);
239             parentMap.put(pathName.toString(), next);
240             if( parent == this )
241             {
242                // This is an immeadiate child of the jar handler
243
entries.add(next);
244                entryMap.put(path, next);
245             }
246             else if( parent instanceof JarEntryHandler )
247             {
248                // This is a child of the jar entry handler
249
JarEntryHandler ehandler = (JarEntryHandler) parent;
250                ehandler.addChild(next);
251             }
252             else if( parent instanceof SynthenticDirEntryHandler )
253             {
254                // This is a child of the jar entry handler
255
SynthenticDirEntryHandler ehandler = (SynthenticDirEntryHandler) parent;
256                ehandler.addChild(next);
257             }
258          }
259          parent = next;
260       }
261       return parent;
262    }
263
264    protected URL JavaDoc getURL(VirtualFileHandler parent, String JavaDoc path)
265       throws MalformedURLException JavaDoc
266    {
267       StringBuilder JavaDoc buffer = new StringBuilder JavaDoc();
268       try
269       {
270          buffer.append(parent.toURL());
271          if (buffer.charAt(buffer.length()-1) != '/')
272             buffer.append('/');
273          buffer.append(path);
274       }
275       catch(URISyntaxException JavaDoc e)
276       {
277          // Should not happen
278
throw new MalformedURLException JavaDoc(e.getMessage());
279       }
280       URL JavaDoc url = new URL JavaDoc(buffer.toString());
281       return url;
282    }
283
284    protected void doClose()
285    {
286       /* TODO Figure out why this breaks things randomly
287       try
288       {
289          if (jar != null)
290             jar.close();
291       }
292       catch (IOException ignored)
293       {
294       }
295       */

296    }
297
298    public boolean isLeaf()
299    {
300       checkClosed();
301       return false;
302    }
303
304    public List JavaDoc<VirtualFileHandler> getChildren(boolean ignoreErrors) throws IOException JavaDoc
305    {
306       checkClosed();
307       return entries;
308    }
309
310    public VirtualFileHandler findChild(String JavaDoc path) throws IOException JavaDoc
311    {
312       return super.structuredFindChild(path);
313    }
314
315    public VirtualFileHandler createChildHandler(String JavaDoc name) throws IOException JavaDoc
316    {
317       VirtualFileHandler child = entryMap.get(name);
318       if( child == null )
319          throw new FileNotFoundException JavaDoc(this+" has no child: "+name);
320       return child;
321    }
322
323    /**
324     * Create a new virtual file handler
325     *
326     * @param parent the parent
327     * @param entry the entry
328     * @return the handler
329     * @throws IOException for any error accessing the file system
330     * @throws IllegalArgumentException for a null parent or entry
331     */

332    protected VirtualFileHandler createVirtualFileHandler(VirtualFileHandler parent, JarEntry JavaDoc entry,
333          String JavaDoc entryName)
334       throws IOException JavaDoc
335    {
336       if (parent == null)
337          throw new IllegalArgumentException JavaDoc("Null parent");
338       if (entry == null)
339          throw new IllegalArgumentException JavaDoc("Null entry");
340
341       // Question: Why doesn't this work properly?
342
// URL url = new URL(parent.toURL(), entry.getName());
343
URL JavaDoc url = getURL(parent, entryName);
344
345       VFSContext context = parent.getVFSContext();
346
347       VirtualFileHandler vfh;
348       if (JarUtils.isArchive(entry.getName()))
349       {
350          String JavaDoc flag = context.getOptions().get("useNoCopyJarHandler");
351          boolean useNoCopyJarHandler = Boolean.valueOf(flag);
352
353          if( useNoCopyJarHandler )
354             vfh = new NoCopyNestedJarHandler(context, parent, jar, entry, url);
355          else
356             vfh = new NestedJarHandler(context, parent, jar, entry, url, entryName);
357       }
358       else
359       {
360          // Jar directory URLs must end in /
361
if (entry.isDirectory())
362             url = new URL JavaDoc(url.toString() + "/");
363          vfh = new JarEntryHandler(context, parent, jar, entry, entryName, url);
364       }
365
366       return vfh;
367    }
368
369    /**
370     * Restore the jar file from the jar URL
371     *
372     * @param in
373     * @throws IOException
374     * @throws ClassNotFoundException
375     */

376    private void readObject(ObjectInputStream JavaDoc in)
377       throws IOException JavaDoc, ClassNotFoundException JavaDoc
378    {
379       in.defaultReadObject();
380       // Initialize the transient values
381
URL JavaDoc jarURL = super.getURL();
382       URLConnection JavaDoc conn = jarURL.openConnection();
383       if( conn instanceof JarURLConnection JavaDoc )
384       {
385          JarURLConnection JavaDoc jconn = (JarURLConnection JavaDoc) conn;
386          jar = jconn.getJarFile();
387          // initJarFile(jar) must be called by subclasses readObject
388
}
389       else
390       {
391          throw new IOException JavaDoc("Cannot restore from non-JarURLConnection, url: "+jarURL);
392       }
393    }
394
395 }
396
Popular Tags