package net.sourceforge.javautil.classloader.util;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.logging.Logger;
import net.sourceforge.javautil.classloader.boot.EntryPoint;
import net.sourceforge.javautil.classloader.boot.EntryPointClassPackage;
import net.sourceforge.javautil.classloader.boot.IEntryPointType;
import net.sourceforge.javautil.classloader.impl.ClassContext;
import net.sourceforge.javautil.classloader.resolver.ClassPackageContext;
import net.sourceforge.javautil.classloader.resolver.ClassPackageResolverContext;
import net.sourceforge.javautil.classloader.resolver.ClassPackageResolverNetworkNode;
import net.sourceforge.javautil.classloader.resolver.IClassArtifactReference;
import net.sourceforge.javautil.classloader.resolver.IClassDependencyPool;
import net.sourceforge.javautil.classloader.resolver.IClassPackage;
import net.sourceforge.javautil.classloader.resolver.IClassPackageDependencyReference;
import net.sourceforge.javautil.classloader.resolver.IClassPackageDescriptor;
import net.sourceforge.javautil.classloader.resolver.IClassPackageReference;
import net.sourceforge.javautil.classloader.resolver.IClassPackageResolver;
import net.sourceforge.javautil.classloader.resolver.IClassDependencyPool.PoolScope;
import net.sourceforge.javautil.classloader.resolver.impl.ClassDependencyPoolImpl;
import net.sourceforge.javautil.classloader.resolver.impl.ClassPackageDependencyReferenceImpl;
import net.sourceforge.javautil.classloader.resolver.impl.ClassPackageReferenceImpl;
import net.sourceforge.javautil.classloader.resolver.impl.ClassPackageResolverImpl;
import net.sourceforge.javautil.common.ClassNameUtil;
import net.sourceforge.javautil.common.logging.ILogger;
import net.sourceforge.javautil.common.logging.LoggingContext;
import net.sourceforge.javautil.common.ui.IBasicUserInterface;
import net.sourceforge.javautil.common.ui.UserInterfaceContext;
/**
* Common code used in the different API's and implementations for {@link IClassPackage}'s.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class ClassPackageUtil {
protected static ILogger log = LoggingContext.getContextualLogger(ClassPackageUtil.class);
/**
* Standard method for {@link IClassPackageReference}'s to show string form.
*
* @param reference The reference to show a string representation for
* @return The string representation
*/
public static String toString (IClassPackageReference reference) {
return reference.getClass().getSimpleName() + "[" + reference.getGroupId() + ":" + reference.getArtifactId() +
(reference.getVersion() == null ? "" : ":" + reference.getVersion().toVersionString()) +
(reference.getClassifier() == null ? "" : ":" + reference.getClassifier()) + "]";
}
/**
* Standard unique id for {@link IClassPackageReference}'s.
*
* @param reference The reference to show a string representation for
* @return The string representation
*/
public static String toPackageString (IClassPackageReference reference) {
return reference.getGroupId() + ":" + reference.getArtifactId() +
(reference.getVersion() == null ? "" : ":" + reference.getVersion().toVersionString()) +
(reference.getClassifier() == null ? "" : ":" + reference.getClassifier());
}
/**
* @param reference The reference to compare from
* @param compare The reference to compare to
* @return 1 if reference is greater that compare
*/
public static int compare (IClassArtifactReference reference, IClassArtifactReference compare) {
if (compare == null) return 1;
if (reference.getGroupId() == null || compare.getGroupId() == null) {
if (reference.getGroupId() != null) return 1;
if (compare.getGroupId() != null) return -1;
} else if (!"*".equals( reference.getGroupId() ) && !"*".equals(compare.getGroupId())) {
int gr = reference.getGroupId().compareTo(compare.getGroupId());
if (gr != 0) return gr;
}
if (reference.getArtifactId() == null || compare.getArtifactId() == null) {
if (reference.getArtifactId() != null) return 1;
if (compare.getArtifactId() != null) return -1;
} else if (!"*".equals( reference.getArtifactId() ) && !"*".equals(compare.getArtifactId())) {
int ar = reference.getArtifactId().compareTo(compare.getArtifactId());
if (ar != 0) return ar;
}
if (reference instanceof IClassPackageReference && compare instanceof IClassPackageReference) {
IClassPackageReference rcpr = (IClassPackageReference) reference;
IClassPackageReference ccpr = (IClassPackageReference) compare;
if (rcpr.getVersion() == null && ccpr.getVersion() == null) return 0;
if (rcpr.getVersion() == null) return -1;
if (ccpr.getVersion() == null) return 1;
int vr = rcpr.getVersion().compareTo(ccpr.getVersion());
if (vr != 0) return vr;
}
return 0;
}
/**
* Find a {@link IClassPackage} via a reference to it by first making sure it is appended to the pool
* and then retrieving it.
*
* @param resolver The resolver to use for finding the reference if neccesary
* @param reference The reference to resolve and/or find
* @param primary True if this reference is a primary reference
* @return The {@link IClassPackage} corresponding to the reference if it could be found/resolved, otherwise null
*/
public static IClassPackage get (IClassPackageResolver resolver, IClassPackageDependencyReference reference, boolean primary) {
ClassDependencyPoolImpl pool = new ClassDependencyPoolImpl("Lookup Temporary: " + reference);
append(pool, resolver, primary, reference);
for (
IClassPackageDescriptor desc = resolver.getImportableRepository().getDescriptor(resolver, reference);
desc != null && desc.getRelocation() != null;
desc = resolver.getImportableRepository().getDescriptor(resolver, reference)
) {
reference = new ClassPackageDependencyReferenceImpl(ClassPackageReferenceImpl.getRelocation(reference, desc.getRelocation()));
}
for (IClassPackage pkg : pool.getPackages(true)) {
if (pkg.compareTo(reference) == 0) return pkg;
}
return null;
}
/**
* Assumes no descriptor.
*
* @see #append(IClassDependencyPool, IClassPackageResolver, boolean, IClassPackageDependencyReference...)
*/
public static void append (IClassDependencyPool pool, IClassPackageResolver resolver, boolean primary, Collection<? extends IClassPackageDependencyReference> references) {
append(pool, resolver, primary, null, references);
}
/**
* This will translate the collection to an array.
*
* @see #append(IClassDependencyPool, IClassPackageResolver, boolean, IClassPackageDescriptor, Collection)
*/
public static void append (IClassDependencyPool pool, IClassPackageResolver resolver, boolean primary, IClassPackageDescriptor descriptor, Collection<? extends IClassPackageDependencyReference> references) {
append(pool, resolver, primary, descriptor, references.toArray(new IClassPackageDependencyReference[references.size()]));
}
/**
* Assumes no descriptor.
*
* @see #append(IClassDependencyPool, IClassPackageResolver, boolean, IClassPackageDescriptor, IClassPackageDependencyReference...)
*/
public static void append (IClassDependencyPool pool, IClassPackageResolver resolver, boolean primary, IClassPackageDependencyReference... references) {
append(pool, resolver, primary, null, references);
}
/**
* Facility method for loading {@link IClassPackageReference}'s into a pool.
*
* @param pool The pool to which to add the reference
* @param resolver The resolver that can locate the packages
* @param primary True if the references are primary references, otherwise false
* @param descriptor The descriptor associated with this process, or null if not available
* @param references The references to add to the pool
*/
public static void append (IClassDependencyPool pool, IClassPackageResolver resolver, boolean primary, IClassPackageDescriptor descriptor, IClassPackageDependencyReference... references) {
log.info("Resolution starting: " + new Date());
List<ClassPackageResolverNetworkNode> download = new ArrayList<ClassPackageResolverNetworkNode>();
ClassPackageResolverContext network = descriptor != null ? new ClassPackageResolverContext(descriptor) : new ClassPackageResolverContext();
for (IClassPackageDependencyReference reference : references) {
resolver.resolve(network, reference);
}
for (ClassPackageResolverNetworkNode dl : network.getDownloadable()) {
download.add(dl);
}
if (download.size() > 0) {
downloadDependencies(resolver, download.toArray(new ClassPackageResolverNetworkNode[download.size()]));
}
log.info("Resolution complete: " + new Date());
List<ClassPackageResolverNetworkNode> available = network.getAvailable();
for (ClassPackageResolverNetworkNode node : available) {
if (node.getResolution() == null) {
log.fatal("Could not resolve: " + node.getDescriptor());
continue;
}
IClassPackage pkg = node.createPackage();
if (pkg != null) pool.addWithDependencies(pkg, node.isPrimary());
else throw new RuntimeException("Could not resolve: " + node.getReference());
}
log.debug("Available packages: " + available.size());
}
public static void downloadDependencies (IClassPackageResolver resolver, ClassPackageResolverNetworkNode... download) {
boolean success = false;
IClassPackageDownloadAuthorizer cpa = null;
switch (ClassPackageContext.getDownloadAuthorization()) {
case APPROVAL:
IBasicUserInterface bui = UserInterfaceContext.getUserInterface();
if (bui != null) {
cpa = bui.getTool(IClassPackageDownloadAuthorizer.class);
}
if (cpa == null) cpa = new SimpleDownloadAuthorizer(2);
if (!cpa.authorize(download)) break;
case AUTOMATIC:
if (cpa == null) cpa = new SimpleDownloadAuthorizer(2);
Throwable error = null;
for (ClassPackageResolverNetworkNode dl : download) {
cpa.downloadStarted(dl);
do {
error = null;
try {
dl.importPackage(resolver);
} catch (Throwable t) {
error = t;
continue;
}
cpa.downloadFinished(dl);
break;
} while (cpa.downloadError(dl, error));
}
success = error == null;
default:
}
if (!success) {
log.warn("Downloading of remote packages denied");
}
}
/**
* This will assume a null parent.
*
* @see #createStandardDependencyPool(boolean, ClassContext)
*/
public static IClassDependencyPool createStandardDependencyPool (String name, boolean detectEntryPoint, PoolScope scope) {
return createStandardDependencyPool(name, detectEntryPoint, scope, (IClassDependencyPool) null);
}
/**
* This will assume the pool of the passed context
*
* @see #createStandardDependencyPool(boolean, IClassDependencyPool)
*/
public static IClassDependencyPool createStandardDependencyPool (String name, boolean usePackageContext, PoolScope scope, ClassContext parent) {
return createStandardDependencyPool(name, usePackageContext, scope, parent.getPool());
}
/**
* @param usePackageContext True if any {@link IEntryPointType}'s should be detected and used for dependency resolution, otherwise false
* @param parent The parent class loader, or null if it does not apply
* @return A standard dependency pool, possibly connected with any {@link MavenEntryPoint} that may have have been used
*/
public static IClassDependencyPool createStandardDependencyPool (String name, boolean usePackageContext, PoolScope scope, IClassDependencyPool parent) {
if (usePackageContext && ClassPackageContext.getDependencyPool() != null) {
IClassDependencyPool pool = null;
if (parent != null) {
pool = parent.createChild(name, scope);
} else {
pool = ClassPackageContext.getDependencyPool().createChild(name, scope);
}
return pool;
} else {
return parent == null ? new ClassDependencyPoolImpl(name) : (ClassDependencyPoolImpl) parent.createChild(name, scope);
}
}
/**
* @param reference The package reference for which a virtual version will be created
* @return A manifest that will contain implementation/specification title/version info from the package
*/
public static Manifest createVirtualManifest (IClassPackageReference reference) {
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
attributes.putValue(Attributes.Name.IMPLEMENTATION_TITLE.toString(), reference.toArtifactString());
attributes.putValue(Attributes.Name.SPECIFICATION_TITLE.toString(), reference.toArtifactString());
attributes.putValue(Attributes.Name.IMPLEMENTATION_VERSION.toString(), reference.getVersion().toVersionString());
attributes.putValue(Attributes.Name.SPECIFICATION_VERSION.toString(), reference.getVersion().toVersionString());
return manifest;
}
}