/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* 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,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006, JBoss Inc.
*/
package org.jboss.soa.esb.listeners.gateway;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.apache.catalina.Container;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardService;
import org.apache.tomcat.util.IntrospectionUtils;
import org.apache.tomcat.util.modeler.Registry;
import org.jboss.mx.util.MBeanServerLocator;
import org.jboss.soa.esb.helpers.KeyValuePair;
import org.jboss.web.tomcat.security.JBossSecurityMgrRealm;
/**
* This class creates and starts the jboss esb tomcat engine. The tomcat Connector
* , Host , StandardContext are also can be created with this class.
* @author <a href="mailto:ema@redhat.com">Jim Ma</a>
* @deprecated
*/
public class HttpServerDelegate {
public static final String defaultVHost = "localhost";
/**Record the count that the same host name is referenced by other Tomcat listener instance */
public static final Map<String, Integer> hostReference= new java.util.HashMap<String, Integer>();
/**Record the count that the same connector/port is referenced by other Tomcat listener instance */
public static final Map<String, Integer> connectorReference= new java.util.HashMap<String, Integer>();
/**JMX domain name for http listener*/
public static final String DOMAIN_NAME = "jboss.esb.tomcat";
/**MBean sever*/
private static MBeanServer mbeanServer = null;
/**TomcatServer instance*/
private static HttpServerDelegate instance = null;
private HttpServerDelegate() {
}
public static synchronized HttpServerDelegate getInstance() {
if (instance == null) {
mbeanServer = MBeanServerLocator.locateJBoss();
instance = new HttpServerDelegate();
instance.createEngine();
}
return instance;
}
/**
* Create a tomcat engine and also register it in JMX server
* If there is exception , it will throw RuntimeException
*/
@SuppressWarnings("unchecked")
private void createEngine() {
try {
Set services = mbeanServer.queryMBeans(new ObjectName(DOMAIN_NAME
+ ":type=Service"), null);
if (services.size() == 0) {
StandardService service = new StandardService();
service.setName("jboss.esb.catalina");
Registry.getRegistry().registerComponent(service,
new ObjectName(DOMAIN_NAME + ":type=Service"), null);
}
Set engines = mbeanServer.queryMBeans(new ObjectName(DOMAIN_NAME
+ ":type=Engine"), null);
if (engines.size() == 0) {
StandardEngine engine = new StandardEngine();
//Add JBossSecurityMgrRealm
JBossSecurityMgrRealm realm = new JBossSecurityMgrRealm();
realm.setCertificatePrincipal("org.jboss.security.auth.certs.SubjectDNMapping");
realm.setAllRolesMode("authOnly");
engine.setRealm(realm);
Registry.getRegistry().registerComponent(realm,
new ObjectName(DOMAIN_NAME + ":type=Realm"), null);
engine.setDefaultHost(defaultVHost);
engine.setDomain(DOMAIN_NAME);
engine.setName(DOMAIN_NAME + ".engine");
mbeanServer.setAttribute(new ObjectName(DOMAIN_NAME
+ ":type=Service"), new Attribute("container", engine));
Registry.getRegistry().registerComponent(engine,
new ObjectName(DOMAIN_NAME + ":type=Engine"), null);
}
mbeanServer.invoke(new ObjectName(DOMAIN_NAME + ":type=Service"),
"start", new Object[] {}, new String[] {});
} catch (Exception e) {
throw new RuntimeException("Failed to create tomcat engine in ESB", e);
}
}
/**
* Add a tomcat StandardHost to tomcat engine
* @param host tomcat vhost name
* @throws Exception If there is error occured
*/
@SuppressWarnings("unchecked")
public void createHost(String host) throws Exception {
ObjectName hostName = new ObjectName(DOMAIN_NAME + ":host=" + host + ",type=Host");
ObjectName stardardEngineName = new ObjectName(DOMAIN_NAME + ":type=Engine");
//Check if it needs to create host
Set hosts = mbeanServer.queryNames(hostName, null);
if (hosts.size() == 0) {
StandardHost newHost = new StandardHost();
newHost.setName(host);
mbeanServer.invoke(stardardEngineName, "addChild", new Object[] { newHost }, new String[] { Container.class .getName() });
synchronized (hostReference) {
hostReference.put(host, 1);
}
} else {
updateReference(hostReference, host, 1);
}
}
/**
* Add a tomcat Connector to tomcat Enginer/Service
* @param address the connector address
* @param port the connector port
* @param properties The properties to configure this connector
* @throws Exception when error is occured
*/
@SuppressWarnings("unchecked")
public void createConnector(String address, String port, List<KeyValuePair> properties) throws Exception {
ObjectName standardServiceName = new ObjectName(DOMAIN_NAME + ":type=Service");
Set connectors = queryObjects(DOMAIN_NAME + ":address=" + URLEncoder.encode("/" + address) +",port="
+ port + ",type=Connector,*");
if (connectors.size() == 0) {
Connector connector = null;
connector = new Connector("org.apache.coyote.http11.Http11Protocol");
connector.setPort(Integer.parseInt(port));
for (KeyValuePair property : properties) {
boolean effected = IntrospectionUtils.setProperty(connector, property.getKey(), property.getValue());
if (!effected) {
connector.setProperty(property.getKey(), property.getValue());
}
}
connector.setAttribute("address", address);
mbeanServer.invoke(standardServiceName, "addConnector",
new Object[] { connector }, new String[] { Connector.class
.getName() });
synchronized (connectorReference) {
connectorReference.put(port, 1);
}
} else {
updateReference(connectorReference, port, 1);
}
}
/**
* Add a StandardContext to a specific host
* @param host tomcat vhost name
* @param ctx new created StandardContext
* @throws Exception when error occurs
*/
public void addContext(String host, StandardContext ctx) throws Exception {
ObjectName hostName = new ObjectName(DOMAIN_NAME + ":host=" + host + ",type=Host");
addContext(hostName, ctx);
}
public void addContext(ObjectName hostName, StandardContext ctx) throws Exception {
mbeanServer.invoke(hostName, "addChild", new Object[] { ctx }, new String[] { Container.class.getName() });
}
/**
* Destroy the created context. This method will also check if this context's parent StandardHost
* and Connector can be destroyed also. There are reference counters for Connector and Host
* @param host tomcat vhost name
* @param address the Connector address
* @param port port number
* @param httpContext the new created httpContext name
* @throws Exception if failed to destroy
*/
@SuppressWarnings("unchecked")
public void destroyContext(String host, String address, String port, String httpContext)
throws Exception {
ObjectName contextName = new ObjectName(DOMAIN_NAME
+ ":j2eeType=WebModule,name=//" + host + httpContext
+ ",*");
Set engines = mbeanServer.queryNames(contextName, null);
if (engines.isEmpty()) {
throw new InstanceNotFoundException("HttpContext:" + httpContext + "not found");
}
contextName = (ObjectName) engines.iterator().next();
mbeanServer.invoke(contextName, "destroy", new Object[] {},
new String[] {});
// Decrese the host and connector reference
updateReference(hostReference, host, -1);
updateReference(connectorReference, port, -1);
Object obj = hostReference.get(host);
if (obj != null && (Integer) obj == 0) {
ObjectName standardHostName = new ObjectName(DOMAIN_NAME + ":host="
+ host + ",type=Host");
mbeanServer.invoke(standardHostName, "destroy", new Object[] {}, new String[] {});
}
obj = connectorReference.get(port);
if (obj != null && (Integer) obj == 0) {
Set connectors = queryObjects(DOMAIN_NAME + ":address=" + URLEncoder.encode("/" + address) +",port="
+ port + ",type=Connector,*");
if (connectors.size() > 0) {
ObjectName connector = (ObjectName)connectors.iterator().next();
mbeanServer.invoke(connector, "destroy", new Object[] {},new String[] {});
}
}
}
public void destroyContext(ObjectName contextName) throws Exception {
mbeanServer.invoke(contextName, "destroy", new Object[] {},
new String[] {});
}
/**
* Query objects
* @param objectName
* @return Set contains ObjectName
* @throws Exception error occurs
*/
@SuppressWarnings("unchecked")
public Set queryObjects(String objectName) throws Exception {
ObjectName name = new ObjectName(objectName);
Set objects = mbeanServer.queryNames(name, null);
return objects;
}
/**Update the reference value
* @param refrenceMap The reference map
* @param key Update key
* @param increment Update value
*/
@SuppressWarnings("unchecked")
public void updateReference(Map refrenceMap, String key , int increment) {
synchronized (refrenceMap) {
if (refrenceMap.get(key) != null) {
int count = (Integer) refrenceMap.get(key);
if (count == 0) {
return;
}
refrenceMap.put(key, count + increment);
}
}
}
}