001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.tomcat;
019    
020    import java.net.InetSocketAddress;
021    import java.net.UnknownHostException;
022    import java.net.InetAddress;
023    import java.util.Map;
024    import java.util.HashMap;
025    
026    import org.apache.catalina.LifecycleException;
027    import org.apache.catalina.connector.Connector;
028    import org.apache.commons.logging.Log;
029    import org.apache.commons.logging.LogFactory;
030    import org.apache.geronimo.gbean.GBeanInfo;
031    import org.apache.geronimo.gbean.GBeanInfoBuilder;
032    import org.apache.geronimo.gbean.GBeanLifecycle;
033    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
034    import org.apache.geronimo.management.geronimo.WebManager;
035    
036    /**
037     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
038     */
039    public class ConnectorGBean extends BaseGBean implements GBeanLifecycle, ObjectRetriever, TomcatWebConnector {
040        private static final Log log = LogFactory.getLog(ConnectorGBean.class);
041        public final static String CONNECTOR_CONTAINER_REFERENCE = "TomcatContainer";
042    
043        protected final Connector connector;
044        private final TomcatContainer container;
045        private String name;
046        private String connectHost;
047    
048        public ConnectorGBean(String name, String protocol, String host, int port, TomcatContainer container) throws Exception {
049            super(); // TODO: make it an attribute
050    
051            Map initParams = new HashMap();
052    
053            validateProtocol(protocol);
054            
055            //Default the host to listen on all address is one was not specified
056            if (host == null){
057                host = "0.0.0.0";
058            }
059            
060            //Must have a port
061            if (port == 0){
062                throw new IllegalArgumentException("Must declare a port.");
063            }
064    
065            initParams.put("address", host);
066            initParams.put("port", Integer.toString(port));
067            initializeParams(protocol, initParams);
068    
069            // Convert Geronimo standard values to Tomcat standard values
070            // Only AJP requires an explicit protocol setting
071            if(protocol != null && protocol.equals(WebManager.PROTOCOL_AJP)) {
072                protocol = "AJP/1.3";
073            } else {
074                protocol = null;
075            }
076    
077            if (name == null){
078                throw new IllegalArgumentException("name cannot be null.");
079            }
080    
081            if (container == null){
082                throw new IllegalArgumentException("container cannot be null.");
083            }
084     
085            this.name = name;
086            this.container = container;
087    
088            //Create the Connector object
089            connector = new Connector(protocol);
090    
091    
092            //Set the parameters
093            setParameters(connector, initParams);
094            
095        }
096    
097        /**
098         * Adds any special parameters before constructing the connector.  Note:
099         * all keys and values must be Strings.
100         *
101         * @param protocol Should be one of the constants from WebContainer.
102         * @param params   The map of parameters that will be used to initialize the connector.
103         */
104        protected void initializeParams(String protocol, Map params) {}
105    
106        /**
107         * Ensures that this implementation can handle the requested protocol.
108         * @param protocol
109         */
110        protected void validateProtocol(String protocol) {
111            if(protocol == null) {
112                return;
113            }
114            if(protocol.equals(WebManager.PROTOCOL_HTTPS)) {
115                throw new IllegalArgumentException("Use a HttpsConnectorGBean for an HTTPS connector");
116            } else if(!protocol.equals(WebManager.PROTOCOL_HTTP) && !protocol.equals(WebManager.PROTOCOL_AJP)) {
117                throw new IllegalArgumentException("Unrecognized protocol '"+protocol+"' (use the values of the PROTOCOL_* constants in WebConnector)");
118            }
119        }
120    
121        public String getName() {
122            return name;
123        }
124    
125        public Object getInternalObject() {
126            return connector;
127        }
128    
129        public void doStart() throws LifecycleException {
130            container.addConnector(connector);
131            connector.start();
132            log.debug(name + " connector started");
133       }
134    
135        public void doStop() {
136            try{
137                connector.stop();
138            } catch (LifecycleException e){
139                log.error(e);
140            }
141            container.removeConnector(connector);
142            log.debug(name + " connector stopped");
143        }
144    
145        public void doFail() {
146            log.warn(name + " connector failed");
147            doStop();
148        }
149    
150        public int getDefaultPort() {
151            return getProtocol().equals(WebManager.PROTOCOL_AJP) ? -1 :
152                    getProtocol().equals(WebManager.PROTOCOL_HTTP) ? 80 :
153                    getProtocol().equals(WebManager.PROTOCOL_HTTPS) ? 443 : -1;
154        }
155    
156        public String getConnectUrl() {
157            if(connectHost == null) {
158                String host = getHost();
159                if(host == null || host.equals("0.0.0.0")) {
160                    InetAddress address = null;
161                    try {
162                        address = InetAddress.getLocalHost();
163                    } catch (UnknownHostException e) {
164                        host = "unknown-host";
165                    }
166                    if(address != null) {
167                        host = address.getCanonicalHostName();
168                        if(host == null || host.equals("")) {
169                            host = address.getHostAddress();
170                        }
171                    }
172                }
173                connectHost = host;
174            }
175            return getProtocol().toLowerCase()+"://"+connectHost+(getPort() == getDefaultPort() ? "" : ":"+getPort());
176        }
177    
178        public boolean isEmptySessionPath(){
179            return connector.getEmptySessionPath();
180        }
181        
182        public void setEmptySessionPath(boolean emptySessionPath){
183           connector.setEmptySessionPath(emptySessionPath); 
184        }
185    
186        /**
187         * Gets the network protocol that this connector handles.
188         */
189        public String getProtocol() {
190            String protocol = connector.getProtocol();
191            if(protocol.indexOf("AJP") > -1) {
192                return WebManager.PROTOCOL_AJP;
193            } else if(connector.getScheme().equalsIgnoreCase("http")) {
194                return WebManager.PROTOCOL_HTTP;
195            } else if(connector.getScheme().equalsIgnoreCase("https")) {
196                return WebManager.PROTOCOL_HTTPS;
197            }
198            throw new IllegalStateException("Unknown protocol '"+protocol+"' and scheme '"+connector.getScheme()+"'");
199        }
200    
201        /**
202         * Gets the network port that this connector listens on.
203         */
204        public int getPort() {
205            return connector.getPort();
206        }
207    
208        /**
209         * Sets the network port that this connector listens on.
210         */
211        public void setPort(int port) {
212            connector.setPort(port);
213        }
214    
215        /**
216         * Gets the hostname/IP that this connector listens on.
217         */
218        public String getHost() {
219            Object value = connector.getAttribute("address");
220            if(value == null) {
221                return "0.0.0.0";
222            } else if(value instanceof InetAddress) {
223                return ((InetAddress)value).getHostAddress();
224            } else return value.toString();
225        }
226    
227        /**
228         * Sets the hostname/IP that this connector listens on.  This is typically
229         * most useful for machines with multiple network cards, but can be used
230         * to limit a connector to only listen for connections from the local
231         * machine (127.0.0.1).  To listen on all available network interfaces,
232         * specify an address of 0.0.0.0.
233         */
234        public void setHost(String host) throws UnknownHostException {
235            connector.setAttribute("address", host);
236        }
237    
238        /**
239         * Every connector must specify a property of type InetSocketAddress
240         * because we use that to identify the network services to print a list
241         * during startup.  However, this can be read-only since the host and port
242         * are set separately using setHost and setPort.
243         */
244        public InetSocketAddress getListenAddress() {
245            return new InetSocketAddress(getHost(), getPort());
246        }
247    
248        /**
249         * Gets the size of the buffer used to handle network data for this
250         * connector.
251         */
252        public int getBufferSizeBytes() {
253            Object value = connector.getAttribute("bufferSize");
254            return value == null ? 2048 : Integer.parseInt(value.toString());
255        }
256    
257        /**
258         * Gets the size of the buffer used to handle network data for this
259         * connector.
260         */
261        public void setBufferSizeBytes(int bytes) {
262            connector.setAttribute("bufferSize", new Integer(bytes));
263        }
264    
265        /**
266         * Gets the maximum number of threads used to service connections from
267         * this connector.
268         */
269        public int getMaxThreads() {
270            Object value = connector.getAttribute("maxThreads");
271            return value == null ? 200 : Integer.parseInt(value.toString());
272        }
273    
274        /**
275         * Sets the maximum number of threads used to service connections from
276         * this connector.
277         */
278        public void setMaxThreads(int threads) {
279            connector.setAttribute("maxThreads", new Integer(threads));
280        }
281    
282        /**
283         * Gets the maximum number of connections that may be queued while all
284         * threads are busy.  Any requests received while the queue is full will
285         * be rejected.
286         */
287        public int getAcceptQueueSize() {
288            Object value = connector.getAttribute("acceptCount");
289            return value == null ? 10 : Integer.parseInt(value.toString());
290        }
291    
292        /**
293         * Sets the maximum number of connections that may be queued while all
294         * threads are busy.  Any requests received while the queue is full will
295         * be rejected.
296         */
297        public void setAcceptQueueSize(int size) {
298            connector.setAttribute("acceptCount", new Integer(size));
299        }
300    
301        /**
302         * Gets the amount of time the socket used by this connector will linger
303         * after being closed.  -1 indicates that socket linger is disabled.
304         */
305        public int getLingerMillis() {
306            Object value = connector.getAttribute("connectionLinger");
307            return value == null ? -1 : Integer.parseInt(value.toString());
308        }
309    
310        /**
311         * Sets the amount of time the socket used by this connector will linger
312         * after being closed.  Use -1 to disable socket linger.
313         */
314        public void setLingerMillis(int millis) {
315            connector.setAttribute("connectionLinger", new Integer(millis));
316        }
317    
318        /**
319         * Gets whether the TCP_NODELAY flag is set for the sockets used by this
320         * connector.  This usually enhances performance, so it should typically
321         * be set.
322         */
323        public boolean isTcpNoDelay() {
324            Object value = connector.getAttribute("tcpNoDelay");
325            return value == null ? true : new Boolean(value.toString()).booleanValue();
326        }
327    
328        /**
329         * Sets whether the TCP_NODELAY flag is set for the sockets used by this
330         * connector.  This usually enhances performance, so it should typically
331         * be set.
332         */
333        public void setTcpNoDelay(boolean enable) {
334            connector.setAttribute("tcpNoDelay", new Boolean(enable));
335        }
336    
337        /**
338         * Gets the network port to which traffic will be redirected if this
339         * connector handles insecure traffic and the request requires a secure
340         * connection.  Needless to say, this should point to another connector
341         * configured for SSL.
342         */
343        public int getRedirectPort() {
344            return connector.getRedirectPort();
345        }
346    
347        /**
348         * Gets the network port to which traffic will be redirected if this
349         * connector handles insecure traffic and the request requires a secure
350         * connection.  Needless to say, this should point to another connector
351         * configured for SSL.  If no SSL connector is available, any port can
352         * be used as they all fail equally well.  :)
353         */
354        public void setRedirectPort(int port) {
355            connector.setRedirectPort(port);
356        }
357    
358        public int getMinSpareThreads() {
359            Object value = connector.getAttribute("minSpareThreads");
360            return value == null ? 4 : Integer.parseInt(value.toString());
361        }
362    
363        public void setMinSpareThreads(int threads) {
364            connector.setAttribute("minSpareThreads", new Integer(threads));
365        }
366    
367        public int getMaxSpareThreads() {
368            Object value = connector.getAttribute("maxSpareThreads");
369            return value == null ? 50 : Integer.parseInt(value.toString());
370        }
371    
372        public void setMaxSpareThreads(int threads) {
373            connector.setAttribute("maxSpareThreads", new Integer(threads));
374        }
375    
376        public int getMaxHttpHeaderSizeBytes() {
377            Object value = connector.getAttribute("maxHttpHeaderSize");
378            return value == null ? 4096 : Integer.parseInt(value.toString());
379        }
380    
381        public void setMaxHttpHeaderSizeBytes(int bytes) {
382            connector.setAttribute("maxHttpHeaderSize", new Integer(bytes));
383        }
384    
385        public boolean isHostLookupEnabled() {
386            return connector.getEnableLookups();
387        }
388    
389        public void setHostLookupEnabled(boolean enabled) {
390            connector.setEnableLookups(enabled);
391        }
392    
393        public int getConnectionTimeoutMillis() {
394            Object value = connector.getAttribute("connectionTimeout");
395            return value == null ? 60000 : Integer.parseInt(value.toString());
396        }
397    
398        public void setConnectionTimeoutMillis(int millis) {
399            connector.setAttribute("connectionTimeout", new Integer(millis));
400        }
401    
402        public boolean isUploadTimeoutEnabled() {
403            Object value = connector.getAttribute("disableUploadTimeout");
404            return value == null ? true : !new Boolean(value.toString()).booleanValue();
405        }
406    
407        public void setUploadTimeoutEnabled(boolean enabled) {
408            connector.setAttribute("disableUploadTimeout", new Boolean(!enabled));
409        }
410    
411        public int getMaxPostSize() {
412            int value = connector.getMaxPostSize();
413            return value == 0 ? 2097152 : value;
414        }
415    
416        public void setMaxPostSize(int bytes) {
417            connector.setMaxPostSize(bytes);
418        }
419    
420        public int getMaxSavePostSize() {
421            int value = connector.getMaxSavePostSize();
422            return value == 0 ? 4096 : value;
423        }
424    
425        public void setMaxSavePostSize(int kbytes) {
426            connector.setMaxSavePostSize(kbytes);
427        }
428    
429        public int getMaxKeepAliveRequests() {
430            Object value = connector.getAttribute("maxKeepAliveRequests");
431            return value == null ? 100 : Integer.parseInt(value.toString());
432        }
433    
434        public void setMaxKeepAliveRequests(int maxKeepAliveRequests) {
435            connector.setAttribute("maxKeepAliveRequests", new Integer(maxKeepAliveRequests));
436        }
437    
438        public int getSocketBuffer() {
439            Object value = connector.getAttribute("socketBuffer");
440            return value == null ? 9000 : Integer.parseInt(value.toString());
441        }
442    
443        public void setSocketBuffer(int kbytes) {
444            connector.setAttribute("socketBuffer", new Integer(kbytes));
445        }
446    
447        public boolean getUseBodyEncodingForURI() {
448            return connector.getUseBodyEncodingForURI();
449        }
450    
451        public void setUseBodyEncodingForURI(boolean enabled) {
452            connector.setUseBodyEncodingForURI(enabled);
453        }
454    
455        public void setAllowTrace(boolean allow) {
456            connector.setAllowTrace(allow);
457        }
458    
459        public boolean getAllowTrace() {
460            return connector.getAllowTrace();
461        }
462    
463        public void setProxyName(String proxyName) {
464            connector.setProxyName(proxyName);
465        }
466    
467        public String getProxyName() {
468            return connector.getProxyName();
469        }
470    
471        public void setProxyPort(int port) {
472            connector.setProxyPort(port);
473        }
474    
475        public int getProxyPort() {
476            return connector.getProxyPort();
477        }
478    
479        public void setScheme(String scheme) {
480            connector.setScheme(scheme);
481        }
482    
483        public String getScheme() {
484            return connector.getScheme();
485        }
486    
487        public void setUriEncoding(String encoding) {
488            connector.setURIEncoding(encoding);
489        }
490    
491        public String getUriEncoding() {
492            return connector.getURIEncoding();
493        }
494    
495        public void setUseIPVHosts(boolean useIPVHosts) {
496            connector.setUseIPVHosts(useIPVHosts);
497        }
498    
499        public boolean getUseIPVHosts() {
500            return connector.getUseIPVHosts();
501        }
502    
503        public void setXpoweredBy(boolean xpoweredBy) {
504            connector.setXpoweredBy(xpoweredBy);
505        }
506    
507        public boolean getXpoweredBy() {
508            return connector.getXpoweredBy();
509        }
510    
511        public void setCompressableMimeType(String compressableMimeType) {
512            connector.setAttribute("compressableMimeType", compressableMimeType);
513        }
514    
515        public String getCompressableMimeType() {
516            return (String) connector.getAttribute("compressableMimeType");
517        }
518    
519        public void setCompression(String compression) {
520            connector.setAttribute("compression", compression);
521        }
522    
523        public String getCompression() {
524            return (String) connector.getAttribute("compression");
525        }
526    
527        public void setNoCompressionUserAgents(String noCompressionUserAgents) {
528            connector.setAttribute("noCompressionUserAgents", noCompressionUserAgents);
529        }
530    
531        public String getNoCompressionUserAgents() {
532            return (String) connector.getAttribute("noCompressionUserAgents");
533        }
534    
535        public void setRestrictedUserAgents(String restrictedUserAgents) {
536            connector.setAttribute("restrictedUserAgents", restrictedUserAgents);
537        }
538    
539        public String getRestrictedUserAgents() {
540            return (String) connector.getAttribute("restrictedUserAgents");
541        }
542    
543        public void setThreadPriority(int threadPriority) {
544            connector.setAttribute("threadPriority", new Integer(threadPriority));
545        }
546    
547        public int getThreadPriority() {
548            Object value = connector.getAttribute("threadPriority");
549            return value == null ? 5 :Integer.parseInt(value.toString());
550        }
551    
552        public void setServer(String server) {
553            connector.setAttribute("server", server);
554        }
555    
556        public String getServer() {
557            return (String) connector.getAttribute("server");
558        }
559    
560        public void setStrategy(String strategy) {
561            connector.setAttribute("strategy", strategy);
562        }
563    
564        public String getStrategy() {
565            return (String) connector.getAttribute("strategy");
566        }
567    
568        public static final GBeanInfo GBEAN_INFO;
569    
570        static {
571            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Tomcat Connector", ConnectorGBean.class);
572            infoFactory.addAttribute("name", String.class, true);
573            infoFactory.addAttribute("protocol", String.class, true);
574            infoFactory.addReference(CONNECTOR_CONTAINER_REFERENCE, TomcatContainer.class, NameFactory.GERONIMO_SERVICE);
575            infoFactory.addOperation("getInternalObject");
576            infoFactory.addInterface(TomcatWebConnector.class,
577                    new String[]{
578                            "host",
579                            "port",
580                            "bufferSizeBytes",
581                            "maxThreads",
582                            "acceptQueueSize",
583                            "lingerMillis",
584                            "tcpNoDelay",
585                            "redirectPort",
586                            "minSpareThreads",
587                            "maxSpareThreads",
588                            "maxHttpHeaderSizeBytes",
589                            "hostLookupEnabled",
590                            "connectionTimeoutMillis",
591                            "uploadTimeoutEnabled",
592                            "connectUrl",
593                            "maxPostSize",
594                            "maxSavePostSize",
595                            "emptySessionPath",
596                            "maxKeepAliveRequests",
597                            "socketBuffer",
598                            "useBodyEncodingForURI",
599                            "allowTrace",
600                            "proxyName",
601                            "proxyPort",
602                            "scheme",
603                            "secure",
604                            "uriEncoding",
605                            "useIPVHosts",
606                            "xpoweredBy",
607                            "compressableMimeType",
608                            "compression",
609                            "noCompressionUserAgents",
610                            "restrictedUserAgents",
611                            "threadPriority",
612                            "server",
613                            "strategy"
614                    },
615    
616                    new String[]{
617                            "host",
618                            "port",
619                            "redirectPort",
620                            "maxThreads"});
621            infoFactory.setConstructor(new String[] { "name", "protocol", "host", "port", "TomcatContainer"});
622            GBEAN_INFO = infoFactory.getBeanInfo();
623        }
624    
625        public static GBeanInfo getGBeanInfo() {
626            return GBEAN_INFO;
627        }
628    
629    }