/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.deployment.services;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
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.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.enterprise.deploy.shared.ModuleType;
import javax.enterprise.deploy.spi.exceptions.TargetException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.jboss.dependency.spi.Controller;
import org.jboss.deployers.client.spi.Deployment;
import org.jboss.deployers.plugins.main.MainDeployerImpl;
import org.jboss.deployers.spi.DeploymentState;
import org.jboss.deployers.structure.spi.DeploymentContext;
import org.jboss.deployers.structure.spi.DeploymentUnit;
import org.jboss.deployers.vfs.spi.client.VFSDeploymentFactory;
import org.jboss.deployment.spi.SerializableTargetModuleID;
import org.jboss.logging.Logger;
import org.jboss.mx.util.MBeanServerLocator;
import org.jboss.system.metadata.ServiceMetaData;
import org.jboss.util.file.Files;
import org.jboss.vfs.VFS;
import org.jboss.vfs.VirtualFile;
/**
* A service that supports the JSR-88 DeploymentManager operations.
*
* @author Scott.Stark@jboss.org
* @author adrian@jboss.org
* @version $Revision: 102463 $
*/
public class DeploymentManagerService
implements DeploymentManagerServiceMBean
{
private static Logger log = Logger.getLogger(DeploymentManagerService.class);
/** The deployment factory */
VFSDeploymentFactory deploymentFactory = VFSDeploymentFactory.getInstance();
/**
* Map<deployURL, TargetID> of the deployment modules.
*/
private Map<String, SerializableTargetModuleID> moduleMap =
Collections.synchronizedMap(new HashMap<String, SerializableTargetModuleID>());
/**
* The type of attachment used to identify a CAR
*/
private Class carDeployerType;
/**
* The type of attachment used to identify a EAR
*/
private Class earDeployerType;
/**
* The type of attachment used to identify a EJB
*/
private Class ejbDeployerType;
private Class ejb3DeployerType;
/**
* The type of attachment used to identify a RAR
*/
private Class rarDeployerType;
/**
* The type of attachment used to identify a WAR
*/
private Class warDeployerType;
/**
* The MainDeployer
*/
private MainDeployerImpl mainDeployer;
/**
* The controller
*/
private Controller controller;
/**
* The local directory for uploaded content.
*/
private File uploadDir;
private boolean failOnCollision;
private boolean deleteOnUndeploy;
/**
* Get the deployment name
*
* @param file the file
* @return the name;
*/
public static String getDeploymentName(VirtualFile file)
{
if (file == null)
throw new IllegalArgumentException("Null file");
try
{
URI uri = file.asFileURI(); // gets the file path without trailing slash
return uri.toString();
}
catch (Exception e)
{
throw new IllegalArgumentException("File does not have a valid uri: " + file, e);
}
}
public MainDeployerImpl getMainDeployer()
{
return mainDeployer;
}
public void setMainDeployer(MainDeployerImpl mainDeployer)
{
this.mainDeployer = mainDeployer;
}
public Controller getController()
{
return controller;
}
public void setController(Controller controller)
{
this.controller = controller;
}
public Class getCarDeployerType()
{
return carDeployerType;
}
public void setCarDeployerType(Class carDeployerType)
{
this.carDeployerType = carDeployerType;
}
public Class getEarDeployerType()
{
return earDeployerType;
}
public void setEarDeployerType(Class earDeployerType)
{
this.earDeployerType = earDeployerType;
}
public Class getEjbDeployerType()
{
return ejbDeployerType;
}
public void setEjbDeployerType(Class ejbDeployerType)
{
this.ejbDeployerType = ejbDeployerType;
}
public Class getEjb3DeployerType()
{
return ejb3DeployerType;
}
public void setEjb3DeployerType(Class ejb3DeployerType)
{
this.ejb3DeployerType = ejb3DeployerType;
}
public Class getRarDeployerType()
{
return rarDeployerType;
}
public void setRarDeployerType(Class rarDeployerType)
{
this.rarDeployerType = rarDeployerType;
}
public Class getWarDeployerType()
{
return warDeployerType;
}
public void setWarDeployerType(Class warDeployerType)
{
this.warDeployerType = warDeployerType;
}
public void setModuleMap(Map<String, SerializableTargetModuleID> moduleMap)
{
this.moduleMap = moduleMap;
}
public File getUploadDir()
{
return this.uploadDir;
}
public void setUploadDir(File uploadDir)
{
this.uploadDir = uploadDir;
}
public boolean isDeleteOnUndeploy()
{
return deleteOnUndeploy;
}
public void setDeleteOnUndeploy(boolean deleteOnUndeploy)
{
this.deleteOnUndeploy = deleteOnUndeploy;
}
public boolean isFailOnCollision()
{
return failOnCollision;
}
public void setFailOnCollision(boolean failOnCollision)
{
this.failOnCollision = failOnCollision;
}
public Map getModuleMap()
{
return Collections.unmodifiableMap(moduleMap);
}
public void deploy(SerializableTargetModuleID moduleID) throws Exception
{
String url = moduleID.getModuleID();
// Create a status object
URL deployURL = new URL(url);
int contentLength = deployURL.openConnection().getContentLength();
log.debug("Begin deploy, url: " + deployURL + ", contentLength: " + contentLength);
// Create the local path
File path = new File(deployURL.getFile());
String archive = path.getName();
File deployFile = new File(uploadDir, archive);
if (failOnCollision && deployFile.exists())
throw new IOException("deployURL(" + deployURL + ") collides with: " + deployFile.getPath());
if (deployFile.exists())
Files.delete(deployFile);
File parentFile = deployFile.getParentFile();
if (parentFile.exists() == false)
{
if (parentFile.mkdirs() == false)
throw new IOException("Failed to create local path: " + parentFile);
}
InputStream is = moduleID.getContentIS();
if( is == null )
{
is = deployURL.openStream();
}
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[4096];
FileOutputStream fos = new FileOutputStream(deployFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int count = 0;
while ((count = bis.read(buffer)) > 0)
{
bos.write(buffer, 0, count);
}
bis.close();
bos.close();
moduleMap.put(url, moduleID);
// TODO: arrange deploy_phase2 (and TC glue code).
deploy_phase2(url);
}
/* Invoke the method on the contexts */
public void hack(SerializableTargetModuleID moduleID,
DeploymentContext info, String method)
{
try {
MBeanServer server = MBeanServerLocator.locateJBoss();
String objNames = getComponentName(info);
String contexts = null;
if (objNames != null)
{
String token = ":war=";
int i = objNames.indexOf(token);
if (i == -1)
return;
i = i + token.length();
contexts = objNames.substring(i);
}
String onStr = "*:j2eeType=WebModule,*,J2EEApplication=none,J2EEServer=none";
ObjectName objectName = new ObjectName(onStr);
Set mbeans = server.queryNames(objectName, null);
if (mbeans != null && mbeans.size () > 0 && contexts != null)
{
for (Iterator iter = mbeans.iterator(); iter.hasNext();)
{
ObjectName inst = (ObjectName) iter.next();
String name = inst.toString();
String token = ".*" + contexts + ".*";
if (name.matches(token))
{
server.invoke(inst, method, new Object[] {}, new String[] {});
}
}
}
} catch (Throwable e)
{
log.info("hack: failed" + e);
}
}
public void start(String url) throws Exception
{
SerializableTargetModuleID moduleID = (SerializableTargetModuleID)moduleMap.get(url);
if (moduleID == null)
throw new IOException("deployURL(" + url + ") has not been distributed");
if (moduleID.isRunning()) {
log.error("start, url: " + url + " Already started");
return;
}
URL deployURL = new URL(url);
// Build the local path
File path = new File(deployURL.getFile());
String archive = path.getName();
File deployFile = new File(uploadDir, archive);
VirtualFile root = VFS.getChild(deployFile.toURI());
Deployment deployment = mainDeployer.getDeployment(getDeploymentName(root));
/* TODO: that is a hack */
if (deployment == null)
{
deployment = deploymentFactory.createVFSDeployment(getDeploymentName(root), root);
mainDeployer.addDeployment(deployment);
mainDeployer.process();
moduleID.setRunning(true);
moduleID.clearChildModuleIDs();
// Repopulate the child modules
DeploymentContext context = mainDeployer.getDeploymentContext(deployment.getName());
fillChildrenTargetModuleID(moduleID, context);
}
// hack(moduleID, context, "start");
}
/*
* Get the component name.
*/
private String getComponentName(DeploymentContext context)
{
if (context == null)
return null;
DeploymentUnit u = context.getDeploymentUnit();
ServiceMetaData data = u.getAttachment(ServiceMetaData.class);
if (data == null)
return null;
ObjectName objectName = data.getObjectName();
return objectName.toString();
}
public void deploy_phase2(String url) throws Exception
{
SerializableTargetModuleID moduleID = moduleMap.get(url);
if (moduleID == null)
throw new IOException("deployURL(" + url + ") has not been distributed");
if (moduleID.isRunning())
{
return;
}
URL deployURL = new URL(url);
// Build the local path
File path = new File(deployURL.getFile());
String archive = path.getName();
File deployFile = new File(uploadDir, archive);
if (deployFile.exists() == false)
throw new IOException("deployURL(" + url + ") has no local archive");
VirtualFile root = VFS.getChild(deployFile.toURI());
Deployment deployment = deploymentFactory.createVFSDeployment(getDeploymentName(root), root);
mainDeployer.addDeployment(deployment);
DeploymentContext context = null;
try
{
mainDeployer.process();
context = mainDeployer.getDeploymentContext(deployment.getName());
mainDeployer.checkComplete(deployment);
}
catch (Exception e)
{
/* destroy the context */
hack(moduleID, context, "destroy");
/* clear the child */
moduleID.clearChildModuleIDs();
/* remove the deployment */
mainDeployer.removeDeployment(getDeploymentName(root));
mainDeployer.process();
/* remove the map */
if (deleteOnUndeploy)
Files.delete(deployFile);
moduleMap.remove(url);
throw e;
}
moduleID.setRunning(true);
moduleID.clearChildModuleIDs();
// Repopulate the child modules
fillChildrenTargetModuleID(moduleID, context);
// TODO: invoke the start.
// hack(moduleID, context, "start");
}
public void stop(String url) throws Exception
{
SerializableTargetModuleID moduleID = (SerializableTargetModuleID)moduleMap.get(url);
if (moduleID == null)
throw new IOException("deployURL(" + url + ") has not been distributed");
URL deployURL = new URL(url);
// Build the local path
File path = new File(deployURL.getFile());
String archive = path.getName();
File deployFile = new File(uploadDir, archive);
if (deployFile.exists() == false)
throw new IOException("deployURL(" + url + ") has no local archive");
VirtualFile root = VFS.getChild(deployFile.toURI());
mainDeployer.removeDeployment(getDeploymentName(root));
mainDeployer.process();
moduleID.setRunning(false);
}
public void undeploy(String url) throws Exception
{
SerializableTargetModuleID moduleID = (SerializableTargetModuleID)moduleMap.get(url);
if (moduleID == null)
return;
// If the module is still running, stop it
if (moduleID.isRunning())
stop(url);
URL deployURL = new URL(url);
// Build the local path
File path = new File(deployURL.getFile());
String archive = path.getName();
File deployFile = new File(uploadDir, archive);
if (deployFile.exists() == false)
throw new IOException("deployURL(" + url + ") has not been distributed");
if (deleteOnUndeploy)
Files.delete(deployFile);
moduleMap.remove(url);
}
public SerializableTargetModuleID[] getAvailableModules(int moduleType)
throws TargetException
{
ArrayList<SerializableTargetModuleID> matches = new ArrayList<SerializableTargetModuleID>();
Iterator<SerializableTargetModuleID> modules = moduleMap.values().iterator();
while (modules.hasNext())
{
SerializableTargetModuleID module = modules.next();
if (module.getModuleType() == moduleType)
matches.add(module);
}
SerializableTargetModuleID[] ids = new SerializableTargetModuleID[matches.size()];
matches.toArray(ids);
return ids;
}
/**
* Travers the deployment children to build up the jsr88 module children
* @param moduleID
* @param info
*/
private void fillChildrenTargetModuleID(SerializableTargetModuleID moduleID,
DeploymentContext info)
{
List<DeploymentContext> children = info.getChildren();
for(DeploymentContext ctx : children)
{
try
{
ModuleType type = getModuleType(ctx);
// Discard unknown ModuleTypes
if (type != null)
{
String module = ctx.getName();
// TODO, DEPLOYED may not be the same as running?
boolean isRunning = ctx.getState() == DeploymentState.DEPLOYED;
SerializableTargetModuleID child = new SerializableTargetModuleID(moduleID, module, type.getValue(), isRunning);
moduleID.addChildTargetModuleID(child);
fillChildrenTargetModuleID(child, ctx);
}
}
catch (UnsupportedOperationException e)
{
if (log.isTraceEnabled())
log.trace("Ignoring", e);
}
}
}
/**
* Determine the module type by looking for an attachment that identifies
* the deployer type.
*
* @param info
* @return
*/
private ModuleType getModuleType(DeploymentContext info)
{
ModuleType type = null;
DeploymentUnit unit = info.getDeploymentUnit();
if (unit.getAttachment(carDeployerType) != null)
{
type = ModuleType.CAR;
}
else if (unit.getAttachment(ejbDeployerType) != null
|| unit.getAttachment(ejb3DeployerType) != null)
{
type = ModuleType.EJB;
}
else if (unit.getAttachment(earDeployerType) != null)
{
type = ModuleType.EAR;
}
else if (unit.getAttachment(rarDeployerType) != null)
{
type = ModuleType.RAR;
}
else if (unit.getAttachment(warDeployerType) != null)
{
type = ModuleType.WAR;
}
return type;
}
}