package org.jboss.shrinkwrap.impl.base.container;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ArchiveEventHandler;
import org.jboss.shrinkwrap.api.ArchiveFactory;
import org.jboss.shrinkwrap.api.ArchiveFormat;
import org.jboss.shrinkwrap.api.ArchivePath;
import org.jboss.shrinkwrap.api.ArchivePaths;
import org.jboss.shrinkwrap.api.ClassLoaderSearchUtilDelegator;
import org.jboss.shrinkwrap.api.Configuration;
import org.jboss.shrinkwrap.api.Domain;
import org.jboss.shrinkwrap.api.Filter;
import org.jboss.shrinkwrap.api.Filters;
import org.jboss.shrinkwrap.api.IllegalArchivePathException;
import org.jboss.shrinkwrap.api.Node;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.ByteArrayAsset;
import org.jboss.shrinkwrap.api.asset.ClassAsset;
import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset;
import org.jboss.shrinkwrap.api.asset.FileAsset;
import org.jboss.shrinkwrap.api.asset.NamedAsset;
import org.jboss.shrinkwrap.api.asset.UrlAsset;
import org.jboss.shrinkwrap.api.container.ClassContainer;
import org.jboss.shrinkwrap.api.container.LibraryContainer;
import org.jboss.shrinkwrap.api.container.ManifestContainer;
import org.jboss.shrinkwrap.api.container.ResourceContainer;
import org.jboss.shrinkwrap.api.container.ServiceProviderContainer;
import org.jboss.shrinkwrap.api.exporter.StreamExporter;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.formatter.Formatter;
import org.jboss.shrinkwrap.impl.base.ArchiveBase;
import org.jboss.shrinkwrap.impl.base.AssignableBase;
import org.jboss.shrinkwrap.impl.base.URLPackageScanner;
import org.jboss.shrinkwrap.impl.base.Validate;
import org.jboss.shrinkwrap.impl.base.asset.AssetUtil;
import org.jboss.shrinkwrap.impl.base.asset.ServiceProviderAsset;
import org.jboss.shrinkwrap.impl.base.path.BasicPath;
import org.jboss.shrinkwrap.spi.ArchiveFormatAssociable;
import org.jboss.shrinkwrap.spi.Configurable;
public abstract class ContainerBase<T extends Archive<T>> extends AssignableBase<Archive<?>> implements Archive<T>,
ManifestContainer<T>, ServiceProviderContainer<T>, ResourceContainer<T>, ClassContainer<T>, LibraryContainer<T>,
ArchiveFormatAssociable {
private static final String DEFAULT_MANIFEST = "DefaultManifest.MF";
private static final String DEFAULT_PACKAGE_NAME = "";
private final Class<T> actualType;
protected ContainerBase(final Class<T> actualType, final Archive<?> archive) {
super(archive);
Validate.notNull(actualType, "ActualType should be specified");
this.actualType = actualType;
}
@Override
public ArchiveFormat getArchiveFormat() {
return getArchive().as(Configurable.class).getConfiguration().getExtensionLoader()
.getArchiveFormatFromExtensionMapping(actualType);
}
@Override
public T add(final Archive<?> archive, final String path, final Class<? extends StreamExporter> exporter) {
this.getArchive().add(archive, path, exporter);
return covarientReturn();
}
@Override
public T add(final Archive<?> archive, final ArchivePath path, final Class<? extends StreamExporter> exporter) {
this.getArchive().add(archive, path, exporter);
return covarientReturn();
}
@Override
public T add(Asset asset, ArchivePath target) throws IllegalArgumentException {
this.getArchive().add(asset, target);
return covarientReturn();
}
@Override
public T add(Asset asset, ArchivePath path, String name) {
this.getArchive().add(asset, path, name);
return covarientReturn();
}
@Override
public T add(final Asset asset, final String target, final String name) throws IllegalArgumentException {
this.getArchive().add(asset, target, name);
return covarientReturn();
}
@Override
public T add(NamedAsset namedAsset) {
this.getArchive().add(namedAsset);
return covarientReturn();
}
@Override
public T addAsDirectories(ArchivePath... paths) throws IllegalArgumentException {
this.getArchive().addAsDirectories(paths);
return covarientReturn();
}
@Override
public T addAsDirectories(String... paths) throws IllegalArgumentException {
this.getArchive().addAsDirectories(paths);
return covarientReturn();
}
@Override
public T addAsDirectory(ArchivePath path) throws IllegalArgumentException {
this.getArchive().addAsDirectory(path);
return covarientReturn();
}
@Override
public T addAsDirectory(String path) throws IllegalArgumentException {
this.getArchive().addAsDirectory(path);
return covarientReturn();
}
@Override
public T addHandlers(ArchiveEventHandler... handlers) {
for (ArchiveEventHandler handler : handlers) {
this.getArchive().addHandlers(handler);
}
return covarientReturn();
}
@Override
public T merge(Archive<?> source) throws IllegalArgumentException {
this.getArchive().merge(source);
return covarientReturn();
}
@Override
public T merge(Archive<?> source, Filter<ArchivePath> filter) throws IllegalArgumentException {
this.getArchive().merge(source, filter);
return covarientReturn();
}
@Override
public T merge(Archive<?> source, ArchivePath path) throws IllegalArgumentException {
this.getArchive().merge(source, path);
return covarientReturn();
}
@Override
public T merge(Archive<?> source, ArchivePath path, Filter<ArchivePath> filter) throws IllegalArgumentException {
this.getArchive().merge(source, path, filter);
return covarientReturn();
}
@Override
public T merge(final Archive<?> source, final String path, final Filter<ArchivePath> filter)
throws IllegalArgumentException {
this.getArchive().merge(source, path, filter);
return covarientReturn();
}
@Override
public T merge(final Archive<?> source, final String path) throws IllegalArgumentException {
this.getArchive().merge(source, path);
return covarientReturn();
}
@Override
public T move(ArchivePath source, ArchivePath target) throws IllegalArgumentException, IllegalArchivePathException {
this.getArchive().move(source, target);
return covarientReturn();
}
@Override
public T move(String source, String target) throws IllegalArgumentException, IllegalArchivePathException {
this.getArchive().move(source, target);
return covarientReturn();
}
@Override
public T add(Asset asset, String name) {
this.getArchive().add(asset, name);
return covarientReturn();
}
@Override
public boolean contains(ArchivePath path) {
return this.getArchive().contains(path);
}
@Override
public boolean contains(final String path) throws IllegalArgumentException {
Validate.notNull(path, "Path must be specified");
return this.contains(ArchivePaths.create(path));
}
@Override
public Node delete(ArchivePath path) {
return this.getArchive().delete(path);
}
@Override
public Node delete(String archivePath) {
Validate.notNull(archivePath, "No path was specified");
return getArchive().delete(archivePath);
}
@Override
public Node get(ArchivePath path) {
return this.getArchive().get(path);
}
@Override
public Node get(String path) throws IllegalArgumentException {
return this.getArchive().get(path);
}
@Override
public <X extends Archive<X>> X getAsType(Class<X> type, String path) {
return this.getArchive().getAsType(type, path);
}
@Override
public <X extends Archive<X>> X getAsType(Class<X> type, ArchivePath path) {
return this.getArchive().getAsType(type, path);
}
@Override
public <X extends Archive<X>> Collection<X> getAsType(Class<X> type, Filter<ArchivePath> filter) {
return this.getArchive().getAsType(type, filter);
}
@Override
public <X extends Archive<X>> X getAsType(final Class<X> type, final String path,
final ArchiveFormat archiveCompression) {
return this.getArchive().getAsType(type, path, archiveCompression);
}
@Override
public <X extends Archive<X>> X getAsType(final Class<X> type, final ArchivePath path,
final ArchiveFormat archiveCompression) {
return this.getArchive().getAsType(type, path, archiveCompression);
}
@Override
public <X extends Archive<X>> Collection<X> getAsType(final Class<X> type, final Filter<ArchivePath> filter,
final ArchiveFormat archiveCompression) {
return this.getArchive().getAsType(type, filter, archiveCompression);
}
@Override
public T filter(Filter<ArchivePath> filter) {
return this.shallowCopy(filter).as(getActualClass());
}
@Override
public Map<ArchivePath, Node> getContent() {
return this.getArchive().getContent();
}
@Override
public Map<ArchivePath, Node> getContent(Filter<ArchivePath> filter) {
return this.getArchive().getContent(filter);
}
@Override
public String getName() {
return this.getArchive().getName();
}
@Override
public String getId() {
return this.getArchive().getId();
}
@Override
public Archive<T> shallowCopy() {
return this.shallowCopy(Filters.includeAll());
}
@Override
public Archive<T> shallowCopy(Filter<ArchivePath> filter) {
Validate.notNull(filter, "Filter must be specified");
final Class<T> actualClass = this.getActualClass();
final Archive<?> underlyingArchive = this.getArchive();
final Configuration existingConfig = ((Configurable) underlyingArchive).getConfiguration();
final Domain domain = ShrinkWrap.createDomain(existingConfig);
final ArchiveFactory factory = domain.getArchiveFactory();
final Archive<T> newArchive = factory.create(actualClass, this.getName());
final Map<ArchivePath, Node> contents = underlyingArchive.getContent();
for (final ArchivePath path : contents.keySet()) {
Asset asset = contents.get(path).getAsset();
if (asset != null) {
if(!filter.include(path)) {
continue;
}
newArchive.add(asset, path);
}
}
return newArchive;
}
@Override
public String toString() {
return this.getArchive().toString();
}
@Override
public String toString(final boolean verbose) {
return this.getArchive().toString(verbose);
}
@Override
public String toString(final Formatter formatter) throws IllegalArgumentException {
return this.getArchive().toString(formatter);
}
@Override
public int hashCode() {
return this.getArchive().hashCode();
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof ArchiveBase<?>) {
return this.getArchive().equals(obj);
}
if (!(obj instanceof ContainerBase)) {
return false;
}
final ContainerBase<?> other = (ContainerBase<?>) obj;
return this.getArchive().equals(other.getArchive());
}
protected abstract ArchivePath getManifestPath();
@Override
public final T setManifest(String resourceName) {
Validate.notNull(resourceName, "ResourceName should be specified");
return setManifest(new ClassLoaderAsset(resourceName));
}
@Override
public T setManifest(File resource) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
return setManifest(new FileAsset(resource));
}
@Override
public T setManifest(URL resource) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
return setManifest(new UrlAsset(resource));
}
@Override
public T setManifest(Asset resource) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
return addAsManifestResource(resource, "MANIFEST.MF");
}
@Override
public T setManifest(Package resourcePackage, String resourceName) throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNull(resourceName, "ResourceName must be specified");
String classloaderResourceName = AssetUtil.getClassLoaderResourceName(resourcePackage, resourceName);
return setManifest(classloaderResourceName);
}
@Override
public final T addAsManifestResource(String resourceName) {
Validate.notNull(resourceName, "ResourceName should be specified");
return addAsManifestResource(fileFromResource(resourceName), resourceName);
}
@Override
public T addAsManifestResource(File resource) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
return addAsManifestResource(resource, resource.getName());
}
@Override
public T addAsManifestResource(String resourceName, String target) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName should be specified");
Validate.notNull(target, "Target should be specified");
return addAsManifestResource(fileFromResource(resourceName), target);
}
@Override
public T addAsManifestResource(File resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
return addAsManifestResource(resource, new BasicPath(target));
}
@Override
public T addAsManifestResource(URL resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
return addAsManifestResource(resource, new BasicPath(target));
}
@Override
public T addAsManifestResource(Asset resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
return addAsManifestResource(resource, new BasicPath(target));
}
@Override
public T addAsManifestResource(String resourceName, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName should be specified");
Validate.notNull(target, "Target should be specified");
return addAsManifestResource(fileFromResource(resourceName), target);
}
private T addNestedJarFileResource(final File resource, final ArchivePath target, final ArchivePath base)
throws IllegalArgumentException {
final Iterable<ClassLoader> classLoaders = ((Configurable) this.getArchive()).getConfiguration()
.getClassLoaders();
for (final ClassLoader classLoader : classLoaders) {
final InputStream in = classLoader.getResourceAsStream(resourceAdjustedPath(resource));
if (in != null) {
final Asset asset = new ByteArrayAsset(in);
return add(asset, base, target.get());
}
}
throw new IllegalArgumentException(resource.getPath() + " was not found in any available ClassLoaders");
}
private String resourceAdjustedPath(final File resource) {
final String path = resource.getPath();
final String adjustedPath = path.substring(path.indexOf("!" + File.separator) + 2, path.length());
return adjustedPath.replace(File.separator, "/");
}
@Override
public T addAsManifestResource(File resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
if (resource.isFile()) {
return addAsManifestResource(new FileAsset(resource), target);
}
final File[] files = resource.listFiles();
if (files == null) {
return this.addNestedJarFileResource(resource, target, this.getManifestPath());
}
if (files.length == 0) {
return addAsManifestResource(new FileAsset(resource), target);
}
for (File file : resource.listFiles()) {
ArchivePath child = ArchivePaths.create(file.getName());
addAsManifestResource(file, new BasicPath(target, child));
}
return covarientReturn();
}
@Override
public T addAsManifestResource(URL resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
File file = new File(resource.getFile());
if (file.exists()) {
return addAsManifestResource(file, target);
}
return addAsManifestResource(new UrlAsset(resource), target);
}
@Override
public T addAsManifestResource(Asset resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
ArchivePath location = new BasicPath(getManifestPath(), target);
return add(resource, location);
}
@Override
public T addAsManifestResources(Package resourcePackage, String... resourceNames) throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNullAndNoNullValues(resourceNames,
"ResourceNames must be specified and can not container null values");
for (String resourceName : resourceNames) {
addAsManifestResource(resourcePackage, resourceName);
}
return covarientReturn();
}
@Override
public T addAsManifestResource(Package resourcePackage, String resourceName) throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNull(resourceName, "ResourceName must be specified");
String classloaderResourceName = AssetUtil.getClassLoaderResourceName(resourcePackage, resourceName);
ArchivePath target = ArchivePaths.create(classloaderResourceName);
return addAsManifestResource(resourcePackage, resourceName, target);
}
@Override
public T addAsManifestResource(Package resourcePackage, String resourceName, String target)
throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNull(resourceName, "ResourceName must be specified");
Validate.notNull(target, "Target must be specified");
return addAsManifestResource(resourcePackage, resourceName, ArchivePaths.create(target));
}
@Override
public T addAsManifestResource(Package resourcePackage, String resourceName, ArchivePath target)
throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNull(resourceName, "ResourceName must be specified");
Validate.notNull(target, "Target must be specified");
String classloaderResourceName = AssetUtil.getClassLoaderResourceName(resourcePackage, resourceName);
Asset resource = new ClassLoaderAsset(classloaderResourceName);
return addAsManifestResource(resource, target);
}
@Override
public T addManifest() throws IllegalArgumentException {
return addAsManifestResource(DEFAULT_MANIFEST, ManifestContainer.DEFAULT_MANIFEST_NAME);
}
@Override
public T addAsServiceProvider(Class<?> serviceInterface, Class<?>... serviceImpls) throws IllegalArgumentException {
Validate.notNull(serviceInterface, "ServiceInterface must be specified");
Validate.notNullAndNoNullValues(serviceImpls, "ServiceImpls must be specified and can not contain null values");
Asset asset = new ServiceProviderAsset(serviceImpls);
ArchivePath path = new BasicPath("services", serviceInterface.getName());
return addAsManifestResource(asset, path);
}
@Override
public T addAsServiceProvider(String serviceInterface, String... serviceImpls) throws IllegalArgumentException {
Validate.notNull(serviceInterface, "ServiceInterface must be specified");
Validate.notNullAndNoNullValues(serviceImpls, "ServiceImpls must be specified and can not contain null values");
Asset asset = new ServiceProviderAsset(serviceImpls);
ArchivePath path = new BasicPath("services", serviceInterface);
return addAsManifestResource(asset, path);
}
@Override
public T addAsServiceProviderAndClasses(Class<?> serviceInterface, Class<?>... serviceImpls)
throws IllegalArgumentException {
Validate.notNull(serviceInterface, "ServiceInterface must be specified");
Validate.notNullAndNoNullValues(serviceImpls, "ServiceImpls must be specified and can not contain null values");
addAsServiceProvider(serviceInterface, serviceImpls);
addClass(serviceInterface);
return addClasses(serviceImpls);
}
protected abstract ArchivePath getResourcePath();
@Override
public final T addAsResource(String resourceName) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName should be specified");
return addAsResource(resourceName, resourceName);
}
@Override
public final T addAsResource(File resource) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
return addAsResource(resource, resource.getName());
}
@Override
public final T addAsResource(String resourceName, String target) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName should be specified");
Validate.notNull(target, "Target should be specified");
return addAsResource(fileFromResource(resourceName), target);
}
@Override
public T addAsResource(File resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
return addAsResource(resource, new BasicPath(target));
}
@Override
public T addAsResource(URL resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
return addAsResource(resource, new BasicPath(target));
}
@Override
public T addAsResource(Asset resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
return addAsResource(resource, new BasicPath(target));
}
@Override
public T addAsResource(String resourceName, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName should be specified");
Validate.notNull(target, "Target should be specified");
File resource = fileFromResource(resourceName);
return addAsResource(resource, target);
}
@Override
public T addAsResource(String resourceName, ArchivePath target, ClassLoader classLoader)
throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName should be specified");
Validate.notNull(target, "Target should be specified");
Validate.notNull(classLoader, "ClassLoader should be specified");
return addAsResource(new ClassLoaderAsset(resourceName, classLoader), target);
}
@Override
public T addAsResource(File resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
if (resource.isFile()) {
return addAsResource(new FileAsset(resource), target);
}
final File[] files = resource.listFiles();
if (files == null) {
return this.addNestedJarFileResource(resource, target, this.getResourcePath());
}
if (files.length == 0) {
return addAsDirectory(new BasicPath(getResourcePath(), target));
}
for (File file : resource.listFiles()) {
ArchivePath child = ArchivePaths.create(file.getName());
addAsResource(file, new BasicPath(target, child));
}
return covarientReturn();
}
@Override
public T addAsResource(URL resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
File file = new File(resource.getFile());
if (file.exists()) {
return addAsResource(file, target);
}
return addAsResource(new UrlAsset(resource), target);
}
@Override
public T addAsResource(Asset resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource should be specified");
Validate.notNull(target, "Target should be specified");
ArchivePath location = new BasicPath(getResourcePath(), target);
return add(resource, location);
}
@Override
public T addAsResources(Package resourcePackage, String... resourceNames) throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNullAndNoNullValues(resourceNames,
"ResourceNames must be specified and can not container null values");
for (String resourceName : resourceNames) {
addAsResource(resourcePackage, resourceName);
}
return covarientReturn();
}
@Override
public T addAsResource(Package resourcePackage, String resourceName) throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNull(resourceName, "ResourceName must be specified");
String classloaderResourceName = AssetUtil.getClassLoaderResourceName(resourcePackage, resourceName);
ArchivePath target = ArchivePaths.create(classloaderResourceName);
return addAsResource(resourcePackage, resourceName, target);
}
@Override
public T addAsResource(Package resourcePackage, String resourceName, String target) throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNull(resourceName, "ResourceName must be specified");
Validate.notNull(target, "Target must be specified");
return addAsResource(resourcePackage, resourceName, ArchivePaths.create(target));
}
@Override
public T addAsResource(Package resourcePackage, String resourceName, ArchivePath target)
throws IllegalArgumentException {
Validate.notNull(resourcePackage, "ResourcePackage must be specified");
Validate.notNull(resourceName, "ResourceName must be specified");
Validate.notNull(target, "Target must be specified");
String classloaderResourceName = AssetUtil.getClassLoaderResourceName(resourcePackage, resourceName);
Asset resource = new ClassLoaderAsset(classloaderResourceName);
return addAsResource(resource, target);
}
protected abstract ArchivePath getClassesPath();
@Override
public T addClass(Class<?> clazz) throws IllegalArgumentException {
Validate.notNull(clazz, "Clazz must be specified");
return addClasses(clazz);
}
@Override
public T addClass(String fullyQualifiedClassName) throws IllegalArgumentException {
Validate.notNullOrEmpty(fullyQualifiedClassName, "Fully-qualified class name must be specified");
Iterable<ClassLoader> cls = getArchiveClassLoaders();
assert cls != null : "CLs of this archive is not specified:" + this.getArchive();
final Class<?> classToAdd;
try {
classToAdd = ClassLoaderSearchUtilDelegator.findClassFromClassLoaders(fullyQualifiedClassName, cls);
} catch (final ClassNotFoundException cnfe) {
throw new IllegalArgumentException("Could not find the requested Class " + fullyQualifiedClassName
+ " in any of the configured ClassLoaders for this archive", cnfe);
}
return addClass(classToAdd);
}
@Override
public T addClass(final String fullyQualifiedClassName, final ClassLoader cl) throws IllegalArgumentException {
Validate.notNullOrEmpty(fullyQualifiedClassName, "Fully-qualified class name must be specified");
Validate.notNull(cl, "ClassLoader must be specified");
final Class<?> clazz;
try {
clazz = Class.forName(fullyQualifiedClassName, false, cl);
} catch (final ClassNotFoundException e) {
throw new IllegalArgumentException("Could not load class of name " + fullyQualifiedClassName + " with "
+ cl, e);
}
return this.addClass(clazz);
}
@Override
public T addClasses(Class<?>... classes) throws IllegalArgumentException {
Validate.notNull(classes, "Classes must be specified");
for (final Class<?> clazz : classes) {
Asset resource = new ClassAsset(clazz);
ArchivePath location = new BasicPath(getClassesPath(), AssetUtil.getFullPathForClassResource(clazz));
add(resource, location);
final ClassLoader loadingCl = clazz.getClassLoader();
final ClassLoader adjustedCl = loadingCl == null ? ClassLoader.getSystemClassLoader() : loadingCl;
addPackages(false, new Filter<ArchivePath>() {
@Override
public boolean include(ArchivePath path) {
ArchivePath classArchivePath = AssetUtil.getFullPathForClassResource(clazz);
String expression = classArchivePath.get().replace(".class", "\\$.*");
return path.get().matches(expression);
};
}, adjustedCl,
clazz.getPackage() == null ? DEFAULT_PACKAGE_NAME : clazz.getPackage().getName());
}
return covarientReturn();
};
@Override
public T addPackage(Package pack) throws IllegalArgumentException {
Validate.notNull(pack, "Pack must be specified");
return addPackage(pack.getName());
}
@Override
public T addPackages(boolean recursive, Package... packages) throws IllegalArgumentException {
Validate.notNull(packages, "Packages must be specified");
return addPackages(recursive, Filters.includeAll(), packages);
}
@Override
public T addPackages(final boolean recursive, final Filter<ArchivePath> filter, final Package... packages)
throws IllegalArgumentException {
return addPackages(recursive, filter, null, packages);
}
private T addPackages(final boolean recursive, final Filter<ArchivePath> filter, final ClassLoader cl,
final Package... packages) throws IllegalArgumentException {
Validate.notNull(filter, "Filter must be specified");
Validate.notNull(packages, "Packages must be specified");
String[] packageNames = new String[packages.length];
for (int i = 0; i < packages.length; i++) {
packageNames[i] = packages[i] == null ? null : packages[i].getName();
}
if (cl == null) {
return addPackages(recursive, filter, packageNames);
}
return addPackages(recursive, filter, cl, packageNames);
}
@Override
public T addPackage(String pack) throws IllegalArgumentException {
Validate.notNull(pack, "Package must be specified");
return addPackages(false, pack);
}
@Override
public T addDefaultPackage() {
return addPackages(false, DEFAULT_PACKAGE_NAME);
}
@Override
public T addPackages(boolean recursive, String... packages) throws IllegalArgumentException {
Validate.notNullAndNoNullValues(packages, "Pakcages must be specified and can not container null values");
return addPackages(recursive, Filters.includeAll(), packages);
}
@Override
public T addPackages(boolean recursive, final Filter<ArchivePath> filter, String... packageNames)
throws IllegalArgumentException {
Validate.notNull(filter, "Filter must be specified");
Validate.notNull(packageNames, "PackageNames must be specified");
final Iterable<ClassLoader> classLoaders = getArchiveClassLoaders();
for (String packageName : packageNames) {
for (final ClassLoader classLoader : classLoaders) {
addPackage(recursive, filter, classLoader, packageName);
}
}
return covarientReturn();
}
private T addPackages(final boolean recursive, final Filter<ArchivePath> filter, final ClassLoader classLoader,
String... packageNames) {
Validate.notNull(filter, "Filter must be specified");
Validate.notNull(packageNames, "PackageNames must be specified");
for (String packageName : packageNames) {
addPackage(recursive, filter, classLoader, packageName);
}
return covarientReturn();
}
private void addPackage(final boolean recursive, final Filter<ArchivePath> filter, final ClassLoader classLoader,
String packageName) {
Validate.notNull(packageName, "Package doesn't exist");
final URLPackageScanner.Callback callback = new URLPackageScanner.Callback() {
@Override
public void classFound(String className, Asset asset) {
ArchivePath classNamePath = AssetUtil.getFullPathForClassResource(className);
if (!filter.include(classNamePath)) {
return;
}
ArchivePath location = new BasicPath(getClassesPath(), classNamePath);
add(asset, location);
}
};
final URLPackageScanner scanner = URLPackageScanner.newInstance(recursive, classLoader, callback, packageName);
scanner.scanPackage();
}
@Override
public T deleteClass(Class<?> clazz) throws IllegalArgumentException {
Validate.notNull(clazz, "Class must be specified");
return deleteClasses(clazz);
}
@Override
public T deleteClass(String fullyQualifiedClassName) throws IllegalArgumentException {
Validate.notNull(fullyQualifiedClassName, "Class name must be specified");
ArchivePath path = new BasicPath(getClassesPath(), AssetUtil.getFullPathForClassResource(fullyQualifiedClassName));
getArchive().delete(path);
return covarientReturn();
}
@Override
public T deleteClasses(Class<?>... classes) throws IllegalArgumentException {
Validate.notNullAndNoNullValues(classes, "Classes must be specified and cannot contain null values");
for (Class<?> clazz : classes) {
final ArchivePath path = new BasicPath(getClassesPath(), AssetUtil.getFullPathForClassResource(clazz));
for (ArchivePath innerPath : getInnerClasses(path)) {
getArchive().delete(innerPath);
}
getArchive().delete(path);
}
return covarientReturn();
}
private Set<ArchivePath> getInnerClasses(final ArchivePath path) {
Map<ArchivePath, Node> content = getContent(new Filter<ArchivePath>() {
@Override
public boolean include(ArchivePath object) {
String expression = path.get().replace(".class", "\\$.*");
final boolean matches = object.get().matches(expression);
return matches;
}
});
return content.keySet();
}
@Override
public T deletePackage(Package pack) throws IllegalArgumentException {
Validate.notNull(pack, "Package name must be specified");
return deletePackages(false, pack);
}
@Override
public T deletePackage(String pack) throws IllegalArgumentException {
Validate.notNull(pack, "Package name must be specified");
return deletePackages(false, pack);
}
@Override
public T deleteDefaultPackage() {
return deletePackage(DEFAULT_PACKAGE_NAME);
}
@Override
public T deletePackages(boolean recursive, Package... packages) throws IllegalArgumentException {
Validate.notNullAndNoNullValues(packages, "Packages must be specified and must not contain null values");
return deletePackages(recursive, Filters.includeAll(), packages);
}
@Override
public T deletePackages(boolean recursive, String... packages) throws IllegalArgumentException {
Validate.notNullAndNoNullValues(packages, "Packages must be specified and must not contain null values");
return deletePackages(recursive, Filters.includeAll(), packages);
}
@Override
public T deletePackages(boolean recursive, Filter<ArchivePath> filter, Package... packages) throws IllegalArgumentException {
Validate.notNullAndNoNullValues(packages, "Packages must be specified and cannot contain null values");
Validate.notNull(filter, "Filter must be specified");
String[] packagesName = new String[packages.length];
for (int i = 0; i < packages.length; i++) {
packagesName[i] = packages[i].getName();
}
return deletePackages(recursive, filter, packagesName);
}
@Override
public T deletePackages(boolean recursive, Filter<ArchivePath> filter, String... packages) throws IllegalArgumentException {
Validate.notNullAndNoNullValues(packages, "Packages must be specified and cannot contain null values");
Validate.notNull(filter, "Filter must be specified");
for (String packageName : packages) {
for (ClassLoader cl : getArchiveClassLoaders()) {
deletePackage(recursive, filter, packageName, cl);
}
}
return covarientReturn();
}
private void deletePackage(boolean recursive, final Filter<ArchivePath> filter, String packageName, ClassLoader classLoader) {
assert filter != null : "Filter cannot be null";
final URLPackageScanner.Callback callback = new URLPackageScanner.Callback() {
@Override
public void classFound(String className, Asset asset) {
ArchivePath classNamePath = AssetUtil.getFullPathForClassResource(className);
if (!filter.include(classNamePath)) {
return;
}
ArchivePath location = new BasicPath(getClassesPath(), classNamePath);
delete(location);
}
};
final URLPackageScanner scanner = URLPackageScanner.newInstance(recursive, classLoader, callback, packageName);
scanner.scanPackage();
}
protected abstract ArchivePath getLibraryPath();
@Override
public T addAsLibrary(final Archive<?> archive) throws IllegalArgumentException {
Validate.notNull(archive, "Archive must be specified");
return add(archive, getLibraryPath(), ZipExporter.class);
};
@Override
public T addAsLibrary(String resourceName) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName must be specified");
File file = fileFromResource(resourceName);
return addAsLibrary(file, new BasicPath(resourceName));
}
@Override
public T addAsLibrary(File resource) throws IllegalArgumentException {
Validate.notNull(resource, "Resource must be specified");
return addAsLibrary(resource, resource.getName());
}
@Override
public T addAsLibrary(String resourceName, String target) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName must be specified");
Validate.notNull(target, "Target must be specified");
return addAsLibrary(resourceName, new BasicPath(target));
}
@Override
public T addAsLibrary(File resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource must be specified");
Validate.notNull(target, "Target must be specified");
return addAsLibrary(resource, new BasicPath(target));
}
@Override
public T addAsLibrary(URL resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource must be specified");
Validate.notNull(target, "Target must be specified");
return addAsLibrary(resource, new BasicPath(target));
}
@Override
public T addAsLibrary(Asset resource, String target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource must be specified");
Validate.notNull(target, "Target must be specified");
return addAsLibrary(resource, new BasicPath(target));
}
@Override
public T addAsLibrary(String resourceName, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resourceName, "ResourceName must be specified");
Validate.notNull(target, "Target must be specified");
return addAsLibrary(fileFromResource(resourceName), target);
}
@Override
public T addAsLibrary(File resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource must be specified");
Validate.notNull(target, "Target must be specified");
if (resource.isFile()) {
return addAsLibrary(new FileAsset(resource), target);
}
if (resource.listFiles().length == 0) {
return addAsLibrary(new FileAsset(resource), target);
}
for (File file : resource.listFiles()) {
addAsLibrary(file, new BasicPath(target, file.getName()));
}
return covarientReturn();
}
@Override
public T addAsLibrary(URL resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource must be specified");
Validate.notNull(target, "Target must be specified");
File resourceFile = new File(resource.getFile());
if (!resourceFile.exists()) {
return addAsLibrary(new UrlAsset(resource), target);
}
if (resourceFile.isFile()) {
return addAsLibrary(new UrlAsset(resource), target);
}
if (resourceFile.listFiles().length == 0) {
return addAsLibrary(new UrlAsset(resource), target);
}
for (File file : resourceFile.listFiles()) {
addAsLibrary(file, new BasicPath(target, file.getName()));
}
return covarientReturn();
}
@Override
public T addAsLibrary(Asset resource, ArchivePath target) throws IllegalArgumentException {
Validate.notNull(resource, "Resource must be specified");
Validate.notNull(target, "Target must be specified");
ArchivePath location = new BasicPath(getLibraryPath(), target);
return add(resource, location);
}
@Override
public T addAsLibraries(String... resourceNames) throws IllegalArgumentException {
Validate.notNull(resourceNames, "ResourceNames must be specified");
for (String resourceName : resourceNames) {
addAsLibrary(resourceName);
}
return covarientReturn();
}
@Override
public T addAsLibraries(File... resources) throws IllegalArgumentException {
Validate.notNull(resources, "Resources must be specified");
for (File resource : resources) {
addAsLibrary(resource);
}
return covarientReturn();
}
@Override
public T addAsLibraries(Archive<?>... archives) throws IllegalArgumentException {
Validate.notNull(archives, "Archives must be specified");
for (final Archive<?> archive : archives) {
addAsLibrary(archive);
}
return covarientReturn();
}
@Override
public T addAsLibraries(final Collection<? extends Archive<?>> archives) throws IllegalArgumentException {
Validate.notNull(archives, "Archives must be specified");
return this.addAsLibraries(archives.toArray(new Archive<?>[archives.size()]));
}
@Override
public T addAsLibraries(final Archive<?>[]... archives) throws IllegalArgumentException {
Validate.notNullAndNoNullValues(archives, "Archives must be specified");
for (Archive<?>[] archiveArray : archives) {
for (Archive<?> archive : archiveArray) {
this.addAsLibraries(archive);
}
}
return covarientReturn();
}
@Override
public void writeTo(final OutputStream outputStream, final Formatter formatter) throws IllegalArgumentException {
this.getArchive().writeTo(outputStream, formatter);
}
protected T covarientReturn() {
return getActualClass().cast(this);
}
protected Class<T> getActualClass() {
return this.actualType;
}
private File fileFromResource(final String resourceName) throws IllegalArgumentException {
final URL resourceUrl = AccessController.doPrivileged(GetTcclAction.INSTANCE).getResource(resourceName);
Validate.notNull(resourceUrl, resourceName + " doesn't exist or can't be accessed");
String resourcePath = AccessController.doPrivileged(GetTcclAction.INSTANCE).getResource(resourceName).getFile();
try {
resourcePath = URLDecoder.decode(resourcePath, "UTF-8");
} catch (UnsupportedEncodingException uee) {
throw new IllegalArgumentException(uee);
}
return new File(resourcePath);
}
private enum GetTcclAction implements PrivilegedAction<ClassLoader> {
INSTANCE;
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
}
private Iterable<ClassLoader> getArchiveClassLoaders() {
final Archive<?> archive = getArchive();
final Iterable<ClassLoader> cls = ((Configurable) archive).getConfiguration().getClassLoaders();
return cls;
}
}