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