/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (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.civilian-framework.org/license.txt * * 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.civilian.internal.classpath; import java.lang.reflect.Method; import java.net.URL; import java.util.Enumeration; import java.util.Set; import org.civilian.util.Check; public class ClassPathScan { private static final String ECLIPSE_FILE_LOCATOR = "org.eclipse.core.runtime.FileLocator"; public ClassPathScan(String... rootPackages) { this(Thread.currentThread().getContextClassLoader(), rootPackages); } public ClassPathScan(ClassLoader classLoader, String... rootPackages) { classLoader_ = Check.notNull(classLoader, "classLoader"); rootPackages_ = Check.notEmpty(rootPackages, "rootPackages"); detectEquinox(); } public Set<String> collect() throws Exception { return collect((ClassFilter)null); } public Set<String> collect(ClassFilter filter) throws Exception { SimpleScanResult result = new SimpleScanResult(filter); run(result); return result.getClasses(); } public <R extends ScanListener> R run(R result) throws Exception { for (String rootPackage : rootPackages_) { ScanContext context = new ScanContext(result, rootPackage); Enumeration<URL> rootUrls = classLoader_.getResources(context.rootPath); while (rootUrls.hasMoreElements()) run(context, rootUrls.nextElement()); } return result; } private void run(ScanContext context, URL rootUrl) throws Exception { if (rootUrl.getProtocol().startsWith("bundle")) rootUrl = resolveBundleUrl(rootUrl); for (Protocol protocol : protocols_) { if (protocol.accept(rootUrl)) { protocol.scan(context, rootUrl); return; } } throw new IllegalArgumentException("no protocol implementation for URL " + rootUrl); } private URL resolveBundleUrl(URL url) { if (detectEquinox_) { detectEquinox_ = false; detectEquinox(); } if (equinoxResolveMethod_ != null) { try { url = (URL)equinoxResolveMethod_.invoke(null, url); } catch(RuntimeException e) { throw e; } catch (Exception e) { throw new IllegalStateException(e); } } return url; } public static boolean equinoxDetected() { detectEquinox(); return equinoxResolveMethod_ != null; } private static void detectEquinox() { if (equinoxResolveMethod_ == null) { try { Class<?> fileLocatorClass = ClassPathScan.class.getClassLoader().loadClass(ECLIPSE_FILE_LOCATOR); equinoxResolveMethod_ = fileLocatorClass.getMethod("resolve", URL.class); } catch (Throwable e) { } } } private ClassLoader classLoader_; private String[] rootPackages_; private boolean detectEquinox_ = true; private static Method equinoxResolveMethod_; private static Protocol[] protocols_ = { ArchiveProtocol.INSTANCE, FileProtocol.INSTANCE, VfsProtocol.INSTANCE }; }