View Javadoc

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