/** * Copyright 2011 meltmedia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xchain.framework.scanner; import static org.xchain.framework.util.AnnotationUtil.hasAnnotation; import static org.xchain.framework.util.AnnotationUtil.getAnnotationValue; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedList; import java.util.Set; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import org.xchain.framework.scanner.MarkerResourceLocator; import org.xchain.framework.scanner.ScannerLifecycle; import org.xchain.framework.scanner.ScanNode; import javassist.bytecode.AnnotationsAttribute; import javassist.bytecode.ClassFile; import javassist.bytecode.annotation.MemberValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractScanner { private static final Logger log = LoggerFactory.getLogger(AbstractScanner.class); protected RootUrlLocator rootUrlLocator; protected ClassLoader classLoader; public AbstractScanner(RootUrlLocator rootUrlLocator) { this( rootUrlLocator, Thread.currentThread().getContextClassLoader() ); } public AbstractScanner(RootUrlLocator rootUrlLocator, ClassLoader classLoader) { this.rootUrlLocator = rootUrlLocator; this.classLoader = classLoader; } /* Pattern to match path names with a *-INF directory at the base, such as WEB-INF, OSGI-INF, etc. */ private static final Pattern INF_DIR_SUBPATH_PATTERN = Pattern.compile("^[/\\\\]?[^/\\\\]+-INF[/\\\\].*$", Pattern.CASE_INSENSITIVE); /** * Returns true if the given name represents a path to a class file that does not have an INF directory at its * base. For example, <code>isLoadableClassFile('org/my/package/name/Foo.class')</code> will return true but * <code>isLoadableClassFile('org/my/package/name/Foo')</code> and <code>isLoadableClassFile('WEB-INF/classes/org/my/package/name/Foo.class')</code> * will return false. * * @param name * @return */ public static boolean isLoadableClassFile(String name) { return name.endsWith(".class") && !INF_DIR_SUBPATH_PATTERN.matcher(name).matches(); } public static String toClassName(ScanNode scanNode) { return scanNode.getResourceName().replaceAll("\\A(.*)\\.class\\Z", "$1").replaceAll("[/\\\\]", "."); } protected void scan() throws ScanException { ScannerLifecycle scanLifecycle = ScannerLifecycle.getInstance(); LinkedList<ScanNode> stack = new LinkedList<ScanNode>(); try { stack.addFirst(scanLifecycle.scanNode(rootUrlLocator)); } catch( Exception e ) { throw new ScanException("Could not build the root scan node.", e); } while( !stack.isEmpty() ) { ScanNode scanNode = stack.removeFirst(); stack.addAll(0, scanNode.getChildMap().values()); if( scanNode.isFile() ) { scanNode(scanNode); } else { if( log.isDebugEnabled() ) { log.debug("Scan node "+scanNode.getResourceName()+" not handled, it is a directory."); } } } } public abstract void scanNode(ScanNode node) throws ScanException; /** protected ClassFile getClassFile(String name) throws IOException { InputStream stream = classLoader.getResourceAsStream(name); DataInputStream dstream = new DataInputStream(stream); try { return new ClassFile(dstream); } finally { dstream.close(); stream.close(); } } */ public static String componentFilename(String name) { return name.substring( 0, name.lastIndexOf(".class") ) + ".component.xml"; } }