package org.jboss.varia.deployment;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.jboss.deployment.DeploymentException;
import org.jboss.deployment.DeploymentInfo;
import org.jboss.deployment.MainDeployerMBean;
import org.jboss.deployment.SubDeployer;
import org.jboss.deployment.SubDeployerSupport;
import org.jboss.system.ServiceControllerMBean;
import org.jboss.system.server.ServerConfig;
import org.jboss.system.server.ServerConfigLocator;
import org.jboss.util.Counter;
import org.jboss.util.file.Files;
import org.jboss.util.file.JarUtils;
import org.jboss.mx.util.MBeanProxyExt;
import org.jboss.varia.deployment.convertor.Convertor;
public class FoeDeployer
extends SubDeployerSupport
implements SubDeployer, FoeDeployerMBean
{
private ServiceControllerMBean serviceController;
private File scratchDirectory;
private List converterList = new ArrayList();
private final Counter id = Counter.makeSynchronized(new Counter(0));
private ThreadLocal destinationByDI = new ThreadLocal() {
protected Object initialValue()
{
return new HashMap();
}
};
public boolean accepts(DeploymentInfo di)
{
Iterator i = converterList.iterator();
while(i.hasNext())
{
Convertor converter = (Convertor)i.next();
if(converter.accepts(di.url))
{
return true;
}
}
return false;
}
public boolean accepts(URL url)
{
Iterator i = converterList.iterator();
while(i.hasNext())
{
Convertor converter = (Convertor)i.next();
if(converter.accepts(url))
{
return true;
}
}
return false;
}
public void init(DeploymentInfo di)
throws DeploymentException
{
Map destinations = (Map)destinationByDI.get();
File destination = (File)destinations.get(di.parent);
if(destination == null)
{
while(destination == null || destination.exists())
destination = new File(scratchDirectory, id.increment() + "." + di.shortName);
}
else
{
destination = new File(destination, di.shortName);
}
destinations.put(di, destination);
destinationByDI.set(destinations);
try
{
log.debug("unpacking to " + destination);
inflateJar(di.localUrl, destination);
}
catch(Exception e)
{
throw new DeploymentException("Unpacking failed: ", e);
}
super.init(di);
}
public void create(DeploymentInfo di)
throws DeploymentException
{
try
{
Map destinations = (Map)destinationByDI.get();
File inflateDest = (File)destinations.get(di);
Iterator i = converterList.iterator();
while(i.hasNext())
{
Convertor converter = (Convertor)i.next();
if(converter.accepts(di.url))
{
converter.convert(di, inflateDest);
break;
}
}
File deflateDest = (File)destinations.get(di.parent);
if(deflateDest == null)
deflateDest = scratchDirectory;
String validName = null;
if(di.shortName.endsWith(".wl"))
validName = di.shortName.substring(0, di.shortName.length()-3);
else
validName = di.shortName.substring( 0, di.shortName.length() - 4 ) + "jar";
File convertedUnit = new File(deflateDest, validName);
log.debug("deflating to " + convertedUnit);
deflateJar(convertedUnit, inflateDest);
Files.delete(inflateDest);
if(di.parent == null)
copyFile(convertedUnit, new File(di.url.getFile()).getParentFile());
}
catch(Exception e)
{
log.error("Conversion error: ", e);
}
}
public void start(DeploymentInfo di)
throws DeploymentException
{
stop(di);
destroy(di);
}
public void stop(DeploymentInfo di)
{
log.debug("undeploying application: " + di.url);
}
public void destroy(DeploymentInfo di)
{
List services = di.mbeans;
int lastService = services.size();
for(ListIterator i = services.listIterator(lastService); i.hasPrevious();)
{
ObjectName name = (ObjectName)i.previous();
log.debug( "destroying mbean " + name );
try
{
serviceController.destroy(name);
}
catch(Exception e)
{
log.error("Could not destroy mbean: " + name, e);
}
}
for(ListIterator i = services.listIterator(lastService); i.hasPrevious();)
{
ObjectName name = (ObjectName)i.previous();
log.debug("removing mbean " + name);
try
{
serviceController.remove( name );
}
catch(Exception e)
{
log.error("Could not remove mbean: " + name, e);
}
}
}
protected void addDeployableJar(DeploymentInfo di, JarFile jarFile)
throws DeploymentException
{
String urlPrefix = "jar:" + di.localUrl.toString() + "!/";
for(Enumeration e = jarFile.entries(); e.hasMoreElements();)
{
JarEntry entry = (JarEntry)e.nextElement();
String name = entry.getName();
try
{
URL url = new URL(urlPrefix + name);
if(isDeployable(name, url))
{
URL nestedURL = JarUtils.extractNestedJar(url, this.tempDeployDir);
File file = new File(nestedURL.getFile());
File wlFile = new File(nestedURL.getFile() + ".wl");
file.renameTo(wlFile);
if(accepts(wlFile.toURL()))
{
deployUrl(di, wlFile.toURL(), name + ".wl");
}
else
{
wlFile.renameTo(new File(nestedURL.getFile()));
}
}
}
catch(MalformedURLException mue)
{
log.warn("Jar entry invalid; ignoring: " + name, mue);
}
catch(IOException ex)
{
log.warn("Failed to extract nested jar; ignoring: " + name, ex);
}
}
}
protected void startService()
throws Exception
{
mainDeployer = (MainDeployerMBean) MBeanProxyExt.create(
MainDeployerMBean.class,
MainDeployerMBean.OBJECT_NAME,
server
);
serviceController = (ServiceControllerMBean) MBeanProxyExt.create(
ServiceControllerMBean.class,
ServiceControllerMBean.OBJECT_NAME,
server
);
ServerConfig config = ServerConfigLocator.locate();
File tempDirectory = config.getServerTempDir();
scratchDirectory = new File(tempDirectory, "foe");
if(!scratchDirectory.exists())
scratchDirectory.mkdirs();
super.startService();
}
protected ObjectName getObjectName(MBeanServer server, ObjectName name)
throws MalformedObjectNameException
{
return name == null ? OBJECT_NAME : name;
}
public void addConvertor(Convertor converter)
{
converterList.add(converter);
Collection waitingDeployments = mainDeployer.listWaitingForDeployer();
if((waitingDeployments != null) && (waitingDeployments.size() > 0))
{
for( Iterator iter = waitingDeployments.iterator(); iter.hasNext(); )
{
DeploymentInfo di = (DeploymentInfo)iter.next();
if(!converter.accepts(di.url))
continue;
log.debug("trying to deploy with new converter: " + di.shortName);
try
{
mainDeployer.redeploy(di);
}
catch (DeploymentException e)
{
log.error("DeploymentException while trying to deploy a package with new converter", e);
}
}
}
}
public void removeConvertor(Convertor converter)
{
converterList.remove(converter);
}
protected void inflateJar( URL fileURL, File destinationDirectory )
throws DeploymentException, IOException
{
File destFile = new File(fileURL.getFile());
InputStream input = new FileInputStream(fileURL.getFile());
JarUtils.unjar(input, destinationDirectory);
}
private void deflateJar( File jarFile, File root )
throws Exception
{
OutputStream output = new FileOutputStream(jarFile);
JarUtils.jar(output, root.listFiles(), null, null, null);
output.close();
}
private void copyFile(File source, File destinationDirectory)
throws Exception
{
File target = new File( destinationDirectory, source.getName() );
Files.copy(source, target);
}
}