001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.jetty6.connector;
019    
020    import java.net.InetAddress;
021    import java.net.InetSocketAddress;
022    import java.net.UnknownHostException;
023    
024    import javax.management.j2ee.statistics.Stats;
025    
026    import org.apache.geronimo.gbean.GBeanInfo;
027    import org.apache.geronimo.gbean.GBeanInfoBuilder;
028    import org.apache.geronimo.gbean.GBeanLifecycle;
029    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
030    import org.apache.geronimo.jetty6.JettyContainer;
031    import org.apache.geronimo.jetty6.JettyWebConnector;
032    import org.apache.geronimo.management.LazyStatisticsProvider;
033    import org.apache.geronimo.management.geronimo.stats.JettyWebConnectorStatsImpl;
034    import org.apache.geronimo.system.threads.ThreadPool;
035    import org.mortbay.jetty.AbstractConnector;
036    
037    /**
038     * Base class for GBeans for Jetty network connectors (HTTP, HTTPS, AJP, etc.).
039     *
040     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
041     */
042    public abstract class JettyConnector implements GBeanLifecycle, JettyWebConnector, LazyStatisticsProvider {
043        public final static String CONNECTOR_CONTAINER_REFERENCE = "JettyContainer";
044        private final JettyContainer container;
045        protected final AbstractConnector listener;
046        private JettyWebConnectorStatsImpl stats;           // data structure for jsr77 stats
047        private String connectHost;
048    
049        /**
050         * Only used to allow declaration as a reference.
051         */
052        public JettyConnector() {
053            container = null;
054            listener = null;
055        }
056    
057        public JettyConnector(JettyContainer container, ThreadPool threadPool) {
058            this.container = container;
059            this.listener = null;
060        }
061    
062        public JettyConnector(JettyContainer container, AbstractConnector listener, ThreadPool threadPool, String name) {
063            this.container = container;
064            this.listener = listener;
065            if (threadPool != null) {
066                JettyThreadPool jettyThreadPool = new JettyThreadPool(threadPool, name);
067                listener.setThreadPool(jettyThreadPool);
068            }
069            stats = new JettyWebConnectorStatsImpl();
070        }
071    
072        //TODO: support the jetty6 specific methods
073        public String getHost() {
074            return listener.getHost();
075        }
076    
077        public void setHost(String host) throws UnknownHostException {
078            // underlying impl treats null as 0.0.0.0
079            listener.setHost(host);
080        }
081    
082        public int getPort() {
083            return listener.getPort();
084        }
085    
086        public void setPort(int port) {
087            listener.setPort(port);
088        }
089        
090        public int getHeaderBufferSizeBytes() {
091            return listener.getHeaderBufferSize();
092        }
093        public void setHeaderBufferSizeBytes(int size) {
094            listener.setHeaderBufferSize(size);
095        }
096    
097        public abstract int getDefaultPort();
098    
099        public String getDefaultScheme() {
100            return null;
101        }
102    
103        public String getConnectUrl() {
104            if (connectHost == null) {
105                String host = getHost();
106                if (host == null || host.equals("0.0.0.0")) {
107                    InetAddress address = null;
108                    try {
109                        address = InetAddress.getLocalHost();
110                    } catch (UnknownHostException e) {
111                        host = "unknown-host";
112                    }
113                    if (address != null) {
114                        host = address.getHostName();
115                        if (host == null || host.equals("")) {
116                            host = address.getHostAddress();
117                        }
118                    }
119                }
120                connectHost = host;
121            }
122            return getProtocol().toLowerCase() + "://" + connectHost + (getPort() == getDefaultPort() ? "" : ":" + getPort());
123        }
124    
125        public int getMaxIdleTimeMs() {
126            return listener.getMaxIdleTime();
127        }
128    
129        public void setMaxIdleTimeMs(int idleTime) {
130            listener.setMaxIdleTime(idleTime);
131        }
132    
133        public int getBufferSizeBytes() {
134            //TODO return the request buffer size, what about the response and header buffer size?
135            return listener.getRequestBufferSize();
136        }
137    
138        public void setBufferSizeBytes(int bytes) {
139            //TODO what about the response and header buffer size?
140            listener.setRequestBufferSize(bytes);
141        }
142    
143        public int getAcceptQueueSize() {
144            return listener.getAcceptQueueSize();
145        }
146    
147        public void setAcceptQueueSize(int size) {
148            listener.setAcceptQueueSize(size);
149        }
150    
151        public int getLingerMillis() {
152            return (int) ((AbstractConnector) listener).getSoLingerTime();
153        }
154    
155        public void setLingerMillis(int millis) {
156            listener.setSoLingerTime(millis);
157        }
158    
159        public boolean isTcpNoDelay() {
160            return true;
161        }
162    
163        public void setTcpNoDelay(boolean enable) {
164            throw new UnsupportedOperationException(listener == null ? "No Listener" : listener.getClass().getName());
165        }
166    
167        public void setMaxThreads(int maxThreads) {
168            //TODO: in jetty6 connectors have a number of acceptor threads
169            listener.setAcceptors(maxThreads);
170        }
171    
172        public int getMaxThreads() {
173            //TODO: confirm that this is reasonable
174            return listener.getAcceptors();
175        }
176    
177        public int getRedirectPort() {
178            return listener.getConfidentialPort();
179        }
180    
181        public InetSocketAddress getListenAddress() {
182            try {
183                return new InetSocketAddress(InetAddress.getByName(listener.getHost()), listener.getPort());
184            } catch (UnknownHostException e) {
185                throw new IllegalStateException("InetSocketAddress cannot be determined for host=" + listener.getHost(), e);
186            }
187        }
188    
189        public void setRedirectPort(int port) {
190            throw new UnsupportedOperationException("No redirect port on " + this.getClass().getName());
191        }
192    
193        public abstract String getProtocol();
194    
195        public void doStart() throws Exception {
196            container.addListener(listener);
197            listener.start();
198        }
199    
200        public void doStop() {
201            while (true) {
202                try {
203                    listener.stop();
204                    container.removeListener(listener);
205                    return;
206                } catch (Exception e) {
207                    continue;
208                }
209            }
210        }
211    
212        public void doFail() {
213            while (true) {
214                try {
215                    listener.stop();
216                    container.removeListener(listener);
217                    return;
218                } catch (Exception e) {
219                    continue;
220                }
221            }
222        }
223        
224        public boolean isStatsOn() {
225            return listener.getStatsOn();
226        }
227        
228        public void setStatsOn(boolean on) {
229            listener.setStatsOn(on);
230            if (on) stats.setStartTime();
231        }
232        
233        /**
234         * Gets the statistics collected for this class. 
235         * The first call to this method initializes the startTime for
236         * all statistics. 
237         *
238         * @return gets collected for this class
239         */
240        public Stats getStats() {
241            if(isStatsOn()) {
242                stats.setLastSampleTime();
243                // connections open
244                stats.getOpenConnectionCountImpl().setCurrent(listener.getConnectionsOpen());
245                stats.getOpenConnectionCountImpl().setHighWaterMark(listener.getConnectionsOpenMax());
246                stats.getOpenConnectionCountImpl().setLowWaterMark(listener.getConnectionsOpenMin());
247                // request count
248                stats.getRequestCountImpl().setCount(listener.getRequests());
249                // connections count and durations
250                stats.getConnectionsDurationImpl().setCount(listener.getConnections());
251                stats.getConnectionsDurationImpl().setMaxTime(listener.getConnectionsDurationMax());
252                stats.getConnectionsDurationImpl().setMinTime(listener.getConnectionsDurationMin());
253                stats.getConnectionsDurationImpl().setTotalTime(listener.getConnectionsDurationTotal());
254                // requests per connection (connection requests)
255                stats.getConnectionsRequestImpl().setCurrent(listener.getConnectionsRequestsAve());
256                stats.getConnectionsRequestImpl().setHighWaterMark(listener.getConnectionsRequestsMax());
257                stats.getConnectionsRequestImpl().setLowWaterMark(listener.getConnectionsRequestsMin());
258            }
259            return stats;
260        }
261        
262        /**
263         * Reset the startTime for all statistics
264         */
265        public void resetStats() {
266            listener.statsReset();
267            stats.setStartTime(); // sets atartTime for all stats to Now
268        }
269        
270        public boolean isStateManageable() {
271            return true;
272        }
273    
274        public boolean isStatisticsProvider() {
275            return true;
276        }
277    
278        public static final GBeanInfo GBEAN_INFO;
279    
280        static {
281            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Jetty HTTP Connector", JettyConnector.class);
282            infoFactory.addReference(CONNECTOR_CONTAINER_REFERENCE, JettyContainer.class, NameFactory.GERONIMO_SERVICE);
283            infoFactory.addReference("ThreadPool", ThreadPool.class, NameFactory.GERONIMO_SERVICE);
284            // this is needed because the getters/setters are not added automatically
285            infoFactory.addOperation("setStatsOn", new Class[] { boolean.class }, "void");
286            // removed 'minThreads' from persistent and manageable String[]
287            // removed 'tcpNoDelay' from persistent String[]
288            // added 'protocol' to persistent and manageable String[]
289            infoFactory.addInterface(JettyWebConnector.class, 
290                    new String[]{"host", "port", "minThreads", "maxThreads", "bufferSizeBytes", "headerBufferSizeBytes", "acceptQueueSize", "lingerMillis", "protocol", "redirectPort", "connectUrl", "maxIdleTimeMs"},
291                    new String[]{"host", "port", "minThreads", "maxThreads", "bufferSizeBytes", "headerBufferSizeBytes", "acceptQueueSize", "lingerMillis", "protocol", "redirectPort"});
292            infoFactory.setConstructor(new String[]{"JettyContainer", "ThreadPool"});
293            GBEAN_INFO = infoFactory.getBeanInfo();
294        }
295    }