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 }