//========================================================================
//$Id: $
//JBoss Jetty Integration
//------------------------------------------------------------------------
//Licensed under LGPL.
//See license terms at http://www.gnu.org/licenses/lgpl.html
//========================================================================
package org.cipango.jboss;
import java.io.CharArrayWriter;
import java.lang.reflect.Method;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.cipango.SipServer;
import org.jboss.deployment.DeploymentInfo;
import org.jboss.deployment.MainDeployerMBean;
import org.jboss.deployment.SubDeployerExt;
import org.jboss.mx.util.MBeanProxyExt;
import org.jboss.system.ServiceControllerMBean;
import org.jboss.web.AbstractWebContainer;
import org.jboss.web.AbstractWebDeployer;
import org.mortbay.log.Log;
import org.mortbay.xml.XmlConfiguration;
import org.w3c.dom.Element;
//------------------------------------------------------------------------------
/**
* CipangoService
* A service to launch cipangpo as the sipserver for JBoss.
*
*
* @jmx:mbean name="jboss.cipango:service=cipango"
* extends="org.jboss.web.AbstractWebContainerMBean"
*
* @todo convert to use JMXDoclet...
*
*/
public class CipangoService extends AbstractWebContainer implements CipangoServiceMBean, MBeanRegistration
{
public static final String NAME = "Cipango";
public static final String MBEAN_DOMAIN = "org.cipango";
private MBeanServer _server = null;
private SipServer _cipango = null;
private boolean _supportJSR77;
private String _webDefaultResource;
private SubDeployerExt _subDeployerProxy = null;
private Element _cipangoConfig = null;
private SsarDeployer _ssarDeployer;
/**
* ConfigurationData
*
* Holds info that the jboss API sets on the
* AbstractWebContainer but is needed by the
* AbstractWebDeployer.
*/
public static class ConfigurationData
{
private boolean _loaderCompliance;
private boolean _unpackWars;
private boolean _lenientEjbLink;
private String _subjectAttributeName;
private String _defaultSecurityDomain;
private boolean _acceptNonWarDirs;
private String _webDefaultResource;
private boolean _supportJSR77;
private String _mbeanDomain;
/**
* @return the _webDefaultResource
*/
public String getWebDefaultResource()
{
return _webDefaultResource;
}
/**
* @param defaultResource the _webDefaultResource to set
*/
public void setWebDefaultResource(String defaultResource)
{
_webDefaultResource = defaultResource;
}
public void setJava2ClassLoadingCompliance(boolean loaderCompliance)
{
_loaderCompliance=loaderCompliance;
}
public boolean getJava2ClassLoadingCompliance()
{
return _loaderCompliance;
}
public boolean getUnpackWars()
{
return _unpackWars;
}
public void setUnpackWars(boolean unpackWars)
{
_unpackWars=unpackWars;
}
public void setLenientEjbLink (boolean lenientEjbLink)
{
_lenientEjbLink=lenientEjbLink;
}
public boolean getLenientEjbLink()
{
return _lenientEjbLink;
}
public String getSubjectAttributeName()
{
return _subjectAttributeName;
}
/**
* @jmx:managed-attribute
*/
public void setSubjectAttributeName(String subjectAttributeName)
{
_subjectAttributeName=subjectAttributeName;
}
/**
* @return the _defaultSecurityDomain
*/
public String getDefaultSecurityDomain()
{
return _defaultSecurityDomain;
}
/**
* @param securityDomain the _defaultSecurityDomain to set
*/
public void setDefaultSecurityDomain(String securityDomain)
{
_defaultSecurityDomain = securityDomain;
}
/**
* @return the _acceptNonWarDirs
*/
public boolean getAcceptNonWarDirs()
{
return _acceptNonWarDirs;
}
/**
* @param nonWarDirs the _acceptNonWarDirs to set
*/
public void setAcceptNonWarDirs(boolean nonWarDirs)
{
_acceptNonWarDirs = nonWarDirs;
}
/**
* @return the _supportJSR77
*/
public boolean getSupportJSR77()
{
return _supportJSR77;
}
/**
* @param _supportjsr77 the _supportJSR77 to set
*/
public void setSupportJSR77(boolean _supportjsr77)
{
_supportJSR77 = _supportjsr77;
}
/**
* @return the _mbeanDomain
*/
public String getMBeanDomain()
{
return _mbeanDomain;
}
/**
* @param domain the _mbeanDomain to set
*/
public void setMBeanDomain(String domain)
{
_mbeanDomain = domain;
}
}
/**
* Constructor
*/
public CipangoService()
{
super();
_cipango = new SipServer();
System.setProperty("cipango.home",
System.getProperty("jboss.server.home.dir"));
Log.setLog(Log.getLogger("cipango"));
}
/**
* Listen for our registration as an mbean and remember our name.
* @see org.jboss.system.ServiceMBeanSupport#preRegister(javax.management.MBeanServer, javax.management.ObjectName)
*/
public ObjectName preRegister(MBeanServer server, ObjectName name)
throws Exception
{
super.preRegister(server, name);
name = getObjectName(server, name);
_server = server;
return name;
}
/**
* Listen for post-mbean registration and set up the jetty
* mbean infrastructure so it can generate mbeans according
* to the elements contained in the <configuration> element
* of the jboss-service.xml file.
* @see org.jboss.system.ServiceMBeanSupport#postRegister(java.lang.Boolean)
*/
public void postRegister(Boolean done)
{
super.postRegister(done);
try
{
log.debug("Setting up mbeanlistener on Cipango");
_cipango.getContainer().addEventListener(new JBossMBeanContainer(_server, MBEAN_DOMAIN));
}
catch (Throwable e)
{
log.error("could not create MBean peers", e);
}
}
/**
* @see org.jboss.system.ServiceMBeanSupport#getName()
*/
public String getName()
{
return NAME;
}
/**
* @see org.jboss.deployment.SubDeployerSupport#createService()
*/
public void createService() throws Exception {
super.createService();
if (_cipangoConfig != null)
configure();
}
/**
* Start up the jetty service. Also, as we need to be able
* to have interceptors injected into us to support jboss.ws:service=WebService,
* we need to create a proxy to ourselves and register that proxy with the
* mainDeployer.
* See <a href="http://wiki.jboss.org/wiki/Wiki.jsp?page=SubDeployerInterceptorSupport">SubDeployerInterceptorSupport</a>
* @see org.jboss.web.AbstractWebContainer#startService()
*/
public void startService() throws Exception
{
//do what AbstractWebContainer.startService() would have done
serviceController = (ServiceControllerMBean)
MBeanProxyExt.create(ServiceControllerMBean.class,
ServiceControllerMBean.OBJECT_NAME,
server);
//instead of calling mainDeployer.addDeployer(this) as SubDeployerSupport super class does,
//we register instead a proxy to oursevles so we can support dynamic addition of interceptors
_subDeployerProxy = (SubDeployerExt)MBeanProxyExt.create(SubDeployerExt.class, super.getServiceName(), super.getServer());
mainDeployer.addDeployer(_subDeployerProxy);
_cipango.start();
registerDeployers();
}
public void stopService() throws Exception
{
mainDeployer.removeDeployer(_subDeployerProxy);
unregisterDeployers();
_cipango.stop();
}
public void destroyService() throws Exception
{
super.destroyService();
_cipango.stop();
_cipango = null;
}
/**
* @jmx:managed-attribute
*/
public boolean getSupportJSR77()
{
return _supportJSR77;
}
/**
* @jmx:managed-attribute
*/
public void setSupportJSR77(boolean supportJSR77)
{
if (log.isDebugEnabled())
log.debug("set SupportJSR77 to " + supportJSR77);
_supportJSR77=supportJSR77;
}
/**
* Get the custom webdefault.xml file.
* @jmx:managed-attribute
*/
public String getWebDefaultResource()
{
return _webDefaultResource;
}
/**
* Set a custom webdefault.xml file.
* @jmx:managed-attribute
*/
public void setWebDefaultResource(String webDefaultResource)
{
if (log.isDebugEnabled())
log.debug("set WebDefaultResource to " + webDefaultResource);
_webDefaultResource=webDefaultResource;
}
/**
* @see org.jboss.web.AbstractWebContainer#getDeployer(org.jboss.deployment.DeploymentInfo)
*/
public AbstractWebDeployer getDeployer(DeploymentInfo di) throws Exception
{
CipangoDeployer deployer = new CipangoDeployer(_cipango, di);
ConfigurationData configData = new ConfigurationData();
configData.setMBeanDomain(MBEAN_DOMAIN);
configData.setAcceptNonWarDirs(getAcceptNonWarDirs());
configData.setJava2ClassLoadingCompliance(getJava2ClassLoadingCompliance());
configData.setLenientEjbLink(getLenientEjbLink());
configData.setSubjectAttributeName(getSubjectAttributeName());
configData.setSupportJSR77(getSupportJSR77());
configData.setUnpackWars(getUnpackWars());
configData.setWebDefaultResource(getWebDefaultResource());
//defaultSecurityDomain was added at a certain point, so do it
//this way so we have backwards compatibility
try
{
Method method = AbstractWebContainer.class.getDeclaredMethod("getDefaultSecurityDomain", new Class[0]);
String defaultSecurityDomain = (String) method.invoke(CipangoService.this, new Object[0]);
configData.setDefaultSecurityDomain(defaultSecurityDomain);
}
catch (Exception e)
{
// ignore - it means the currently executing version of jboss
// does not support this method
log.info("Getter/setter for DefaultSecurityDomain not available in this version of JBoss");
}
deployer.setServer(_server);
deployer.init(configData);
return deployer;
}
private void registerDeployers() {
try {
_ssarDeployer = new SsarDeployer(_cipango, this);
server.registerMBean(_ssarDeployer, SsarDeployerMBean.OBJECT_NAME);
server.invoke(MainDeployerMBean.OBJECT_NAME, "addDeployer",
new Object[] { _ssarDeployer },
new String[] { "org.jboss.deployment.SubDeployer" });
} catch (Exception e) {
Log.warn("Could not deploy SsarDeployer - ssar deployment feature will not work.\n"
+ e.getClass().getName() + ": " + e.getMessage());
}
}
private void unregisterDeployers() {
try {
server.invoke(MainDeployerMBean.OBJECT_NAME, "removeDeployer",
new Object[] { _ssarDeployer },
new String[] { "org.jboss.deployment.SubDeployer" });
server.unregisterMBean(SsarDeployerMBean.OBJECT_NAME);
} catch (Exception e) {
Log.warn("Could not undeploy SsarDeployer - ssar deployment will continue (badly).\n"
+ e.getClass().getName() + ": " + e.getMessage());
}
}
public Element getConfigurationElement()
{
return _cipangoConfig;
}
public void setConfigurationElement(Element configElement)
{
_cipangoConfig = configElement;
}
/**
* @param configElement XML fragment from jboss-service.xml
*/
private void configure()
{
// convert to an xml string to pass into Jetty's normal
// configuration mechanism
try
{
DOMSource source = new DOMSource(_cipangoConfig);
CharArrayWriter writer = new CharArrayWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, result);
String _xmlConfigString = writer.toString();
// get rid of the first line, as this will be prepended by
// the XmlConfiguration
int index = _xmlConfigString.indexOf("?>");
if (index >= 0)
{
index += 2;
while ((_xmlConfigString.charAt(index) == '\n')
|| (_xmlConfigString.charAt(index) == '\r'))
index++;
}
_xmlConfigString = _xmlConfigString.substring(index);
if (Log.isDebugEnabled())
Log.debug("Passing xml config to Cipango:\n" + _xmlConfigString);
XmlConfiguration xmlConfigurator = new XmlConfiguration(_xmlConfigString);
xmlConfigurator.configure(_cipango);
}
catch (TransformerConfigurationException tce)
{
Log.warn("Can't transform config Element -> xml:", tce);
}
catch (TransformerException te)
{
Log.warn("Can't transform config Element -> xml:", te);
}
catch (Exception e)
{
Log.warn("Unexpected exception converting configuration Element -> xml", e);
}
}
}