package net.sourceforge.javautil.deployer.artifact.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EventObject;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sourceforge.javautil.common.event.IEventPropagator;
import net.sourceforge.javautil.common.event.EventProxy;
import net.sourceforge.javautil.common.io.IVirtualArtifact;
import net.sourceforge.javautil.deployer.IDeployer;
import net.sourceforge.javautil.deployer.DeployerEvent;
import net.sourceforge.javautil.deployer.DeployerException;
import net.sourceforge.javautil.deployer.DeployerEvent.Type;
import net.sourceforge.javautil.deployer.artifact.IVirtualArtifactDeployer;
import net.sourceforge.javautil.deployer.artifact.VirtualArtifactDeployerEvent;
import net.sourceforge.javautil.deployer.artifact.VirtualArtifactDeployerException;
import net.sourceforge.javautil.deployer.artifact.IVirtualArtifactDeployerListener;
import net.sourceforge.javautil.deployer.artifact.IVirtualArtifactDeployment;
import net.sourceforge.javautil.deployer.artifact.IVirtualArtifactDeploymentContext;
import net.sourceforge.javautil.deployer.event.Undeployment;
import net.sourceforge.javautil.deployer.impl.DeployerAbstract;
/**
* One or more deployers that act as one and are used according to the artifacts they handle.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class VirtualArtifactDeployerComposite extends VirtualArtifactDeployerAbstract<IVirtualArtifact, IVirtualArtifactDeployment<IVirtualArtifact>> {
protected final IVirtualArtifactDeployer<IVirtualArtifact, ? extends IVirtualArtifactDeployment<IVirtualArtifact>>[] deployers;
protected ClassLoader deploymentClassLoader = Thread.currentThread().getContextClassLoader();
public VirtualArtifactDeployerComposite(IVirtualArtifactDeployer... deployers) {
this.deployers = deployers;
for (IVirtualArtifactDeployer deployer : deployers)
deployer.addListener(this);
}
@Undeployment private void handle(VirtualArtifactDeployerEvent evt) {
if (evt.getType() != Type.UndeploymentSuccess) return;
for (IVirtualArtifactDeployer deployer : deployers) {
if (deployer != evt.getDeployer()) {
if (deployer.isDeployed(evt.getSource().getDeployed()))
deployer.undeploy(deployer.getDeployment(evt.getSource().getDeployed()));
}
}
}
public ClassLoader getDeploymentClassLoader() { return this.deploymentClassLoader; }
public void setDeploymentClassLoader(ClassLoader dcl) { this.deploymentClassLoader = dcl; }
public VirtualArtifactDeploymentComposite getDeployment(IVirtualArtifact artifact) { return this.getCompositeDeployment(artifact); }
public Collection<IVirtualArtifactDeployment<IVirtualArtifact>> getDeployments() {
Map<String, List<IVirtualArtifactDeployment<IVirtualArtifact>>> deployments = new LinkedHashMap<String, List<IVirtualArtifactDeployment<IVirtualArtifact>>>();
for (IVirtualArtifactDeployer<IVirtualArtifact, ? extends IVirtualArtifactDeployment<IVirtualArtifact>> deployer : this.deployers) {
for (IVirtualArtifactDeployment<IVirtualArtifact> deployment : deployer.getDeployments()) {
String id = this.createUniqueId(deployment.getDeployed());
if (!deployments.containsKey(id)) deployments.put(id, new ArrayList<IVirtualArtifactDeployment<IVirtualArtifact>>());
deployments.get(id).add(deployment);
}
}
if (deployments.size() == 0) return Collections.EMPTY_LIST;
List<IVirtualArtifactDeployment<IVirtualArtifact>> cd = new ArrayList<IVirtualArtifactDeployment<IVirtualArtifact>>();
for (String id : deployments.keySet()) {
cd.add(this.getCompositeDeployment(deployments.get(id).get(0).getDeployed(), deployments.get(id)));
}
return cd;
}
public boolean isDeployed(IVirtualArtifact artifact) { return this.getCompositeDeployment(artifact) != null; }
public void undeploy(IVirtualArtifactDeployment unit) {
if (unit == null) throw new IllegalArgumentException("No unit provided");
if (unit instanceof VirtualArtifactDeploymentComposite && unit.getDeployer() == this) {
VirtualArtifactDeploymentComposite composite = (VirtualArtifactDeploymentComposite) unit;
for (IVirtualArtifactDeployment cd : this.getDeployments()) {
if (cd.isLinked(unit)) cd.unlink(unit);
}
for (IVirtualArtifactDeployment<IVirtualArtifact> deployment : composite.getDeployments()) {
try {
if (deployment.getDeployer().isDeployed(deployment.getDeployed()))
deployment.getDeployer().undeploy(deployment);
} catch (VirtualArtifactDeployerException e) {
log.error("Undeplozyment failuer: " + deployment, e);
}
}
} else {
throw new VirtualArtifactDeployerException(this, unit.getDeployed(), "Unrecognized deployment: " + unit);
}
}
public IVirtualArtifactDeployment<IVirtualArtifact> deploy(IVirtualArtifact deployable) throws DeployerException {
return this.deploy(new VirtualArtifactDeploymentContext(deployable));
}
public IVirtualArtifactDeployment<IVirtualArtifact> deploy(IVirtualArtifactDeploymentContext<IVirtualArtifact, IVirtualArtifactDeployment<IVirtualArtifact>> ctx) throws VirtualArtifactDeployerException {
for (IVirtualArtifactDeployer deployer : this.find(ctx.getDeployment())) {
try {
IVirtualArtifactDeployment<IVirtualArtifact> depl = deployer.deploy(ctx);
if (depl != null) ctx.getRelatedDeployments().add( depl );
else log.warn("Null deployment returned by: " + deployer);
} catch (VirtualArtifactDeployerException e) {
log.error("Deployment failure: " + deployer, e);
}
}
if (ctx.getRelatedDeployments().size() == 0)
throw new VirtualArtifactDeployerException(this, ctx.getDeployment(), "Could not deploy artifact: " + ctx.getDeployment().getPath().toString("/"));
VirtualArtifactDeploymentComposite composite = this.getCompositeDeployment(ctx.getDeployment(), ctx.getRelatedDeployments());
for (IVirtualArtifactDeployment deployment : ctx.getRelatedDeployments()) {
composite.link(deployment, true);
}
return composite;
}
public boolean handlesDeployment(IVirtualArtifact artifact) { return this.find(artifact).size() != 0; }
/**
* This will dynamically collect all the current deployments in the different sub deployers
* and return them in a composite deployment.
*
* @param artifact The artifact for which deployments must be collected
* @return A composite deployment or null if no deployer has currently deployed the artifact
*/
protected VirtualArtifactDeploymentComposite getCompositeDeployment (IVirtualArtifact artifact) {
List<IVirtualArtifactDeployment> deployments = new ArrayList<IVirtualArtifactDeployment>();
for (IVirtualArtifactDeployer<IVirtualArtifact, ? extends IVirtualArtifactDeployment<IVirtualArtifact>> deployer : this.deployers) {
IVirtualArtifactDeployment deployment = deployer.getDeployment(artifact);
if (deployment != null) deployments.add(deployment);
}
return deployments.size() == 0 ? null : this.getCompositeDeployment(artifact, deployments);
}
/**
* Convenience method.
*
* @param artifact The artifact the deployment is for
* @param deployments The list of deployments
* @return A composite deployment instance
*/
protected VirtualArtifactDeploymentComposite getCompositeDeployment (IVirtualArtifact artifact, List deployments) {
return new VirtualArtifactDeploymentComposite(artifact, this, artifact).setDeployments(deployments);
}
/**
* @param <T> The type of deployer
* @param deployerType The class of the type
* @return The first deployer found of the specified type, otherwise null
*/
public <T extends IVirtualArtifactDeployer> T getDeployer (Class<T> deployerType) {
for (IVirtualArtifactDeployer deployer : this.deployers) {
if (deployerType.isAssignableFrom(deployer.getClass())) return (T) deployer;
}
return null;
}
/**
* @param artifact The artifact in question
* @return A list, possibly empty, of deployers that can deploy the artifact
*/
protected List<IVirtualArtifactDeployer> find (IVirtualArtifact artifact) {
List<IVirtualArtifactDeployer> deployers = new ArrayList<IVirtualArtifactDeployer>();
for (IVirtualArtifactDeployer deployer : this.deployers) {
if (deployer.handlesDeployment(artifact)) deployers.add(deployer);
}
return deployers;
}
}