View Javadoc

1   // ========================================================================
2   // Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  
15  package org.eclipse.jetty.webapp;
16  
17  import java.io.InputStream;
18  import java.net.URI;
19  import java.net.URL;
20  import java.net.URLClassLoader;
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.jar.JarEntry;
24  import java.util.jar.JarInputStream;
25  import java.util.regex.Pattern;
26  
27  import org.eclipse.jetty.util.log.Log;
28  import org.eclipse.jetty.util.resource.Resource;
29  
30  /**
31   * JarScannerConfiguration
32   *
33   * Abstract base class for configurations that want to scan jars in
34   * WEB-INF/lib and the classloader hierarchy.
35   * 
36   * Jar name matching based on regexp patterns is provided.
37   * 
38   * Subclasses should implement the processEntry(URL jarUrl, JarEntry entry)
39   * method to handle entries in jar files whose names match the supplied 
40   * pattern.
41   */
42  public abstract class JarScanner extends org.eclipse.jetty.util.PatternMatcher
43  {
44  
45      public abstract void processEntry (URI jarUri, JarEntry entry);
46      
47      /**
48       * Find jar names from the provided list matching a pattern.
49       * 
50       * If the pattern is null and isNullInclusive is true, then
51       * all jar names will match.
52       * 
53       * A pattern is a set of acceptable jar names. Each acceptable
54       * jar name is a regex. Each regex can be separated by either a
55       * "," or a "|". If you use a "|" this or's together the jar
56       * name patterns. This means that ordering of the matches is
57       * unimportant to you. If instead, you want to match particular
58       * jar names, and you want to match them in order, you should
59       * separate the regexs with "," instead. 
60       * 
61       * Eg "aaa-.*\\.jar|bbb-.*\\.jar"
62       * Will iterate over the jar names and match
63       * in any order.
64       * 
65       * Eg "aaa-*\\.jar,bbb-.*\\.jar"
66       * Will iterate over the jar names, matching
67       * all those starting with "aaa-" first, then "bbb-".
68       *
69       * @param pattern
70       * @param loader
71       * @param isNullInclusive if true, an empty pattern means all names match, if false, none match
72       * @throws Exception
73       */
74      public void scan (Pattern pattern, URI[] uris, boolean isNullInclusive)
75      throws Exception
76      {
77         super.match(pattern, uris, isNullInclusive);
78      }
79      
80      /**
81       * Find jar names from the classloader matching a pattern.
82       * 
83       * If the pattern is null and isNullInclusive is true, then
84       * all jar names in the classloader will match.
85       * 
86       * A pattern is a set of acceptable jar names. Each acceptable
87       * jar name is a regex. Each regex can be separated by either a
88       * "," or a "|". If you use a "|" this or's together the jar
89       * name patterns. This means that ordering of the matches is
90       * unimportant to you. If instead, you want to match particular
91       * jar names, and you want to match them in order, you should
92       * separate the regexs with "," instead. 
93       * 
94       * Eg "aaa-.*\\.jar|bbb-.*\\.jar"
95       * Will iterate over the jar names in the classloader and match
96       * in any order.
97       * 
98       * Eg "aaa-*\\.jar,bbb-.*\\.jar"
99       * Will iterate over the jar names in the classloader, matching
100      * all those starting with "aaa-" first, then "bbb-".
101      * 
102      * If visitParent is true, then the pattern is applied to the
103      * parent loader hierarchy. If false, it is only applied to the
104      * classloader passed in.
105      * 
106      * @param pattern
107      * @param loader
108      * @param isNullInclusive
109      * @param visitParent
110      * @throws Exception
111      */
112     public void scan (Pattern pattern, ClassLoader loader, boolean isNullInclusive, boolean visitParent)
113     throws Exception
114     {
115         while (loader!=null)
116         {
117             if (loader instanceof URLClassLoader)
118             {
119                 URL[] urls = ((URLClassLoader)loader).getURLs();
120                 if (urls != null)
121                 {
122                     URI[] uris = new URI[urls.length];
123                     int i=0;
124                     for (URL u : urls)
125                         uris[i++] = u.toURI();
126                     scan (pattern, uris, isNullInclusive);
127                 }
128             }     
129             if (visitParent)
130                 loader=loader.getParent();
131             else
132                 loader = null;
133         }  
134     }
135     
136     
137     public void matched (URI uri)
138     throws Exception
139     {
140         Log.debug("Search of {}",uri);
141         if (uri.toString().toLowerCase().endsWith(".jar"))
142         {
143          
144             InputStream in = Resource.newResource(uri).getInputStream();
145             if (in==null)
146                 return;
147 
148             JarInputStream jar_in = new JarInputStream(in);
149             try
150             { 
151                 JarEntry entry = jar_in.getNextJarEntry();
152                 while (entry!=null)
153                 {
154                     processEntry(uri, entry);
155                     entry = jar_in.getNextJarEntry();
156                 }
157             }
158             finally
159             {
160                 jar_in.close();
161             }   
162         }
163     }
164 }