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