1//
2//  ========================================================================
3//  Copyright (c) 1995-2014 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
20package org.eclipse.jetty.webapp;
21
22import java.io.InputStream;
23import java.net.URI;
24import java.net.URL;
25import java.net.URLClassLoader;
26import java.util.Locale;
27import java.util.jar.JarEntry;
28import java.util.jar.JarInputStream;
29import java.util.regex.Pattern;
30
31import org.eclipse.jetty.util.log.Log;
32import org.eclipse.jetty.util.log.Logger;
33import 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 */
47public 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}
172