KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > util > ExtensionValidator


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.catalina.util;
19
20 import java.io.File JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.NoSuchElementException JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28 import java.util.jar.JarInputStream JavaDoc;
29 import java.util.jar.Manifest JavaDoc;
30
31 import javax.naming.Binding JavaDoc;
32 import javax.naming.NamingEnumeration JavaDoc;
33 import javax.naming.NamingException JavaDoc;
34 import javax.naming.directory.DirContext JavaDoc;
35
36 import org.apache.catalina.core.StandardContext;
37 import org.apache.naming.resources.Resource;
38
39
40 /**
41  * Ensures that all extension dependies are resolved for a WEB application
42  * are met. This class builds a master list of extensions available to an
43  * applicaiton and then validates those extensions.
44  *
45  * See http://java.sun.com/j2se/1.4/docs/guide/extensions/spec.html for
46  * a detailed explanation of the extension mechanism in Java.
47  *
48  * @author Greg Murray
49  * @author Justyna Horwat
50  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
51  *
52  */

53 public final class ExtensionValidator {
54
55     private static org.apache.commons.logging.Log log=
56         org.apache.commons.logging.LogFactory.getLog(ExtensionValidator.class);
57
58     /**
59      * The string resources for this package.
60      */

61     private static StringManager sm =
62         StringManager.getManager("org.apache.catalina.util");
63     
64     private static ArrayList JavaDoc containerAvailableExtensions = null;
65     private static ArrayList JavaDoc containerManifestResources = new ArrayList JavaDoc();
66
67
68     // ----------------------------------------------------- Static Initializer
69

70
71     /**
72      * This static initializer loads the container level extensions that are
73      * available to all web applications. This method scans all extension
74      * directories available via the "java.ext.dirs" System property.
75      *
76      * The System Class-Path is also scanned for jar files that may contain
77      * available extensions.
78      */

79     static {
80
81         // check for container level optional packages
82
String JavaDoc systemClasspath = System.getProperty("java.class.path");
83
84         StringTokenizer JavaDoc strTok = new StringTokenizer JavaDoc(systemClasspath,
85                                                      File.pathSeparator);
86
87         // build a list of jar files in the classpath
88
while (strTok.hasMoreTokens()) {
89             String JavaDoc classpathItem = strTok.nextToken();
90             if (classpathItem.toLowerCase().endsWith(".jar")) {
91                 File JavaDoc item = new File JavaDoc(classpathItem);
92                 if (item.exists()) {
93                     try {
94                         addSystemResource(item);
95                     } catch (IOException JavaDoc e) {
96                         log.error(sm.getString
97                                   ("extensionValidator.failload", item), e);
98                     }
99                 }
100             }
101         }
102
103         // add specified folders to the list
104
addFolderList("java.ext.dirs");
105         addFolderList("catalina.ext.dirs");
106
107     }
108
109
110     // --------------------------------------------------------- Public Methods
111

112
113     /**
114      * Runtime validation of a Web Applicaiton.
115      *
116      * This method uses JNDI to look up the resources located under a
117      * <code>DirContext</code>. It locates Web Application MANIFEST.MF
118      * file in the /META-INF/ directory of the application and all
119      * MANIFEST.MF files in each JAR file located in the WEB-INF/lib
120      * directory and creates an <code>ArrayList</code> of
121      * <code>ManifestResorce<code> objects. These objects are then passed
122      * to the validateManifestResources method for validation.
123      *
124      * @param dirContext The JNDI root of the Web Application
125      * @param context The context from which the Logger and path to the
126      * application
127      *
128      * @return true if all required extensions satisfied
129      */

130     public static synchronized boolean validateApplication(
131                                            DirContext JavaDoc dirContext,
132                                            StandardContext context)
133                     throws IOException JavaDoc {
134
135         String JavaDoc appName = context.getPath();
136         ArrayList JavaDoc appManifestResources = new ArrayList JavaDoc();
137         // If the application context is null it does not exist and
138
// therefore is not valid
139
if (dirContext == null) return false;
140         // Find the Manifest for the Web Applicaiton
141
InputStream JavaDoc inputStream = null;
142         try {
143             NamingEnumeration JavaDoc wne = dirContext.listBindings("/META-INF/");
144             Binding JavaDoc binding = (Binding JavaDoc) wne.nextElement();
145             if (binding.getName().toUpperCase().equals("MANIFEST.MF")) {
146                 Resource resource = (Resource)dirContext.lookup
147                                     ("/META-INF/" + binding.getName());
148                 inputStream = resource.streamContent();
149                 Manifest JavaDoc manifest = new Manifest JavaDoc(inputStream);
150                 inputStream.close();
151                 inputStream = null;
152                 ManifestResource mre = new ManifestResource
153                     (sm.getString("extensionValidator.web-application-manifest"),
154                     manifest, ManifestResource.WAR);
155                 appManifestResources.add(mre);
156             }
157         } catch (NamingException JavaDoc nex) {
158             // Application does not contain a MANIFEST.MF file
159
} catch (NoSuchElementException JavaDoc nse) {
160             // Application does not contain a MANIFEST.MF file
161
} finally {
162             if (inputStream != null) {
163                 try {
164                     inputStream.close();
165                 } catch (Throwable JavaDoc t) {
166                     // Ignore
167
}
168             }
169         }
170
171         // Locate the Manifests for all bundled JARs
172
NamingEnumeration JavaDoc ne = null;
173         try {
174             if (dirContext != null) {
175                 ne = dirContext.listBindings("WEB-INF/lib/");
176             }
177             while ((ne != null) && ne.hasMoreElements()) {
178                 Binding JavaDoc binding = (Binding JavaDoc)ne.nextElement();
179                 if (!binding.getName().toLowerCase().endsWith(".jar")) {
180                     continue;
181                 }
182                 Resource resource = (Resource)dirContext.lookup
183                                         ("/WEB-INF/lib/" + binding.getName());
184                 Manifest JavaDoc jmanifest = getManifest(resource.streamContent());
185                 if (jmanifest != null) {
186                     ManifestResource mre = new ManifestResource(
187                                                 binding.getName(),
188                                                 jmanifest,
189                                                 ManifestResource.APPLICATION);
190                     appManifestResources.add(mre);
191                 }
192             }
193         } catch (NamingException JavaDoc nex) {
194             // Jump out of the check for this application because it
195
// has no resources
196
}
197
198         return validateManifestResources(appName, appManifestResources);
199     }
200
201
202     /**
203      * Checks to see if the given system JAR file contains a MANIFEST, and adds
204      * it to the container's manifest resources.
205      *
206      * @param jarFile The system JAR whose manifest to add
207      */

208     public static void addSystemResource(File JavaDoc jarFile) throws IOException JavaDoc {
209         Manifest JavaDoc manifest = getManifest(new FileInputStream JavaDoc(jarFile));
210         if (manifest != null) {
211             ManifestResource mre
212                 = new ManifestResource(jarFile.getAbsolutePath(),
213                                        manifest,
214                                        ManifestResource.SYSTEM);
215             containerManifestResources.add(mre);
216         }
217     }
218
219
220     // -------------------------------------------------------- Private Methods
221

222
223     /**
224      * Validates a <code>ArrayList</code> of <code>ManifestResource</code>
225      * objects. This method requires an application name (which is the
226      * context root of the application at runtime).
227      *
228      * <code>false</false> is returned if the extension dependencies
229      * represented by any given <code>ManifestResource</code> objects
230      * is not met.
231      *
232      * This method should also provide static validation of a Web Applicaiton
233      * if provided with the necessary parameters.
234      *
235      * @param appName The name of the Application that will appear in the
236      * error messages
237      * @param resources A list of <code>ManifestResource</code> objects
238      * to be validated.
239      *
240      * @return true if manifest resource file requirements are met
241      */

242     private static boolean validateManifestResources(String JavaDoc appName,
243                                                      ArrayList JavaDoc resources) {
244         boolean passes = true;
245         int failureCount = 0;
246         ArrayList JavaDoc availableExtensions = null;
247
248         Iterator JavaDoc it = resources.iterator();
249         while (it.hasNext()) {
250             ManifestResource mre = (ManifestResource)it.next();
251             ArrayList JavaDoc requiredList = mre.getRequiredExtensions();
252             if (requiredList == null) {
253                 continue;
254             }
255
256             // build the list of available extensions if necessary
257
if (availableExtensions == null) {
258                 availableExtensions = buildAvailableExtensionsList(resources);
259             }
260
261             // load the container level resource map if it has not been built
262
// yet
263
if (containerAvailableExtensions == null) {
264                 containerAvailableExtensions
265                     = buildAvailableExtensionsList(containerManifestResources);
266             }
267
268             // iterate through the list of required extensions
269
Iterator JavaDoc rit = requiredList.iterator();
270             while (rit.hasNext()) {
271                 boolean found = false;
272                 Extension requiredExt = (Extension)rit.next();
273                 // check the applicaion itself for the extension
274
if (availableExtensions != null) {
275                     Iterator JavaDoc ait = availableExtensions.iterator();
276                     while (ait.hasNext()) {
277                         Extension targetExt = (Extension) ait.next();
278                         if (targetExt.isCompatibleWith(requiredExt)) {
279                             requiredExt.setFulfilled(true);
280                             found = true;
281                             break;
282                         }
283                     }
284                 }
285                 // check the container level list for the extension
286
if (!found && containerAvailableExtensions != null) {
287                     Iterator JavaDoc cit = containerAvailableExtensions.iterator();
288                     while (cit.hasNext()) {
289                         Extension targetExt = (Extension) cit.next();
290                         if (targetExt.isCompatibleWith(requiredExt)) {
291                             requiredExt.setFulfilled(true);
292                             found = true;
293                             break;
294                         }
295                     }
296                 }
297                 if (!found) {
298                     // Failure
299
log.info(sm.getString(
300                         "extensionValidator.extension-not-found-error",
301                         appName, mre.getResourceName(),
302                         requiredExt.getExtensionName()));
303                     passes = false;
304                     failureCount++;
305                 }
306             }
307         }
308
309         if (!passes) {
310             log.info(sm.getString(
311                      "extensionValidator.extension-validation-error", appName,
312                      failureCount + ""));
313         }
314
315         return passes;
316     }
317     
318    /*
319     * Build this list of available extensions so that we do not have to
320     * re-build this list every time we iterate through the list of required
321     * extensions. All available extensions in all of the
322     * <code>MainfestResource</code> objects will be added to a
323     * <code>HashMap</code> which is returned on the first dependency list
324     * processing pass.
325     *
326     * The key is the name + implementation version.
327     *
328     * NOTE: A list is built only if there is a dependency that needs
329     * to be checked (performance optimization).
330     *
331     * @param resources A list of <code>ManifestResource</code> objects
332     *
333     * @return HashMap Map of available extensions
334     */

335     private static ArrayList JavaDoc buildAvailableExtensionsList(ArrayList JavaDoc resources) {
336
337         ArrayList JavaDoc availableList = null;
338
339         Iterator JavaDoc it = resources.iterator();
340         while (it.hasNext()) {
341             ManifestResource mre = (ManifestResource)it.next();
342             ArrayList JavaDoc list = mre.getAvailableExtensions();
343             if (list != null) {
344                 Iterator JavaDoc values = list.iterator();
345                 while (values.hasNext()) {
346                     Extension ext = (Extension) values.next();
347                     if (availableList == null) {
348                         availableList = new ArrayList JavaDoc();
349                         availableList.add(ext);
350                     } else {
351                         availableList.add(ext);
352                     }
353                 }
354             }
355         }
356
357         return availableList;
358     }
359     
360     /**
361      * Return the Manifest from a jar file or war file
362      *
363      * @param inStream Input stream to a WAR or JAR file
364      * @return The WAR's or JAR's manifest
365      */

366     private static Manifest JavaDoc getManifest(InputStream JavaDoc inStream)
367             throws IOException JavaDoc {
368
369         Manifest JavaDoc manifest = null;
370         JarInputStream JavaDoc jin = null;
371
372         try {
373             jin = new JarInputStream JavaDoc(inStream);
374             manifest = jin.getManifest();
375             jin.close();
376             jin = null;
377         } finally {
378             if (jin != null) {
379                 try {
380                     jin.close();
381                 } catch (Throwable JavaDoc t) {
382                     // Ignore
383
}
384             }
385         }
386
387         return manifest;
388     }
389
390
391     /**
392      * Add the JARs specified to the extension list.
393      */

394     private static void addFolderList(String JavaDoc property) {
395
396         // get the files in the extensions directory
397
String JavaDoc extensionsDir = System.getProperty(property);
398         if (extensionsDir != null) {
399             StringTokenizer JavaDoc extensionsTok
400                 = new StringTokenizer JavaDoc(extensionsDir, File.pathSeparator);
401             while (extensionsTok.hasMoreTokens()) {
402                 File JavaDoc targetDir = new File JavaDoc(extensionsTok.nextToken());
403                 if (!targetDir.exists() || !targetDir.isDirectory()) {
404                     continue;
405                 }
406                 File JavaDoc[] files = targetDir.listFiles();
407                 for (int i = 0; i < files.length; i++) {
408                     if (files[i].getName().toLowerCase().endsWith(".jar")) {
409                         try {
410                             addSystemResource(files[i]);
411                         } catch (IOException JavaDoc e) {
412                             log.error
413                                 (sm.getString
414                                  ("extensionValidator.failload", files[i]), e);
415                         }
416                     }
417                 }
418             }
419         }
420
421     }
422
423
424 }
425
Popular Tags