/** * * Copyright 2003-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.tomcat; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.net.InetAddress; import java.util.Map; import java.util.HashMap; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Connector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.geronimo.gbean.GBeanInfo; import org.apache.geronimo.gbean.GBeanInfoBuilder; import org.apache.geronimo.gbean.GBeanLifecycle; import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; import org.apache.geronimo.management.geronimo.WebManager; /** * @version $Rev$ $Date$ */ public class ConnectorGBean extends BaseGBean implements GBeanLifecycle, ObjectRetriever, TomcatWebConnector { private static final Log log = LogFactory.getLog(ConnectorGBean.class); public final static String CONNECTOR_CONTAINER_REFERENCE = "TomcatContainer"; protected final Connector connector; private final TomcatContainer container; private String name; private String connectHost; public ConnectorGBean(String name, String protocol, String host, int port, TomcatContainer container) throws Exception { super(); // TODO: make it an attribute Map initParams = new HashMap(); validateProtocol(protocol); //Default the host to listen on all address is one was not specified if (host == null){ host = "0.0.0.0"; } //Must have a port if (port == 0){ throw new IllegalArgumentException("Must declare a port."); } initParams.put("address", host); initParams.put("port", Integer.toString(port)); initializeParams(protocol, initParams); // Convert Geronimo standard values to Tomcat standard values // Only AJP requires an explicit protocol setting if(protocol != null && protocol.equals(WebManager.PROTOCOL_AJP)) { protocol = "AJP/1.3"; } else { protocol = null; } if (name == null){ throw new IllegalArgumentException("name cannot be null."); } if (container == null){ throw new IllegalArgumentException("container cannot be null."); } this.name = name; this.container = container; //Create the Connector object connector = new Connector(protocol); //Set the parameters setParameters(connector, initParams); } /** * Adds any special parameters before constructing the connector. Note: * all keys and values must be Strings. * * @param protocol Should be one of the constants from WebContainer. * @param params The map of parameters that will be used to initialize the connector. */ protected void initializeParams(String protocol, Map params) {} /** * Ensures that this implementation can handle the requested protocol. * @param protocol */ protected void validateProtocol(String protocol) { if(protocol == null) { return; } if(protocol.equals(WebManager.PROTOCOL_HTTPS)) { throw new IllegalArgumentException("Use a HttpsConnectorGBean for an HTTPS connector"); } else if(!protocol.equals(WebManager.PROTOCOL_HTTP) && !protocol.equals(WebManager.PROTOCOL_AJP)) { throw new IllegalArgumentException("Unrecognized protocol '"+protocol+"' (use the values of the PROTOCOL_* constants in WebConnector)"); } } public String getName() { return name; } public Object getInternalObject() { return connector; } public void doStart() throws LifecycleException { container.addConnector(connector); connector.start(); log.debug(name + " connector started"); } public void doStop() { try{ connector.stop(); } catch (LifecycleException e){ log.error(e); } container.removeConnector(connector); log.debug(name + " connector stopped"); } public void doFail() { log.warn(name + " connector failed"); doStop(); } public int getDefaultPort() { return getProtocol().equals(WebManager.PROTOCOL_AJP) ? -1 : getProtocol().equals(WebManager.PROTOCOL_HTTP) ? 80 : getProtocol().equals(WebManager.PROTOCOL_HTTPS) ? 443 : -1; } public String getConnectUrl() { if(connectHost == null) { String host = getHost(); if(host == null || host.equals("0.0.0.0")) { InetAddress address = null; try { address = InetAddress.getLocalHost(); } catch (UnknownHostException e) { host = "unknown-host"; } if(address != null) { host = address.getHostName(); if(host == null || host.equals("")) { host = address.getHostAddress(); } } } connectHost = host; } return getProtocol().toLowerCase()+"://"+connectHost+(getPort() == getDefaultPort() ? "" : ":"+getPort()); } /** * Gets the network protocol that this connector handles. */ public String getProtocol() { String protocol = connector.getProtocol(); if(protocol.indexOf("AJP") > -1) { return WebManager.PROTOCOL_AJP; } else if(connector.getScheme().equalsIgnoreCase("http")) { return WebManager.PROTOCOL_HTTP; } else if(connector.getScheme().equalsIgnoreCase("https")) { return WebManager.PROTOCOL_HTTPS; } throw new IllegalStateException("Unknown protocol '"+protocol+"' and scheme '"+connector.getScheme()+"'"); } /** * Gets the network port that this connector listens on. */ public int getPort() { return connector.getPort(); } /** * Sets the network port that this connector listens on. */ public void setPort(int port) { connector.setPort(port); } /** * Gets the hostname/IP that this connector listens on. */ public String getHost() { Object value = connector.getAttribute("address"); if(value == null) { return "0.0.0.0"; } else if(value instanceof InetAddress) { return ((InetAddress)value).getHostAddress(); } else return value.toString(); } /** * Sets the hostname/IP that this connector listens on. This is typically * most useful for machines with multiple network cards, but can be used * to limit a connector to only listen for connections from the local * machine (127.0.0.1). To listen on all available network interfaces, * specify an address of 0.0.0.0. */ public void setHost(String host) throws UnknownHostException { connector.setAttribute("address", host); } /** * Every connector must specify a property of type InetSocketAddress * because we use that to identify the network services to print a list * during startup. However, this can be read-only since the host and port * are set separately using setHost and setPort. */ public InetSocketAddress getListenAddress() { return new InetSocketAddress(getHost(), getPort()); } /** * Gets the size of the buffer used to handle network data for this * connector. */ public int getBufferSizeBytes() { Object value = connector.getAttribute("bufferSize"); return value == null ? 2048 : Integer.parseInt(value.toString()); } /** * Gets the size of the buffer used to handle network data for this * connector. */ public void setBufferSizeBytes(int bytes) { connector.setAttribute("bufferSize", new Integer(bytes)); } /** * Gets the maximum number of threads used to service connections from * this connector. */ public int getMaxThreads() { Object value = connector.getAttribute("maxThreads"); return value == null ? 200 : Integer.parseInt(value.toString()); } /** * Sets the maximum number of threads used to service connections from * this connector. */ public void setMaxThreads(int threads) { connector.setAttribute("maxThreads", new Integer(threads)); } /** * Gets the maximum number of connections that may be queued while all * threads are busy. Any requests received while the queue is full will * be rejected. */ public int getAcceptQueueSize() { Object value = connector.getAttribute("acceptCount"); return value == null ? 10 : Integer.parseInt(value.toString()); } /** * Sets the maximum number of connections that may be queued while all * threads are busy. Any requests received while the queue is full will * be rejected. */ public void setAcceptQueueSize(int size) { connector.setAttribute("acceptCount", new Integer(size)); } /** * Gets the amount of time the socket used by this connector will linger * after being closed. -1 indicates that socket linger is disabled. */ public int getLingerMillis() { Object value = connector.getAttribute("connectionLinger"); return value == null ? -1 : Integer.parseInt(value.toString()); } /** * Sets the amount of time the socket used by this connector will linger * after being closed. Use -1 to disable socket linger. */ public void setLingerMillis(int millis) { connector.setAttribute("connectionLinger", new Integer(millis)); } /** * Gets whether the TCP_NODELAY flag is set for the sockets used by this * connector. This usually enhances performance, so it should typically * be set. */ public boolean isTcpNoDelay() { Object value = connector.getAttribute("tcpNoDelay"); return value == null ? true : new Boolean(value.toString()).booleanValue(); } /** * Sets whether the TCP_NODELAY flag is set for the sockets used by this * connector. This usually enhances performance, so it should typically * be set. */ public void setTcpNoDelay(boolean enable) { connector.setAttribute("tcpNoDelay", new Boolean(enable)); } /** * Gets the network port to which traffic will be redirected if this * connector handles insecure traffic and the request requires a secure * connection. Needless to say, this should point to another connector * configured for SSL. */ public int getRedirectPort() { Object value = connector.getAttribute("redirectPort"); return value == null ? 0 : Integer.parseInt(value.toString()); } /** * Gets the network port to which traffic will be redirected if this * connector handles insecure traffic and the request requires a secure * connection. Needless to say, this should point to another connector * configured for SSL. If no SSL connector is available, any port can * be used as they all fail equally well. :) */ public void setRedirectPort(int port) { connector.setAttribute("redirectPort", new Integer(port)); } public int getMinSpareThreads() { Object value = connector.getAttribute("minSpareThreads"); return value == null ? 4 : Integer.parseInt(value.toString()); } public void setMinSpareThreads(int threads) { connector.setAttribute("minSpareThreads", new Integer(threads)); } public int getMaxSpareThreads() { Object value = connector.getAttribute("maxSpareThreads"); return value == null ? 50 : Integer.parseInt(value.toString()); } public void setMaxSpareThreads(int threads) { connector.setAttribute("maxSpareThreads", new Integer(threads)); } public int getMaxHttpHeaderSizeBytes() { Object value = connector.getAttribute("maxHttpHeaderSize"); return value == null ? 4096 : Integer.parseInt(value.toString()); } public void setMaxHttpHeaderSizeBytes(int bytes) { connector.setAttribute("maxHttpHeaderSize", new Integer(bytes)); } public boolean isHostLookupEnabled() { Object value = connector.getAttribute("enableLookups"); return value == null ? true : new Boolean(value.toString()).booleanValue(); } public void setHostLookupEnabled(boolean enabled) { connector.setAttribute("enableLookups", new Boolean(enabled)); } public int getConnectionTimeoutMillis() { Object value = connector.getAttribute("connectionTimeout"); return value == null ? 60000 : Integer.parseInt(value.toString()); } public void setConnectionTimeoutMillis(int millis) { connector.setAttribute("connectionTimeout", new Integer(millis)); } public boolean isUploadTimeoutEnabled() { Object value = connector.getAttribute("disableUploadTimeout"); return value == null ? true : !new Boolean(value.toString()).booleanValue(); } public void setUploadTimeoutEnabled(boolean enabled) { connector.setAttribute("disableUploadTimeout", new Boolean(!enabled)); } public static final GBeanInfo GBEAN_INFO; static { GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Tomcat Connector", ConnectorGBean.class); infoFactory.addAttribute("name", String.class, true); infoFactory.addAttribute("protocol", String.class, true); infoFactory.addReference(CONNECTOR_CONTAINER_REFERENCE, TomcatContainer.class, NameFactory.GERONIMO_SERVICE); infoFactory.addOperation("getInternalObject"); infoFactory.addInterface(TomcatWebConnector.class, new String[]{"host","port","bufferSizeBytes","maxThreads","acceptQueueSize","lingerMillis","tcpNoDelay","redirectPort","minSpareThreads","maxSpareThreads","maxHttpHeaderSizeBytes","hostLookupEnabled","connectionTimeoutMillis","uploadTimeoutEnabled","connectUrl",}, new String[]{"host","port","redirectPort"}); infoFactory.setConstructor(new String[] { "name", "protocol", "host", "port", "TomcatContainer"}); GBEAN_INFO = infoFactory.getBeanInfo(); } public static GBeanInfo getGBeanInfo() { return GBEAN_INFO; } }