KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > appclient > jws > ExtensionFileManager


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.appclient.jws;
25
26 import java.io.File JavaDoc;
27 import java.io.FilenameFilter JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.util.Collection JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.LinkedList JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.Set JavaDoc;
36 import java.util.StringTokenizer JavaDoc;
37 import java.util.Vector JavaDoc;
38 import java.util.jar.Attributes JavaDoc;
39 import java.util.jar.JarFile JavaDoc;
40 import java.util.jar.Manifest JavaDoc;
41
42 /**
43  * Manages a data structure of all extension jars known to the app server.
44  * <p>
45  * This class builds a map of extension name to an
46  * instance of the inner class Extension that records information about that
47  * extension jar. An Extension is created for every jar file in any of the
48  * directories specified by java.ext.dirs.
49  * <p>
50  * Later, a caller can use the findExtensionTransitiveClosure method, passing
51  * a jar file manifest's main attributes and receiving back a List of Extension objects representing
52  * all extension jars referenced directly or indirectly from that jar.
53  *
54  * @author tjquinn
55  */

56 public class ExtensionFileManager {
57     
58     /** the property name that points to extension directories */
59     private static final String JavaDoc EXT_DIRS_PROPERTY_NAME = "java.ext.dirs";
60     
61     /*
62      *Stores File and version information for all extension jars in all
63      *extension jar directories. (any directory listed in java.ext.dirs)
64      */

65     private Map JavaDoc<ExtensionKey, Extension> extensionFileInfo = null;
66
67     /** Records directories specified in java.ext.dirs */
68     private Vector JavaDoc<File JavaDoc> extensionFileDirs = null;
69             
70     /** Creates a new instance of ExtensionFileManager
71      *@throws IOException in case of errors searching extension directories for jars
72      */

73     public ExtensionFileManager() throws IOException JavaDoc {
74         extensionFileDirs = buildExtensionFileDirs();
75         extensionFileInfo = buildExtensionFileEntries(extensionFileDirs);
76     }
77     
78     /*
79      *Returns the collection of extension
80      *file info objects for the extension jars known to the app server.
81      *@return Map from extension name to
82      *@throws IOException in case of error accessing a file as a jar file
83      */

84     public Map JavaDoc<ExtensionKey, Extension> getExtensionFileEntries() throws IOException JavaDoc {
85         return extensionFileInfo;
86     }
87
88     /**
89      *Constructs the collection of File objects, one for each extension directory.
90      *@return Vector<File> containing a File for each extension directory
91      */

92     private Vector JavaDoc<File JavaDoc> buildExtensionFileDirs() {
93         Vector JavaDoc<File JavaDoc> result = new Vector JavaDoc<File JavaDoc>();
94         
95         String JavaDoc extDirs = System.getProperty(EXT_DIRS_PROPERTY_NAME);
96         StringTokenizer JavaDoc stkn = new StringTokenizer JavaDoc(extDirs, File.pathSeparator);
97
98         while (stkn.hasMoreTokens()) {
99             String JavaDoc extensionDirPath = stkn.nextToken();
100             result.add(new File JavaDoc(extensionDirPath));
101         }
102         return result;
103     }
104     
105     /**
106      * Constructs the collection of extension files known to the app server.
107      * @param dirs the directories in which to search for extension jar files
108      * @return Map<ExtensionKey,Extension> mapping the extension name and spec version to the extension jar entry
109      * @throws IOException in case of errors processing jars in the extension directories
110      */

111      private Map JavaDoc<ExtensionKey, Extension> buildExtensionFileEntries(Vector JavaDoc<File JavaDoc> dirs) throws IOException JavaDoc {
112
113         /*
114          *For each extension directory, collect all jar files
115          *and add an entry (containing File and spec version string) for each
116          *file into the data structure.
117          */

118          Map JavaDoc<ExtensionKey,Extension> result = new HashMap JavaDoc<ExtensionKey,Extension>();
119          
120          for (int i = 0; i < dirs.size(); i++) {
121             addExtJarsFromDirectory(result, i, dirs.get(i));
122         }
123         return result;
124      }
125      
126      /**
127       *Create the collection of extension directories.
128       *@return Vector of File objects, one for each directory.
129       */

130      /**
131       * Adds entries for the extension files from one directory to the indicated Map.
132       * @param extensionFilesMap map of each extension name to its Extension
133       * @param extensionDirNumber the ordinal number of the directory being processed
134       * @param extDirPath the current directory being processed
135       * @throws IOException in case of error scanning for jar files
136       */

137      private void addExtJarsFromDirectory(Map JavaDoc<ExtensionKey, Extension> map, int extensionDirNumber, File JavaDoc extDir) throws IOException JavaDoc {
138         File JavaDoc [] extJars = extDir.listFiles(new FilenameFilter JavaDoc() {
139             public boolean accept(File JavaDoc dir, String JavaDoc name) {
140                 return name.endsWith(".jar");
141             }
142           });
143         if (extJars != null) {
144             for (File JavaDoc file : extJars) {
145                 Extension entry = buildExtensionForJar(file, extensionDirNumber);
146                 if (entry != null) {
147                     map.put(entry.extensionKey, entry);
148                 }
149             }
150         }
151      }
152      
153     /**
154      * Creates an extension Extension for a jar file if the jar is in fact an extension.
155      * @param jarFile a File object for the jar to use
156      * @param extDirectoryNumber the ordinal number of the directory in java.ext.dirs being scanned
157      * @return Extension for the jar if the jar has an extension name; null otherwise
158      * @throws IOException in case of errors working with the file
159      */

160     private Extension buildExtensionForJar(File JavaDoc file, int extDirectoryNumber) throws IOException JavaDoc {
161         Extension result = null;
162         JarFile JavaDoc jarFile = null;
163         try {
164             jarFile = new JarFile JavaDoc(file);
165             ExtensionKey key = getDefinedExtensionKey(jarFile);
166             if (key != null) {
167                 result = new Extension(key, file, extDirectoryNumber);
168             }
169             return result;
170         } finally {
171             if (jarFile != null) {
172                 jarFile.close();
173             }
174         }
175     }
176
177     /**
178      * Constructs a List of Extension objects corresponding to jars required to
179      * satisfy an extension chain.
180      * <p>
181      * The transitive closure includes any extensions required by the
182      * initial jar, its Class-Path jars, and any extensions required
183      * by extensions.
184      * @param anchorDir the directory relative to which Class-Path manifest entries are evaluated (if relative)
185      * @param mainAttrs the main attributes from a jar file whose extensions are to be satisfied
186      * @return List<Extension> containing an Extension object for each required jar
187      * @throws IOException in case of errors building the extension jar file data structure
188      */

189     public Set JavaDoc<Extension> findExtensionTransitiveClosure(File JavaDoc anchorDir, Attributes JavaDoc mainAttrs) throws IOException JavaDoc {
190         
191         Set JavaDoc<Extension> result = new HashSet JavaDoc<Extension>();
192
193         Vector JavaDoc<File JavaDoc> filesToProcess = new Vector JavaDoc<File JavaDoc>();
194         
195         filesToProcess.addAll(getClassPathJars(anchorDir, mainAttrs));
196         
197         Set JavaDoc<Extension> extensionsUsedByApp = getReferencedExtensions(mainAttrs);
198         result.addAll(extensionsUsedByApp);
199         filesToProcess.addAll(extensionsToFiles(extensionsUsedByApp));
200         
201         /**
202          *Do not use the for/each construct next because the loop may add
203          *elements to the vector and for/each would through a concurrent
204          *modification exception.
205          */

206         for (int i = 0; i < filesToProcess.size(); i++) {
207             File JavaDoc nextFile = filesToProcess.get(i);
208             /*
209              *The Class-Path entry might not point to a file that actually exists.
210              *Make sure the file is there before trying to work with it.
211              */

212             if (nextFile.exists()) {
213                 JarFile JavaDoc nextJarFile = new JarFile JavaDoc(nextFile);
214                 try {
215                     Attributes JavaDoc attrs = getMainAttrs(nextJarFile);
216                     Set JavaDoc<Extension> newExtensions = getReferencedExtensions(attrs);
217                     result.addAll(newExtensions);
218                     filesToProcess.addAll(extensionsToFiles(newExtensions));
219                 } finally {
220                     if (nextJarFile != null) {
221                         nextJarFile.close();
222                     }
223                 }
224             }
225         }
226         return result;
227     }
228
229     /**
230      *Returns a Set of File objects corresponding to the supplied set of Extensions.
231      *@param extensions set of Extension the files of which are of interest
232      *@return set of File, one File for each Extension in the input set
233      */

234     private Set JavaDoc<File JavaDoc> extensionsToFiles(Set JavaDoc<Extension> extensions) {
235         Set JavaDoc<File JavaDoc> result = new HashSet JavaDoc<File JavaDoc>();
236         for (Extension e : extensions) {
237             result.add(e.file);
238         }
239         return result;
240     }
241     
242     /**
243      *Returns a Set of Extensions that are referenced by the jar file whose
244      *main attributes are passed.
245      *@param mainAttrs the main attributes from a jar file's manifest
246      *@return Set of Extension objects corresponding to the extensions referenced by the attributes
247      *@throws IOException if an extension jar is required but not found
248      */

249     private Set JavaDoc<Extension> getReferencedExtensions(Attributes JavaDoc mainAttrs) throws IOException JavaDoc {
250         Set JavaDoc<Extension> result = new HashSet JavaDoc<Extension>();
251         Set JavaDoc<ExtensionKey> extensionKeys = getReferencedExtensionKeys(mainAttrs);
252
253         for (ExtensionKey key : extensionKeys) {
254             if ( ! result.contains(key)) {
255                 Extension extension = extensionFileInfo.get(key);
256
257                 /*
258                  *Add this extension only if it does not already appear
259                  *in the result collection. In that case, also add the
260                  *file to the collection of files to be processed.
261                  */

262                 if (extension != null) {
263                     result.add(extension);
264                 } else {
265                     throw new IOException JavaDoc("Jar file requires the extension " + key + " but it is not in the known extensions " + extensionFileInfo);
266                 }
267             }
268         }
269         return result;
270     }
271     
272     /**
273      *Returns the main attributes (if any) object from a jar file.
274      *@param jarFile the JarFile of interest
275      *@return Attributes object for the jar file's main attributes.
276      *@throws IOException in case of error getting the Jar file's manifest
277      */

278     private Attributes JavaDoc getMainAttrs(JarFile JavaDoc jarFile) throws IOException JavaDoc {
279         Attributes JavaDoc result = null;
280         
281         Manifest JavaDoc mf = jarFile.getManifest();
282         if (mf != null) {
283             result = mf.getMainAttributes();
284         }
285         return result;
286     }
287     
288     /**
289      *Returns the Files corresponding to the Class-Path entries (if any) in a
290      *Jar file's main attributes.
291      *@param anchorDir the directory to which relative Class-Path entries are resolved
292      *@param mainAttrs the jar file's main attributes (which would contain Class-Path entries if there are any)
293      */

294     private List JavaDoc<File JavaDoc> getClassPathJars(File JavaDoc anchorDir, Attributes JavaDoc mainAttrs) {
295         List JavaDoc<File JavaDoc> result = new LinkedList JavaDoc<File JavaDoc>();
296         String JavaDoc classPathList = mainAttrs.getValue(Attributes.Name.CLASS_PATH);
297         if (classPathList != null) {
298             StringTokenizer JavaDoc stkn = new StringTokenizer JavaDoc(classPathList, " ");
299             while (stkn.hasMoreTokens()) {
300                 String JavaDoc classPathJarPath = stkn.nextToken();
301                 File JavaDoc classPathJarFile = new File JavaDoc(classPathJarPath);
302                 if ( ! classPathJarFile.isAbsolute()) {
303                     classPathJarFile = new File JavaDoc(anchorDir, classPathJarPath);
304                 }
305                 result.add(classPathJarFile);
306             }
307         }
308         return result;
309     }
310
311     /**
312      *Returns the ExtensionKey for the extension which the specified JarFile provides (if any).
313      *@param jarFile the JarFile which may be an extension jar
314      *@returns the ExtensionKey for the extension if this jar is one; null otherwise
315      *@throws IOException in case of error getting the jar file's main attributes
316      */

317     private ExtensionKey getDefinedExtensionKey(JarFile JavaDoc jarFile) throws IOException JavaDoc {
318         ExtensionKey result = null;
319         
320         Attributes JavaDoc mainAttrs = getMainAttrs(jarFile);
321         if (mainAttrs != null) {
322             String JavaDoc extName = mainAttrs.getValue(Attributes.Name.EXTENSION_NAME);
323             if (extName != null) {
324                 String JavaDoc specVersion = mainAttrs.getValue(Attributes.Name.SPECIFICATION_VERSION);
325                 ExtensionKey entryKey = new ExtensionKey(extName, specVersion);
326                 result = new ExtensionKey(extName, specVersion);
327             }
328         }
329         
330         return result;
331     }
332     
333     /**
334      *Returns the ExtensionKeys for the extension jars referenced by the specified main attributes
335      *@param mainAttrs the main attributes from a jar file that may refer to extension jars
336      *@return Set of ExtensionKey, one key or each distinct extension jar that is referenced
337      */

338     private Set JavaDoc<ExtensionKey> getReferencedExtensionKeys(Attributes JavaDoc mainAttrs) {
339         Set JavaDoc<ExtensionKey> result = new HashSet JavaDoc<ExtensionKey>();
340         
341         if (mainAttrs != null) {
342             String JavaDoc extensionList = mainAttrs.getValue(Attributes.Name.EXTENSION_LIST);
343             if (extensionList != null) {
344                 StringTokenizer JavaDoc stkn = new StringTokenizer JavaDoc(extensionList, " ");
345                 while (stkn.hasMoreTokens()) {
346                     /*
347                      *For each extension jar in this jar's list, create a new
348                      *ExtensionKey using the name and spec version.
349                      */

350                     String JavaDoc token = stkn.nextToken().trim();
351                     String JavaDoc extName = mainAttrs.getValue(token + "-" + Attributes.Name.EXTENSION_NAME);
352                     String JavaDoc specVersion = mainAttrs.getValue(token + "-" + Attributes.Name.SPECIFICATION_VERSION);
353                     ExtensionKey key = new ExtensionKey(extName, specVersion);
354                     result.add(key);
355                 }
356             }
357         }
358         return result;
359     }
360             
361     /**
362      * The key for identifying extension jar Extension objects in the Map. The key
363      * needs to include both the extension name and the specification version.
364      * Note that the spec version defaults to the empty string.
365      */

366     public class ExtensionKey {
367         private String JavaDoc extensionName = null;
368         
369         private String JavaDoc specificationVersion = null;
370         
371         /**
372          * Creates a new instance of ExtensionKey.
373          * @param extensionName the extension name of interest (cannot be null)
374          * @param specificationVersion the spec version of interest
375          */

376         public ExtensionKey(String JavaDoc extensionName, String JavaDoc specificationVersion) {
377             assert extensionName != null : "extensionName is null";
378             this.extensionName = extensionName;
379             this.specificationVersion = (specificationVersion != null) ? specificationVersion : "";
380         }
381         
382         public boolean equals(Object JavaDoc other) {
383             boolean result = false;
384             if (other != null) {
385                 if (other == this) {
386                     result = true;
387                 } else {
388                     if (other instanceof ExtensionKey) {
389                         ExtensionKey otherEntryKey = (ExtensionKey) other;
390                         result = extensionName.equals(otherEntryKey.extensionName) &&
391                                  specificationVersion.equals(otherEntryKey.specificationVersion);
392                     }
393                 }
394             }
395             return result;
396         }
397
398         public int hashCode() {
399             int result = 17;
400             result = 37 * result + extensionName.hashCode();
401             result = 37 * result + specificationVersion.hashCode();
402             return result;
403         }
404         
405         public String JavaDoc toString() {
406             return "Name=" + extensionName + ", spec version = " + specificationVersion;
407         }
408     }
409     
410     /**
411      *Records information about an extension jar file known to the app server.
412      */

413     public class Extension {
414         
415         private ExtensionKey extensionKey;
416         
417         private File JavaDoc file = null;
418         
419         /** in case the same extension appears in more than one extension directory */
420         private int extDirectoryNumber = -1;
421         
422         public Extension(ExtensionKey extensionKey, File JavaDoc file, int extDirectoryNumber) {
423             assert extensionKey != null : "extensionKey is null";
424             assert file != null : "file is null";
425             
426             this.extensionKey = extensionKey;
427             this.file = file;
428             this.extDirectoryNumber = extDirectoryNumber;
429         }
430         
431         public boolean equals(Object JavaDoc other) {
432             boolean result = false;
433             if (other != null) {
434                 if (other == this) {
435                     result = true;
436                 } else {
437                     if (other instanceof Extension) {
438                         Extension otherEntry = (Extension) other;
439                         result = extensionKey.equals(otherEntry.extensionKey) &&
440                                 file.equals(otherEntry.file) &&
441                                 extDirectoryNumber == otherEntry.extDirectoryNumber;
442                     }
443                 }
444             }
445             return result;
446         }
447         
448         public int hashCode() {
449             int result = 17;
450             result = result * 37 + extensionKey.hashCode();
451             result = result * 37 + file.hashCode();
452             result = result * 37 + extDirectoryNumber;
453             return result;
454         }
455         
456         public int getExtDirectoryNumber() {
457             return extDirectoryNumber;
458         }
459         
460         public File JavaDoc getFile() {
461             return file;
462         }
463         
464         public String JavaDoc toString() {
465             return extensionKey.toString() + ", file = " + file.getAbsolutePath() + ", in ext dir " + extDirectoryNumber + "(" + extensionFileDirs.get(extDirectoryNumber).getAbsolutePath();
466         }
467     }
468 }
469
Popular Tags