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