blob: 519790f4feda05ab9363d41f2bbe95bb311927d9 [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.core.EmptyResourcesClassLoader;
import org.apache.openejb.loader.SystemInstance;
import org.apache.xbean.finder.archive.Archive;
import org.apache.xbean.finder.archive.ClassesArchive;
import org.apache.xbean.finder.archive.ClasspathArchive;
import org.apache.xbean.finder.archive.CompositeArchive;
import org.apache.xbean.finder.archive.FilteredArchive;
import org.apache.xbean.finder.filter.Filter;
import org.apache.xbean.finder.filter.FilterList;
import org.apache.xbean.finder.filter.PackageFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ConfigurableClasspathArchive extends CompositeArchive implements ScanConstants {
public ConfigurableClasspathArchive(final Module module, final URL... urls) {
this(module, Arrays.asList(urls));
}
public ConfigurableClasspathArchive(final Module module, final Iterable<URL> urls) {
this(module, false, urls);
}
public ConfigurableClasspathArchive(final ClassLoader loader, final Iterable<URL> urls) {
this(loader, false, urls);
}
public ConfigurableClasspathArchive(final ClassLoader loader, final boolean forceDescriptor, final Iterable<URL> urls) {
this(new FakeModule(loader), forceDescriptor, urls);
}
public ConfigurableClasspathArchive(final ClassLoader loader, final URL url) {
this(new FakeModule(loader), Collections.singletonList(url));
}
public ConfigurableClasspathArchive(final Module module, final boolean forceDescriptor, final Iterable<URL> urls) {
super(archive(module, urls, forceDescriptor));
}
public static List<Archive> archive(final Module module, final Iterable<URL> urls, final boolean forceDescriptor) {
final List<Archive> archives = new ArrayList<>();
for (final URL location : urls) {
try {
archives.add(archive(module, location, forceDescriptor));
} catch (final Exception e) {
// ignored
}
}
return archives;
}
public static Archive archive(final Module module, final URL location, final boolean forceDescriptor) {
final ClassLoader loader = module.getClassLoader();
final String name = "META-INF/" + name();
try {
final URL scanXml = new URLClassLoader(new URL[]{location}, new EmptyResourcesClassLoader()).getResource(name);
if (scanXml == null && !forceDescriptor) {
return ClasspathArchive.archive(loader, location);
} else if (scanXml == null) {
return new ClassesArchive();
}
// read descriptors
final ScanUtil.ScanHandler scan = ScanUtil.read(scanXml);
final Archive packageArchive = packageArchive(scan.getPackages(), loader, location);
final Archive classesArchive = classesArchive(scan.getPackages(), scan.getClasses(), loader);
if (packageArchive != null && classesArchive != null) {
return new CompositeArchive(classesArchive, packageArchive);
} else if (packageArchive != null) {
return packageArchive;
}
return classesArchive;
} catch (final IOException e) {
if (forceDescriptor) {
return new ClassesArchive();
}
return ClasspathArchive.archive(loader, location);
}
}
private static String name() {
return SystemInstance.get().getProperty(SCAN_XML_PROPERTY, SCAN_XML_NAME);
}
public static Archive packageArchive(final Set<String> packageNames, final ClassLoader loader, final URL url) {
if (!packageNames.isEmpty()) {
return new FilteredArchive(ClasspathArchive.archive(loader, url), filters(packageNames));
}
return null;
}
private static Filter filters(final Set<String> packageNames) {
final List<Filter> filters = new ArrayList<>();
for (final String packageName : packageNames) {
filters.add(new PackageFilter(packageName));
}
return new FilterList(filters);
}
public static Archive classesArchive(final Set<String> packages, final Set<String> classnames, final ClassLoader loader) {
Class<?>[] classes = new Class<?>[classnames.size()];
int i = 0;
for (final String clazz : classnames) {
// skip classes managed by package filtering
if (packages != null && clazzInPackage(packages, clazz)) {
continue;
}
try {
classes[i++] = loader.loadClass(clazz);
} catch (final ClassNotFoundException e) {
// ignored
}
}
if (i != classes.length) { // shouldn't occur
final Class<?>[] updatedClasses = new Class<?>[i];
System.arraycopy(classes, 0, updatedClasses, 0, i);
classes = updatedClasses;
}
return new ClassesArchive(classes);
}
private static boolean clazzInPackage(final Collection<String> packagename, final String clazz) {
for (final String str : packagename) {
if (clazz.startsWith(str)) {
return true;
}
}
return false;
}
public static class FakeModule extends Module {
public FakeModule(final ClassLoader loader) {
this(loader, null);
}
public FakeModule(final ClassLoader loader, final Map<String, Object> altDD) {
this(loader, altDD, name());
}
public FakeModule(final ClassLoader loader, final Map<String, Object> altDD, final String name) {
super(false);
setClassLoader(loader);
final URL scanXml;
if (altDD == null) {
scanXml = loader.getResource("META-INF/" + name);
} else {
scanXml = (URL) altDD.get(name);
}
if (scanXml != null) {
getAltDDs().put(SCAN_XML_NAME, scanXml);
}
}
}
}