package org.jboss.deployment.spi;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.jboss.deployment.spi.status.DeploymentStatusImpl;
import org.jboss.deployment.spi.status.ProgressObjectImpl;
import org.jboss.logging.Logger;
import org.jboss.util.xml.JBossEntityResolver;
import javax.enterprise.deploy.model.DeployableObject;
import javax.enterprise.deploy.shared.ActionType;
import javax.enterprise.deploy.shared.CommandType;
import javax.enterprise.deploy.shared.DConfigBeanVersionType;
import javax.enterprise.deploy.shared.ModuleType;
import javax.enterprise.deploy.shared.StateType;
import javax.enterprise.deploy.spi.DeploymentConfiguration;
import javax.enterprise.deploy.spi.DeploymentManager;
import javax.enterprise.deploy.spi.Target;
import javax.enterprise.deploy.spi.TargetModuleID;
import javax.enterprise.deploy.spi.exceptions.DConfigBeanVersionUnsupportedException;
import javax.enterprise.deploy.spi.exceptions.InvalidModuleException;
import javax.enterprise.deploy.spi.exceptions.TargetException;
import javax.enterprise.deploy.spi.status.DeploymentStatus;
import javax.enterprise.deploy.spi.status.ProgressObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class DeploymentManagerImpl implements DeploymentManager
{
private static final Logger log = Logger.getLogger(DeploymentManagerImpl.class);
public static final String DEPLOYER_SCHEME = "jboss-deployer";
private Target[] targets;
private HashMap mapDeploymentPlan;
private DeploymentMetaData metaData;
private List tmpFiles = new ArrayList();
private URI deployURI;
private boolean isConnected;
public DeploymentManagerImpl(URI deployURI, boolean isConnected)
{
this(deployURI, isConnected, null, null);
}
public DeploymentManagerImpl(URI deployURI, boolean isConnected, String username, String password)
{
this.deployURI = deployURI;
this.isConnected = isConnected;
}
public Target[] getTargets()
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
if (targets == null)
{
if (deployURI.isOpaque())
{
log.debug("Using LocalhostTarget");
targets = new Target[]{new LocalhostTarget()};
}
else
{
log.debug("Using JMXTarget");
targets = new Target[]{new JMXTarget(deployURI)};
}
}
return targets;
}
public TargetModuleID[] getRunningModules(ModuleType moduleType, Target[] targets)
throws TargetException
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
log.debug("getRunningModules [type=" + moduleType + ",targets=" + Arrays.asList(targets) + "]");
Set moduleSet = new HashSet();
TargetModuleID[] availableModules = getAvailableModules(moduleType, targets);
for (int i = 0; i < availableModules.length; i++)
{
TargetModuleIDImpl moduleID = (TargetModuleIDImpl)availableModules[i];
if (moduleID.isRunning())
{
moduleSet.add(moduleID);
}
}
TargetModuleID[] idarr = new TargetModuleID[moduleSet.size()];
moduleSet.toArray(idarr);
return idarr;
}
public TargetModuleID[] getNonRunningModules(ModuleType moduleType, Target[] targets)
throws TargetException
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
log.debug("getNonRunningModules [type=" + moduleType + ",targets=" + Arrays.asList(targets) + "]");
Set moduleSet = new HashSet();
TargetModuleID[] availableModules = getAvailableModules(moduleType, targets);
for (int i = 0; i < availableModules.length; i++)
{
TargetModuleIDImpl moduleID = (TargetModuleIDImpl)availableModules[i];
if (!moduleID.isRunning())
{
moduleSet.add(moduleID);
}
}
TargetModuleID[] idarr = new TargetModuleID[moduleSet.size()];
moduleSet.toArray(idarr);
return idarr;
}
public TargetModuleID[] getAvailableModules(ModuleType moduleType, Target[] targets)
throws TargetException
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
log.debug("getAvailableModules [type=" + moduleType + ",targets=" + Arrays.asList(targets) + "]");
List targetModules = new ArrayList();
for (int i = 0; i < targets.length; i++)
{
JBossTarget target = (JBossTarget)targets[i];
TargetModuleID[] tmids = target.getAvailableModules(moduleType);
targetModules.addAll(Arrays.asList(tmids));
}
if (targetModules.size() > 0)
{
TargetModuleID[] idarr = new TargetModuleID[targetModules.size()];
targetModules.toArray(idarr);
return idarr;
}
return null;
}
public DeploymentConfiguration createConfiguration(DeployableObject obj)
throws InvalidModuleException
{
throw new UnsupportedOperationException("createConfiguration");
}
public ProgressObject distribute(Target[] targets, File moduleArchive,
File deploymentPlan)
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
InputStream isModuleArchive = null;
InputStream isDeploymentPlan = null;
try
{
isModuleArchive = new FileInputStream(moduleArchive);
isDeploymentPlan = new FileInputStream(deploymentPlan);
return distribute(targets, isModuleArchive, isDeploymentPlan);
}
catch (FileNotFoundException e)
{
String message = "Cannot find deployment: " + e.getMessage();
log.error(message, e);
DeploymentStatus status = new DeploymentStatusImpl(StateType.FAILED, CommandType.DISTRIBUTE, ActionType.EXECUTE, message);
return new ProgressObjectImpl(status, null);
}
}
public ProgressObject distribute(Target[] targets, InputStream moduleArchive,
InputStream deploymentPlan)
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
URL deployment = null;
TargetModuleID[] targetModuleIDs = new TargetModuleID[targets.length];
try
{
mapDeploymentPlan = unpackDeploymentPlan(deploymentPlan);
initDeploymentMetaData();
deployment = createDeployment(moduleArchive);
for (int i = 0; i < targets.length; i++)
{
JBossTarget target = (JBossTarget)targets[i];
String moduleID = deployment.toExternalForm();
targetModuleIDs[i] = new TargetModuleIDImpl(target, moduleID, null, false);
}
for (int i = 0; i < tmpFiles.size(); i++)
{
File file = (File)tmpFiles.get(i);
if (file.equals(deployment) == false)
file.delete();
}
}
catch (IOException e)
{
String message = "Exception during deployment validation";
log.error(message, e);
DeploymentStatus status = new DeploymentStatusImpl(StateType.FAILED, CommandType.DISTRIBUTE, ActionType.EXECUTE, message);
return new ProgressObjectImpl(status, targetModuleIDs);
}
DeploymentStatus status = new DeploymentStatusImpl(StateType.RUNNING, CommandType.DISTRIBUTE, ActionType.EXECUTE, null);
ProgressObject progress = new ProgressObjectImpl(status, targetModuleIDs);
DeploymentWorker worker = new DeploymentWorker(progress);
worker.start();
return progress;
}
private void initDeploymentMetaData()
throws IOException
{
File metaTmpFile = (File)mapDeploymentPlan.get(DeploymentMetaData.ENTRY_NAME);
if (metaTmpFile == null)
throw new IOException("Deployment plan does not contain an entry: " + DeploymentMetaData.ENTRY_NAME);
try
{
SAXReader saxReader = new SAXReader();
saxReader.setEntityResolver(new JBossEntityResolver());
Document metaDoc = saxReader.read(metaTmpFile);
metaData = new DeploymentMetaData(metaDoc);
log.debug(DeploymentMetaData.ENTRY_NAME + "\n" + metaData.toXMLString());
}
catch (Exception e)
{
log.error("Cannot obtain meta data: " + e);
}
}
private URL createDeployment(InputStream moduleArchive)
throws IOException
{
File tmpFile = File.createTempFile("jboss_deployment_", ".zip");
log.debug("temporary deployment file: " + tmpFile);
JarInputStream jis = new JarInputStream(moduleArchive);
JarOutputStream jos = null;
FileOutputStream fos = new FileOutputStream(tmpFile);
Manifest manifest = jis.getManifest();
if (manifest != null)
jos = new JarOutputStream(fos, manifest);
else
jos = new JarOutputStream(fos);
ModuleType moduleType = null;
JarEntry entry = jis.getNextJarEntry();
while (entry != null)
{
String entryName = entry.getName();
if (entryName.endsWith("/") == false)
{
if (entryName.endsWith("/application.xml"))
{
moduleType = ModuleType.EAR;
}
else if (entryName.endsWith("/application-client.xml"))
{
moduleType = ModuleType.CAR;
}
else if (entryName.endsWith("/ra.xml"))
{
moduleType = ModuleType.RAR;
}
else if (entryName.endsWith("/web.xml"))
{
moduleType = ModuleType.WAR;
}
else if (entryName.endsWith("/ejb-jar.xml"))
{
moduleType = ModuleType.EJB;
}
if (entryName.endsWith(".jar") || entryName.endsWith(".war"))
{
File tmpSubModule = processSubModule(entryName, jis);
FileInputStream fis = new FileInputStream(tmpSubModule);
JarUtils.addJarEntry(jos, entryName, fis);
fis.close();
}
else
{
JarUtils.addJarEntry(jos, entryName, jis);
}
}
entry = jis.getNextJarEntry();
}
if (moduleType == null)
{
throw new RuntimeException("cannot obtain module type");
}
addDeploymentPlanEntry(jos, null);
jos.close();
String deploymentName = tmpFile.getParent() + File.separator + metaData.getDeploymentName();
File deployment = new File(deploymentName);
if (deployment.exists() && deployment.delete() == false)
throw new IOException("Cannot delete existing deployment: " + deployment);
tmpFile.renameTo(deployment);
return deployment.toURL();
}
public ProgressObject redeploy(TargetModuleID[] targetModuleIDs,
File file, File file1)
throws UnsupportedOperationException, IllegalStateException
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
throw new UnsupportedOperationException("redeploy");
}
public ProgressObject redeploy(TargetModuleID[] targetModuleIDs,
InputStream inputStream, InputStream inputStream1)
throws UnsupportedOperationException, IllegalStateException
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
throw new UnsupportedOperationException("redeploy");
}
public ProgressObject start(TargetModuleID[] targetModuleIDs)
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
log.debug("start " + Arrays.asList(targetModuleIDs));
DeploymentStatus status = new DeploymentStatusImpl(StateType.RUNNING, CommandType.START, ActionType.EXECUTE, null);
ProgressObject progress = new ProgressObjectImpl(status, targetModuleIDs);
DeploymentWorker worker = new DeploymentWorker(progress);
worker.start();
return progress;
}
public ProgressObject stop(TargetModuleID[] targetModuleIDs)
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
log.debug("stop " + Arrays.asList(targetModuleIDs));
DeploymentStatus status = new DeploymentStatusImpl(StateType.RUNNING, CommandType.STOP, ActionType.EXECUTE, null);
ProgressObject progress = new ProgressObjectImpl(status, targetModuleIDs);
DeploymentWorker worker = new DeploymentWorker(progress);
worker.start();
return progress;
}
public ProgressObject undeploy(TargetModuleID[] targetModuleIDs)
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
log.debug("undeploy " + Arrays.asList(targetModuleIDs));
DeploymentStatus status = new DeploymentStatusImpl(StateType.RUNNING, CommandType.UNDEPLOY, ActionType.EXECUTE, null);
ProgressObject progress = new ProgressObjectImpl(status, targetModuleIDs);
DeploymentWorker worker = new DeploymentWorker(progress);
worker.start();
return progress;
}
public boolean isRedeploySupported()
{
return false;
}
public ProgressObject redeploy(TargetModuleID[] moduleIDList)
{
if (isConnected == false)
throw new IllegalStateException("DeploymentManager is not connected");
throw new UnsupportedOperationException("redeploy");
}
public void release()
{
isConnected = false;
}
public Locale getDefaultLocale()
{
return Locale.getDefault();
}
public Locale getCurrentLocale()
{
return Locale.getDefault();
}
public void setLocale(Locale locale)
{
throw new UnsupportedOperationException("setLocale");
}
public boolean isLocaleSupported(Locale locale)
{
return Locale.getDefault().equals(locale);
}
public Locale[] getSupportedLocales()
{
return new Locale[]{Locale.getDefault()};
}
public DConfigBeanVersionType getDConfigBeanVersion()
{
return DConfigBeanVersionType.V1_4;
}
public void setDConfigBeanVersion(DConfigBeanVersionType dConfigBeanVersionType)
throws DConfigBeanVersionUnsupportedException
{
throw new UnsupportedOperationException("setDConfigBeanVersion");
}
public boolean isDConfigBeanVersionSupported(DConfigBeanVersionType dConfigBeanVersionType)
{
return dConfigBeanVersionType == DConfigBeanVersionType.V1_4;
}
public boolean isDConfigBeanVersionTypeSupported(DConfigBeanVersionType version)
{
return version == DConfigBeanVersionType.V1_4;
}
public void setDConfigBeanVersionType(DConfigBeanVersionType version)
{
throw new UnsupportedOperationException("setDConfigBeanVersionType");
}
private File processSubModule(String entryName, JarInputStream jis)
throws IOException
{
File tmpModule = getTempFile(entryName);
tmpFiles.add(tmpModule);
FileOutputStream fos = new FileOutputStream(tmpModule);
JarUtils.copyStream(fos, jis);
fos.close();
JarInputStream jisModule = new JarInputStream(new FileInputStream(tmpModule));
File tmpJBossModule = getTempFile("jboss_" + entryName);
tmpFiles.add(tmpJBossModule);
JarOutputStream jos = null;
fos = new FileOutputStream(tmpJBossModule);
Manifest manifest = jisModule.getManifest();
if (manifest != null)
jos = new JarOutputStream(fos, manifest);
else
jos = new JarOutputStream(fos);
JarEntry entry = jisModule.getNextJarEntry();
while (entry != null)
{
String subEntryName = entry.getName();
JarUtils.addJarEntry(jos, subEntryName, jisModule);
entry = jisModule.getNextJarEntry();
}
jisModule.close();
addDeploymentPlanEntry(jos, entryName);
jos.close();
return tmpJBossModule;
}
private void addDeploymentPlanEntry(JarOutputStream jos, String moduleName)
throws IOException
{
if (moduleName == null)
moduleName = "";
String moduleKey = moduleName + "!/";
Iterator it = mapDeploymentPlan.keySet().iterator();
while (it.hasNext())
{
String key = (String)it.next();
if (key.startsWith(moduleKey))
{
String dpName = key.substring(moduleKey.length());
log.debug("found deployment plan entry: " + dpName);
File dpFile = (File)mapDeploymentPlan.get(key);
FileInputStream dpin = new FileInputStream(dpFile);
JarUtils.addJarEntry(jos, dpName, dpin);
dpin.close();
}
}
}
private HashMap unpackDeploymentPlan(InputStream deploymentPlan)
throws IOException
{
HashMap dpMap = new HashMap();
if (deploymentPlan == null)
return dpMap;
try
{
JarInputStream jarDeploymentPlan = new JarInputStream(deploymentPlan);
JarEntry entry = jarDeploymentPlan.getNextJarEntry();
while (entry != null)
{
String entryName = entry.getName();
log.debug("unpack deployment plan entry: " + entryName);
File tempFile = getTempFile(entryName);
dpMap.put(entryName, tempFile);
FileOutputStream out = new FileOutputStream(tempFile);
JarUtils.copyStream(out, jarDeploymentPlan);
out.close();
entry = jarDeploymentPlan.getNextJarEntry();
}
}
finally
{
deploymentPlan.close();
}
return dpMap;
}
private File getTempFile(String entryName)
throws IOException
{
entryName = entryName.replace('/', '_');
int index = entryName.lastIndexOf(".");
String prefix = entryName.substring(0, index);
String suffix = entryName.substring(index);
File tempFile = File.createTempFile(prefix, suffix);
tmpFiles.add(tempFile);
return tempFile;
}
}