//========================================================================
//$Id: JettyDeployer.java 1635 2007-03-02 08:13:13Z janb $
//Copyright 2006 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under LGPL.
//See license terms at http://www.gnu.org/licenses/lgpl.html
//========================================================================
package org.jboss.jetty;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import javax.management.ObjectName;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.LazyList;
import org.jboss.deployment.DeploymentException;
import org.jboss.deployment.DeploymentInfo;
import org.jboss.jetty.security.JBossLoginService;
import org.jboss.logging.Logger;
import org.jboss.web.AbstractWebDeployer;
import org.jboss.web.WebApplication;
import org.jboss.web.AbstractWebContainer.WebDescriptorParser;
/**
* JettyDeployer
*
* Implementation of the jboss AbstractWebDeployer
* for deploying webapps to jetty.
*/
public class JettyDeployer extends AbstractWebDeployer
{
protected static final Logger _log = Logger.getLogger("org.jboss.jetty");
protected Jetty _jetty;
protected ContextHandlerCollection _contexts;
protected DeploymentInfo _deploymentInfo;
protected JettyService.ConfigurationData _configData;
private static String[] __dftConfigurationClasses =
{
"org.eclipse.jetty.webapp.WebInfConfiguration",
"org.eclipse.jetty.webapp.WebXmlConfiguration",
"org.jboss.jetty.JBossWebXmlConfiguration",
"org.eclipse.jetty.webapp.MetaInfConfiguration",
"org.eclipse.jetty.webapp.FragmentConfiguration",
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.webapp.TagLibConfiguration"
} ;
/**
* use Hashtable because is is synchronised
*/
Hashtable _deployed = new Hashtable();
public JettyDeployer(Jetty jetty, DeploymentInfo di)
{
_jetty = jetty;
_deploymentInfo = di;
_contexts = (ContextHandlerCollection)_jetty.getChildHandlerByClass(ContextHandlerCollection.class);
}
public void init(Object containerConfig) throws Exception
{
_configData = (JettyService.ConfigurationData)containerConfig;
setLenientEjbLink(_configData.getLenientEjbLink());
setDefaultSecurityDomain(_configData.getDefaultSecurityDomain());
setJava2ClassLoadingCompliance(_configData.getJava2ClassLoadingCompliance());
setUnpackWars(_configData.getUnpackWars());
}
public void performDeploy(WebApplication webApp, String warUrl, WebDescriptorParser parser) throws DeploymentException
{
warUrl = warUrl.replace(" ", "%20");
if (log.isDebugEnabled()) log.debug("deploying webapp at "+warUrl);
try
{
String contextPath = webApp.getMetaData().getContextRoot();
if (contextPath.equalsIgnoreCase("/root"))
contextPath = "/";
webApp.setURL(new URL(warUrl));
if (_deployed.get(warUrl) != null)
throw new DeploymentException(warUrl+" is already deployed");
//make a context for the webapp and configure it from the jetty jboss-service.xml defaults
//and the jboss-web.xml descriptor
JBossWebAppContext app = new JBossWebAppContext(parser, webApp, warUrl);
app.setContextPath(contextPath);
app.setConfigurationClasses (__dftConfigurationClasses);
app.setExtractWAR(getUnpackWars());
app.setParentLoaderPriority(getJava2ClassLoadingCompliance());
if (webApp.getMetaData().getSecurityDomain() != null)
app.setRealm (new JBossLoginService(webApp.getMetaData().getSecurityDomain()));
else
app.setRealm (new JBossLoginService("other"));
//permit urls without a trailing '/' even though it is not a valid url
//as the jboss webservice client tests seem to use these invalid urls
if (_log.isDebugEnabled())
_log.debug("Allowing non-trailing '/' on context path");
app.setAllowNullPathInfo(true);
// if a different webdefault.xml file has been provided, use it
if (_configData.getWebDefaultResource() != null)
{
try
{
URL url = getClass().getClassLoader().getResource(_configData.getWebDefaultResource());
String fixedUrl = (fixURL(url.toString()));
app.setDefaultsDescriptor(fixedUrl);
if (_log.isDebugEnabled())
_log.debug("webdefault specification is: " + _configData.getWebDefaultResource());
}
catch (Exception e)
{
_log.error("Could not find resource: " + _configData.getWebDefaultResource()+" using default", e);
}
}
Iterator hosts = webApp.getMetaData().getVirtualHosts();
List hostList = new ArrayList();
while(hosts.hasNext())
hostList.add((String)hosts.next());
app.setVirtualHosts((String[])LazyList.toArray(hostList, String.class));
// Add the webapp to jetty
_contexts.addHandler(app);
//tell jboss about the classloader the webapp is using - ensure
//this is done before the context is started, because webservices
//want to get access to this classloader
webApp.getMetaData().setContextLoader(app.getClassLoader());
//if jetty has been started, then start the
//handler just added
if (_contexts.isStarted())
app.start();
// keep track of deployed contexts for undeployment
_deployed.put(warUrl, app);
//tell jboss about the jsr77 mbeans we've created
//first check that there is an mbean for the webapp itself
ObjectName webAppMBean = new ObjectName(_configData.getMBeanDomain() + ":J2EEServer=none,J2EEApplication=none,J2EEWebModule="+app.getUniqueName());
if (server.isRegistered(webAppMBean))
_deploymentInfo.deployedObject = webAppMBean;
else
throw new IllegalStateException("No mbean registered for webapp at "+app.getUniqueName());
//now get all the mbeans that represent servlets and set them on the
//deployment info so they will be found by the jsr77 management system
ObjectName servletQuery = new ObjectName
(_configData.getMBeanDomain() + ":J2EEServer=none,J2EEApplication=none,J2EEWebModule="+app.getUniqueName()+ ",j2eeType=Servlet,*");
Iterator iterator = server.queryNames(servletQuery, null).iterator();
while (iterator.hasNext())
{
_deploymentInfo.mbeans.add((ObjectName) iterator.next());
}
_log.info("successfully deployed " + warUrl + " to " + contextPath);
}
catch (Exception e)
{
_log.error("Undeploying on start due to error", e);
performUndeploy(warUrl, webApp);
throw new DeploymentException(e);
}
}
/**
* Undeploy a webapp
* @see org.jboss.web.AbstractWebDeployer#performUndeploy(java.lang.String, org.jboss.web.WebApplication)
*/
public void performUndeploy(String warUrl, WebApplication wa) throws DeploymentException
{
warUrl = warUrl.replace(" ", "%20");
JBossWebAppContext app = (JBossWebAppContext) _deployed.get(warUrl);
if (app == null)
_log.warn("app (" + warUrl + ") not currently deployed");
else
{
try
{
app.stop();
_contexts.removeHandler(app);
app.destroy();
app = null;
_log.info("Successfully undeployed " + warUrl);
}
catch (Exception e)
{
throw new DeploymentException(e);
}
finally
{
_deployed.remove(warUrl);
}
}
}
/**
* Work around broken JarURLConnection caching...
* @param url
* @return
*/
static String fixURL(String url)
{
String fixedUrl = url;
// Get the separator of the JAR URL and the file reference
int index = url.indexOf('!');
if (index >= 0)
index = url.lastIndexOf('/', index);
else
index = url.lastIndexOf('/');
// If there is at least one forward slash, add a "/." before the JAR file
// change the path just slightly. Otherwise, the url is malformed, but
// we will ignore that.
if (index >= 0)
fixedUrl = url.substring(0, index) + "/." + url.substring(index);
return fixedUrl;
}
}