Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » catalina » util » [javadoc | source]
    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;
   21   import java.io.FileInputStream;
   22   import java.io.IOException;
   23   import java.io.InputStream;
   24   import java.util.ArrayList;
   25   import java.util.Iterator;
   26   import java.util.NoSuchElementException;
   27   import java.util.StringTokenizer;
   28   import java.util.jar.JarInputStream;
   29   import java.util.jar.Manifest;
   30   
   31   import javax.naming.Binding;
   32   import javax.naming.NamingEnumeration;
   33   import javax.naming.NamingException;
   34   import javax.naming.directory.DirContext;
   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.juli.logging.Log log=
   56           org.apache.juli.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 containerAvailableExtensions = null;
   65       private static ArrayList containerManifestResources = new ArrayList();
   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 systemClasspath = System.getProperty("java.class.path");
   83   
   84           StringTokenizer strTok = new StringTokenizer(systemClasspath, 
   85                                                        File.pathSeparator);
   86   
   87           // build a list of jar files in the classpath
   88           while (strTok.hasMoreTokens()) {
   89               String classpathItem = strTok.nextToken();
   90               if (classpathItem.toLowerCase().endsWith(".jar")) {
   91                   File item = new File(classpathItem);
   92                   if (item.exists()) {
   93                       try {
   94                           addSystemResource(item);
   95                       } catch (IOException 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 dirContext, 
  132                                              StandardContext context)
  133                       throws IOException {
  134   
  135           String appName = context.getPath();
  136           ArrayList appManifestResources = new ArrayList();
  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 inputStream = null;
  142           try {
  143               NamingEnumeration wne = dirContext.listBindings("/META-INF/");
  144               Binding binding = (Binding) 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 manifest = new Manifest(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 nex) {
  158               // Application does not contain a MANIFEST.MF file
  159           } catch (NoSuchElementException nse) {
  160               // Application does not contain a MANIFEST.MF file
  161           } finally {
  162               if (inputStream != null) {
  163                   try {
  164                       inputStream.close();
  165                   } catch (Throwable t) {
  166                       // Ignore
  167                   }
  168               }
  169           }
  170   
  171           // Locate the Manifests for all bundled JARs
  172           NamingEnumeration ne = null;
  173           try {
  174               if (dirContext != null) {
  175                   ne = dirContext.listBindings("WEB-INF/lib/");
  176               }
  177               while ((ne != null) && ne.hasMoreElements()) {
  178                   Binding binding = (Binding)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 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 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 jarFile) throws IOException {
  209           Manifest manifest = getManifest(new FileInputStream(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 appName, 
  243                                                        ArrayList resources) {
  244           boolean passes = true;
  245           int failureCount = 0;        
  246           ArrayList availableExtensions = null;
  247   
  248           Iterator it = resources.iterator();
  249           while (it.hasNext()) {
  250               ManifestResource mre = (ManifestResource)it.next();
  251               ArrayList 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 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 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 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 buildAvailableExtensionsList(ArrayList resources) {
  336   
  337           ArrayList availableList = null;
  338   
  339           Iterator it = resources.iterator();
  340           while (it.hasNext()) {
  341               ManifestResource mre = (ManifestResource)it.next();
  342               ArrayList list = mre.getAvailableExtensions();
  343               if (list != null) {
  344                   Iterator values = list.iterator();
  345                   while (values.hasNext()) {
  346                       Extension ext = (Extension) values.next();
  347                       if (availableList == null) {
  348                           availableList = new ArrayList();
  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 getManifest(InputStream inStream)
  367               throws IOException {
  368   
  369           Manifest manifest = null;
  370           JarInputStream jin = null;
  371   
  372           try {
  373               jin = new JarInputStream(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 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 property) {
  395   
  396           // get the files in the extensions directory
  397           String extensionsDir = System.getProperty(property);
  398           if (extensionsDir != null) {
  399               StringTokenizer extensionsTok
  400                   = new StringTokenizer(extensionsDir, File.pathSeparator);
  401               while (extensionsTok.hasMoreTokens()) {
  402                   File targetDir = new File(extensionsTok.nextToken());
  403                   if (!targetDir.exists() || !targetDir.isDirectory()) {
  404                       continue;
  405                   }
  406                   File[] 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 e) {
  412                               log.error
  413                                   (sm.getString
  414                                    ("extensionValidator.failload", files[i]), e);
  415                           }
  416                       }
  417                   }
  418               }
  419           }
  420   
  421       }
  422   
  423   
  424   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » catalina » util » [javadoc | source]