blob: c81c4d35cb69ceb21444cd4f757421768c03810b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.openejb.config;
import org.apache.openejb.loader.FileUtils;
import org.apache.openejb.loader.Options;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.PerformanceTimer;
import org.apache.openejb.util.URLs;
import org.apache.xbean.finder.UrlSet;
import org.apache.xbean.finder.archive.Archive;
import org.apache.xbean.finder.archive.ClasspathArchive;
import org.apache.xbean.finder.archive.FilteredArchive;
import org.apache.xbean.finder.filter.Filter;
import org.apache.xbean.finder.filter.Filters;
import org.apache.xbean.finder.filter.IncludeExcludeFilter;
import org.apache.xbean.finder.filter.PatternFilter;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* @version $Rev$ $Date$
*/
public class NewLoaderLogic {
private static final Logger logger = DeploymentLoader.logger;
public static UrlSet filterArchives(Filter filter, ClassLoader classLoader, UrlSet urlSet) {
for (URL url : urlSet.getUrls()) {
for (Archive archive : ClasspathArchive.archives(classLoader, url)) {
FilteredArchive filtered = new FilteredArchive(archive, filter);
if (!filtered.iterator().hasNext()) {
urlSet = urlSet.exclude(url);
}
}
}
return urlSet;
}
public static Set<String> callers() {
final Set<String> callers = new LinkedHashSet<String>();
final List<StackTraceElement> elements = new ArrayList<StackTraceElement>(Arrays.asList(new Exception().fillInStackTrace().getStackTrace()));
// Yank out everything until we find a known ENTRY point
// if we don't find one, so be it, this is only a convenience
{
// Entry points are the following:
Filter start = Filters.classes("javax.ejb.embeddable.EJBContainer", "javax.naming.InitialContext");
Iterator<StackTraceElement> iterator = elements.iterator();
while (iterator.hasNext()) {
StackTraceElement element = iterator.next();
iterator.remove();
// If we haven't yet reached an entry point, just keep going
if (!start.accept(element.getClassName())) continue;
// We found an entry point.
// Fast-forward past this class
while(iterator.hasNext()&&element.getClassName().equals(iterator.next().getClassName())) iterator.remove();
// Ok, we have iterated up to the calling user class, so stop now
break;
}
}
// Now iterate till we find an END point
// We don't want any of the classes after that
{
Filter end = Filters.packages(
"junit.",
"org.junit.",
"org.testng.",
"org.apache.maven.",
"org.eclipse.",
"com.intellij."
);
// Everything between here and the end is part
// of the call chain in which we are interested
Iterator<StackTraceElement> iterator = elements.iterator();
while (iterator.hasNext()) {
StackTraceElement element = iterator.next();
if (end.accept(element.getClassName())) break;
callers.add(element.getClassName());
}
}
// We don't need this anymore
elements.clear();
// Finally filter out everything that we definitely don't want
{
Filter unwanted = Filters.packages(
"java.",
"javax.",
"sun.reflect."
);
Iterator<String> classes = callers.iterator();
while (classes.hasNext()) {
if (unwanted.accept(classes.next())) classes.remove();
}
}
return callers;
}
public static UrlSet applyBuiltinExcludes(UrlSet urlSet) throws MalformedURLException {
Filter filter = Filters.prefixes(
"activation-",
"activeio-",
"activemq-",
"aether-",
"antlr-",
"aopalliance-",
"ApacheJMeter",
"arquillian-common",
"arquillian-config-",
"arquillian-container-",
"arquillian-core-api-",
"arquillian-core-impl-base",
"arquillian-core-spi-",
"arquillian-junit-",
"arquillian-test-api",
"arquillian-test-impl-base",
"arquillian-test-spi",
"arquillian-tomee-",
"avalon-framework-",
"axis-",
"axis2-",
"access-bridge.jar",
"access-bridge-64.jar",
"annotations-api.jar",
"ant.jar",
"ant-junit*.jar",
"ant-launcher.jar",
"apple_provider.jar",
"AppleScriptEngine.jar",
"aspectj*.jar",
"bootstrap.jar",
"bcprov-",
"bval-core",
"bval-jsr",
"c3p0-",
"catalina.jar",
"catalina-",
"cglib-",
"commons-beanutils",
"commons-cli-",
"commons-codec-",
"commons-collections-",
"commons-daemon.jar",
"commons-dbcp",
"commons-dbcp-all-1.3-",
"commons-digester-",
"commons-fileupload",
"commons-discovery-",
"commons-httpclient-",
"commons-io-",
"commons-lang-",
"commons-lang3-",
"commons-logging-",
"commons-logging-api-",
"commons-math",
"commons-net-",
"commons-pool-",
"cssparser-",
"cxf-",
"CoreAudio.jar",
"dns_sd.jar",
"dnsns.jar",
"deploy.jar",
"derby-",
"derbyclient-",
"derbynet-",
"dom4j-",
"ecj-",
"eclipselink-",
"el-api.jar",
"jsp-api.jar",
"fusemq-leveldb-",
"geronimo-",
"google-",
"gragent.jar",
"gnome-java-bridge.jar",
"groovy-",
"gson",
"guice-",
"hamcrest-",
"hawtbuf-",
"hawtdispatch-",
"hawtjni-runtime",
"hibernate-",
"howl-",
"hsqldb-",
"htmlunit-",
"httpclient-",
"httpcore-",
"icu4j-",
"idb-",
"idea_rt.jar",
"jackson-mapper-asl-",
"jansi-",
"j3daudio.jar",
"j3dcore.jar",
"j3dutils.jar",
"jaccess.jar",
"jai_codec.jar",
"jai_core.jar",
"jasypt-",
"javaee-",
"javaee-api",
"javassist-",
"javaws.jar",
"javax.",
"jaxb-",
"jaxp-",
"jboss-",
"jasper.jar",
"jasper-el.jar",
"jhall.jar",
"jmx.jar",
"jmx-tools.jar",
"jstl.jar",
"jbossall-",
"jbosscx-",
"jbossjts-",
"jbosssx-",
"jcommander-",
"jersey-",
"jettison-",
"jetty",
"jline",
"jmdns-",
"joda-time-",
"jta",
"jsoup-",
"jsp-api",
"jsr299-",
"jsr311-",
"juli-",
"junit-",
"kahadb-",
"leveldb",
"log4j-",
"logkit-",
"lucene-analyzers-",
"lucene-core-",
"ldapsec.jar",
"localedata.jar",
"mail",
"maven-",
"mbean-annotation-api-",
"mimepull-",
"mina-",
"mqtt-client-",
"myfaces-api",
"myfaces-impl",
"MRJToolkit.jar",
"pulse-java.jar",
"servlet-api.jar",
"servlet-api.jar",
"neethi-",
"nekohtml-",
"openejb-api",
"openejb-client",
"openejb-core",
"openejb-cxf",
"openejb-cxf-bundle",
"openejb-cxf-rs",
"openejb-cxf-transport",
"openejb-derby",
"openejb-ejbd",
"openejb-hsql",
"openejb-http",
"openejb-javaagent",
"openejb-jee",
"openejb-jpa-integration",
"openejb-jsf",
"openejb-jstl",
"openejb-loader",
"openejb-openwebbeans",
"openejb-provisionning",
"openejb-rest",
"openejb-server",
"openejb-webservices",
"openjpa-",
"opensaml-",
"openwebbeans-",
"openws-",
"ops4j-",
"org.eclipse.",
"org.junit.",
"org.osgi.core-",
"oro-",
"pax-",
"plexus-",
"quartz-",
"rmock-",
"saaj-",
"sac-",
"scannotation-",
"serializer-",
"serp-",
"servlet-api-",
"shrinkwrap-",
"sisu-guice",
"sisu-inject",
"slf4j-",
"snappy-java-",
"spring-",
"sshd-",
"stax-api-",
"surefire-",
"swizzle-",
"testng-",
"tomcat-",
"tomee-",
"velocity-",
"wagon-",
"webbeans-ee",
"webbeans-ejb",
"webbeans-impl",
"webbeans-spi",
"woodstox-core-asl-",
"wsdl4j-",
"wss4j-",
"wstx-asl-",
"xalan-",
"xbean-",
"xercesImpl-",
"xml-apis-",
"xml-resolver-",
"xmlrpc-",
"xmlschema-",
"XmlSchema-",
"sunec.jar",
"sunjce_provider.jar",
"sunmscapi.jar",
"sunpkcs11.jar",
"tomcat-api.jar",
"tomcat-coyote.jar",
"tomcat-dbcp.jar",
"tomcat-i18n-en.jar",
"tomcat-i18n-es.jar",
"tomcat-i18n-fr.jar",
"tomcat-i18n-ja.jar",
"tomcat-jdbc.jar",
"tomcat-jni.jar",
"tomcat-spdy.jar",
"tomcat-juli.jar",
"tomcat-juli-adapters.jar",
"tomcat-util.jar",
"tools.jar",
"vecmath.jar",
"wsdl4j*.jar",
"xercesImpl.jar",
"xml-apis.jar",
"xmlParserAPIs.jar",
"zipfs.jar",
"xmlsec-",
"xmltooling-",
"xmlunit-",
"ziplock-"
);
// filter = Filters.optimize(filter, new PatternFilter(".*/openejb-.*"));
List<URL> urls = urlSet.getUrls();
Iterator<URL> iterator = urls.iterator();
while (iterator.hasNext()) {
URL url = iterator.next();
File file = URLs.toFile(url);
String name = filter(file).getName();
// System.out.println("JAR "+name);
if (filter.accept(name)) iterator.remove();
}
return new UrlSet(urls);
}
private static File filter(File location) {
List<String> invalid = new ArrayList<String>();
invalid.add("classes");
invalid.add("test-classes");
invalid.add("target");
invalid.add("build");
invalid.add("dist");
invalid.add("bin");
while (invalid.contains(location.getName())) {
location = location.getParentFile();
}
return location;
}
public static void _loadFromClasspath(FileUtils base, List<URL> jarList, ClassLoader classLoader) {
PerformanceTimer timer = new PerformanceTimer();
timer.event("create filters");
Options options = SystemInstance.get().getOptions();
String include = "";
String exclude = "";
PatternFilter classpathInclude = new PatternFilter(options.get(DeploymentFilterable.CLASSPATH_INCLUDE, ".*"));
PatternFilter classpathExclude = new PatternFilter(options.get(DeploymentFilterable.CLASSPATH_EXCLUDE, ""));
IncludeExcludeFilter classpathFilter = new IncludeExcludeFilter(classpathInclude, classpathExclude);
PatternFilter packageInclude = new PatternFilter(options.get(DeploymentFilterable.PACKAGE_INCLUDE, ".*"));
PatternFilter packageExclude = new PatternFilter(options.get(DeploymentFilterable.PACKAGE_EXCLUDE, ""));
IncludeExcludeFilter packageFilter;
if (classpathInclude.getPattern().pattern().equals(".*") && packageInclude.getPattern().pattern().equals(".*")) {
timer.event("callers");
Set<String> callers = callers();
timer.event("parse packages");
callers.size();
Set<String> packages = new HashSet<String>();
for (String caller : callers) {
String[] parts = caller.split("\\.");
if (parts.length > 2) {
parts = new String[]{parts[0], parts[1]};
}
packages.add(Join.join(".", parts));
}
Filter includes = Filters.packages(packages.toArray(new String[0]));
packageFilter = new IncludeExcludeFilter(includes, packageExclude);
} else {
packageFilter = new IncludeExcludeFilter(packageInclude, packageExclude);
}
timer.event("urlset");
Set<RequireDescriptors> requireDescriptors = options.getAll(DeploymentFilterable.CLASSPATH_REQUIRE_DESCRIPTOR, RequireDescriptors.CLIENT);
boolean filterDescriptors = options.get(DeploymentFilterable.CLASSPATH_FILTER_DESCRIPTORS, false);
boolean filterSystemApps = options.get(DeploymentFilterable.CLASSPATH_FILTER_SYSTEMAPPS, true);
try {
UrlSet urlSet = new UrlSet(classLoader);
timer.event("exclude system urls");
urlSet = urlSet.exclude(ClassLoader.getSystemClassLoader().getParent());
urlSet = urlSet.excludeJavaExtDirs();
urlSet = urlSet.excludeJavaEndorsedDirs();
urlSet = urlSet.excludeJavaHome();
urlSet = urlSet.excludePaths(System.getProperty("sun.boot.class.path", ""));
urlSet = urlSet.exclude(".*/JavaVM.framework/.*");
timer.event("classpath filter");
UrlSet beforeFiltering = urlSet;
urlSet = urlSet.filter(classpathFilter);
// If the user filtered out too much, that's a problem
if (urlSet.size() == 0) {
final String message = String.format("Classpath Include/Exclude resulted in zero URLs. There were %s possible URLs before filtering and 0 after: include=\"%s\", exclude=\"%s\"", beforeFiltering.size(), include, exclude);
logger.error(message);
logger.info("Eligible Classpath before filtering:");
for (URL url : beforeFiltering) {
logger.info(String.format(" %s", url.toExternalForm()));
}
// throw new IllegalStateException(message);
}
// If they are the same size, than nothing was filtered
// and we know the user did not take action to change the default
final boolean userSuppliedClasspathFilter = beforeFiltering.size() != urlSet.size();
if (!userSuppliedClasspathFilter) {
logger.info("Applying buildin classpath excludes");
timer.event("buildin excludes");
urlSet = applyBuiltinExcludes(urlSet);
}
DeploymentsResolver.processUrls(urlSet.getUrls(), classLoader, EnumSet.allOf(RequireDescriptors.class), base, jarList);
timer.event("package filter");
urlSet = filterArchives(packageFilter, classLoader, urlSet);
timer.event("process urls");
// we should exclude system apps before and apply user properties after
// if (filterSystemApps){
// urlSet = urlSet.exclude(".*/openejb-[^/]+(.(jar|ear|war)(!/)?|/target/(test-)?classes/?)");
// }
List<URL> urls = urlSet.getUrls();
int size = urls.size();
// if (size == 0) {
// logger.warning("No classpath URLs matched. Current settings: " + CLASSPATH_EXCLUDE + "='" + exclude + "', " + CLASSPATH_INCLUDE + "='" + include + "'");
// return;
// } else if (size == 0 && (!filterDescriptors && prefiltered.getUrls().size() == 0)) {
// return;
// } else if (size < 20) {
// logger.debug("Inspecting classpath for applications: " + urls.size() + " urls.");
// } else {
// // Has the user allowed some module types to be discoverable via scraping?
// boolean willScrape = requireDescriptors.size() < RequireDescriptors.values().length;
//
// if (size < 50 && willScrape) {
// logger.info("Inspecting classpath for applications: " + urls.size() + " urls. Consider adjusting your exclude/include. Current settings: " + CLASSPATH_EXCLUDE + "='" + exclude + "', " + CLASSPATH_INCLUDE + "='" + include + "'");
// } else if (willScrape) {
// logger.warning("Inspecting classpath for applications: " + urls.size() + " urls.");
// logger.warning("ADJUST THE EXCLUDE/INCLUDE!!!. Current settings: " + CLASSPATH_EXCLUDE + "='" + exclude + "', " + CLASSPATH_INCLUDE + "='" + include + "'");
// }
// }
long begin = System.currentTimeMillis();
DeploymentsResolver.processUrls(urls, classLoader, requireDescriptors, base, jarList);
long end = System.currentTimeMillis();
long time = end - begin;
timer.stop(System.out);
UrlSet unchecked = new UrlSet();
// if (!filterDescriptors){
// unchecked = prefiltered.exclude(urlSet);
// if (filterSystemApps){
// unchecked = unchecked.exclude(".*/openejb-[^/]+(.(jar|ear|war)(./)?|/target/classes/?)");
// }
DeploymentsResolver.processUrls(unchecked.getUrls(), classLoader, EnumSet.allOf(RequireDescriptors.class), base, jarList);
// }
if (logger.isDebugEnabled()) {
int urlCount = urlSet.getUrls().size() + unchecked.getUrls().size();
logger.debug("URLs after filtering: "+ urlCount);
for (URL url : urlSet.getUrls()) {
logger.debug("Annotations path: " + url);
}
for (URL url : unchecked.getUrls()) {
logger.debug("Descriptors path: " + url);
}
}
if (urls.size() == 0) return;
if (time < 1000) {
logger.debug("Searched " + urls.size() + " classpath urls in " + time + " milliseconds. Average " + (time / urls.size()) + " milliseconds per url.");
} else if (time < 4000 || urls.size() < 3) {
logger.info("Searched " + urls.size() + " classpath urls in " + time + " milliseconds. Average " + (time / urls.size()) + " milliseconds per url.");
} else if (time < 10000) {
logger.warning("Searched " + urls.size() + " classpath urls in " + time + " milliseconds. Average " + (time / urls.size()) + " milliseconds per url.");
logger.warning("Consider adjusting your " + DeploymentFilterable.CLASSPATH_EXCLUDE + " and " + DeploymentFilterable.CLASSPATH_INCLUDE + " settings. Current settings: exclude='" + exclude + "', include='" + include + "'");
} else {
logger.fatal("Searched " + urls.size() + " classpath urls in " + time + " milliseconds. Average " + (time / urls.size()) + " milliseconds per url. TOO LONG!");
logger.fatal("ADJUST THE EXCLUDE/INCLUDE!!!. Current settings: " + DeploymentFilterable.CLASSPATH_EXCLUDE + "='" + exclude + "', " + DeploymentFilterable.CLASSPATH_INCLUDE + "='" + include + "'");
List<String> list = new ArrayList<String>();
for (URL url : urls) {
list.add(url.toExternalForm());
}
Collections.sort(list);
for (String url : list) {
logger.info("Matched: " + url);
}
}
} catch (IOException e1) {
e1.printStackTrace();
logger.warning("Unable to search classpath for modules: Received Exception: " + e1.getClass().getName() + " " + e1.getMessage(), e1);
}
}
}