Java tutorial
/** * 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 java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.net.URL; import org.xchain.framework.lifecycle.LifecycleClass; import org.xchain.framework.lifecycle.LifecycleAccessor; import org.apache.commons.collections.map.LRUMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The lifecycle scanner provides utilities for scanning the class loader of an xcahins application. * * @author Christian Trimble * @author Josh Kennedy * @author John Trimble */ @LifecycleClass(uri = "http://www.xchain.org/scanner") public class ScannerLifecycle { /* * Flag to turn on/off memoization of ScannerLifecycle.scanNode(). */ private static final boolean MEMOIZE_SCAN_NODE = true; private static Logger log = LoggerFactory.getLogger(ScannerLifecycle.class); private static ScannerLifecycle instance = new ScannerLifecycle(); private Map<ClassLoader, Map<RootUrlLocator, ScanNode>> cache; @LifecycleAccessor public static ScannerLifecycle getInstance() { return instance; } private Map<String, ProtocolScanner> protocolMap = new HashMap<String, ProtocolScanner>(); public ScannerLifecycle() { protocolMap.put("file", new FileProtocolScanner()); protocolMap.put("jar", new JarProtocolScanner()); // define the vfszip, vfsfile, and vfsmemory protocols if the jboss virtual file system classes are on the classpath. if (isVfsDefined()) { protocolMap.put("vfszip", new VfsProtocolScanner()); protocolMap.put("vfsfile", new VfsProtocolScanner()); protocolMap.put("vfsmemory", new VfsProtocolScanner()); } if (isZipDefined()) { protocolMap.put("zip", new ZipProtocolScanner()); } if (isBundleDefined()) { protocolMap.put("bundle", new BundleProtocolScanner()); protocolMap.put("bundleresource", new BundleProtocolScanner()); } if (MEMOIZE_SCAN_NODE) { cache = Collections.synchronizedMap(new WeakHashMap<ClassLoader, Map<RootUrlLocator, ScanNode>>()); } } /** * Returns the root scan node. Using this node, all of the nodes on the * classpath can be visited. */ public ScanNode scanNode() throws Exception { return scanNode(Thread.currentThread().getContextClassLoader(), new MarkerResourceLocator("META-INF/xchain.xml")); } /** * <p>Scans the root urls found by the locator and returns the root scan node for those roots.</p> */ public ScanNode scanNode(RootUrlLocator locator) throws Exception { return scanNode(Thread.currentThread().getContextClassLoader(), locator); } public ScanNode scanNode(ClassLoader classLoader, RootUrlLocator locator) throws Exception { if (MEMOIZE_SCAN_NODE) { ScanNode cachedScanNode = getCached(classLoader, locator); if (cachedScanNode != null) { log.debug("Using cached ScanNode instance '{}' for ClassLoader '{}' and RootUrlLocator '{}'.", new Object[] { cachedScanNode, classLoader, locator }); return cachedScanNode; } } ScanNode rootScanNode = new ScanNode(); Set<URL> roots = locator.findRoots(Thread.currentThread().getContextClassLoader()); for (URL root : roots) { // find the protocol scanner for this root url. String protocol = root.getProtocol(); ProtocolScanner scanner = protocolMap.get(protocol); if (scanner == null) { if (log.isDebugEnabled()) { log.debug("Could not scan protocol " + protocol + " of url " + root + ", because a scanner for this protocol is not defined."); } continue; } scanner.scan(rootScanNode, root); } if (MEMOIZE_SCAN_NODE) { putCached(classLoader, locator, rootScanNode); } return rootScanNode; } /** * Clears internal cache of ScanNode instances. */ public void clearCache() { if (MEMOIZE_SCAN_NODE) this.cache.clear(); } /* * Returns the cached ScanNode instance mapped by the (classLoader, locator) tuple. */ private ScanNode getCached(ClassLoader classLoader, RootUrlLocator locator) { Map<RootUrlLocator, ScanNode> locatorScanNodeMap = cache.get(classLoader); if (locatorScanNodeMap != null) return locatorScanNodeMap.get(locator); return null; } /* * Maps a (ClassLoader,RootUrlLocator) tuple to a ScanNode instance to cache. */ private void putCached(ClassLoader classLoader, RootUrlLocator locator, ScanNode scanNode) { Map<RootUrlLocator, ScanNode> locatorScanNodeMap = this.cache.get(classLoader); if (locatorScanNodeMap == null) { locatorScanNodeMap = Collections.synchronizedMap(new LRUMap(20)); this.cache.put(classLoader, locatorScanNodeMap); } locatorScanNodeMap.put(locator, scanNode); } private boolean isVfsDefined() { try { Thread.currentThread().getContextClassLoader().loadClass("org.jboss.virtual.VirtualFile"); // ASSERT: the virtual file class loaded, so we are on jboss 5. return true; } catch (Exception e) { return false; } } private boolean isZipDefined() { try { Thread.currentThread().getContextClassLoader().loadClass("weblogic.utils.zip.ZipURLConnection"); return true; } catch (Exception e) { return false; } } private boolean isBundleDefined() { try { Thread.currentThread().getContextClassLoader().loadClass("org.osgi.framework.Bundle"); return true; } catch (Exception e) { return false; } } }