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;
019    
020    import java.io.File;
021    import java.util.HashMap;
022    import java.util.Map;
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.management.LazyStatisticsProvider;
030    import org.apache.geronimo.management.geronimo.NetworkConnector;
031    import org.apache.geronimo.management.geronimo.WebManager;
032    import org.apache.geronimo.management.geronimo.stats.JettyWebContainerStatsImpl;
033    import org.apache.geronimo.system.serverinfo.ServerInfo;
034    import org.apache.geronimo.webservices.SoapHandler;
035    import org.apache.geronimo.webservices.WebServiceContainer;
036    import org.mortbay.jetty.Connector;
037    import org.mortbay.jetty.Handler;
038    import org.mortbay.jetty.RequestLog;
039    import org.mortbay.jetty.Server;
040    import org.mortbay.jetty.handler.ContextHandler;
041    import org.mortbay.jetty.handler.ContextHandlerCollection;
042    import org.mortbay.jetty.handler.DefaultHandler;
043    import org.mortbay.jetty.handler.HandlerCollection;
044    import org.mortbay.jetty.handler.RequestLogHandler;
045    import org.mortbay.jetty.handler.StatisticsHandler;
046    import org.mortbay.jetty.handler.AbstractHandlerContainer;
047    
048    /**
049     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
050     */
051    public class JettyContainerImpl implements JettyContainer, SoapHandler, GBeanLifecycle, LazyStatisticsProvider {
052        /**
053         * The default value of JETTY_HOME variable
054         */
055        private static final String DEFAULT_JETTY_HOME = "var/jetty";
056    
057        private final Server server;
058        private final Map webServices = new HashMap();
059        private final String objectName;
060        private final WebManager manager;
061        private final String jettyHome;
062        private final ServerInfo serverInfo;
063        private File jettyHomeDir;
064        private JettyWebContainerStatsImpl stats;
065        private final Map realms = new HashMap();
066        // list of handlers
067        private StatisticsHandler statsHandler = new StatisticsHandler();  
068        private HandlerCollection handlerCollection = new HandlerCollection();
069        private ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
070        private DefaultHandler defaultHandler = new DefaultHandler();
071        private RequestLogHandler requestLogHandler = new RequestLogHandler();
072        private boolean statsHandlerInPlace = false;
073        private boolean statsOn=false;
074    
075        public JettyContainerImpl(String objectName, WebManager manager, String jettyHome, ServerInfo serverInfo) {
076            this.objectName = objectName;
077            this.jettyHome = jettyHome;
078            this.serverInfo = serverInfo;
079    
080            server = new JettyServer();
081    
082            //set up the new jetty6 handler structure which is to have a HandlerCollection,
083            //each element of which is always tried on each request.
084            //The first element of the HandlerCollection is a
085            //ContextHandlerCollection, which is itself is a collection
086            //of Handlers. It's special property is that only of it's
087            //handlers will respond to a request.
088            //The second element of the HandlerCollection is a DefaultHandler
089            //which is responsible for serving static content or anything not
090            //handled by a Handler in the ContextHandlerCollection.
091            //The third element is the RequestLogHandler, which requires
092            //a RequestLog impl to be set.
093            Handler[] handlers = new Handler[3];
094            handlers[0] = contextHandlerCollection;
095            handlers[1] = defaultHandler;
096            handlers[2] = requestLogHandler;
097            handlerCollection.setHandlers(handlers);
098            server.setHandler(handlerCollection);
099    
100            stats = new JettyWebContainerStatsImpl();
101            this.manager = manager;
102        }
103    
104        public String getObjectName() {
105            return objectName;
106        }
107    
108        public boolean isStateManageable() {
109            return true;
110        }
111    
112        public boolean isStatisticsProvider() {
113            return true;
114        }
115    
116        public boolean isEventProvider() {
117            return true;
118        }
119    
120        public NetworkConnector[] getConnectors() {
121            return manager.getConnectorsForContainer(this);
122        }
123    
124        public NetworkConnector[] getConnectors(String protocol) {
125            return manager.getConnectorsForContainer(this, protocol);
126        }
127    
128        public void resetStats() {
129            statsHandler.statsReset();
130            stats.setStartTime();
131        }
132    
133        public long getCollectStatisticsStarted() {
134            return statsHandler.getStatsOnMs();
135        }
136    
137        public boolean isStatsOn() {
138            return statsOn;
139        }
140        
141        public void setStatsOn(boolean on) {
142            try {
143                if (on) {
144                    // set the statistics handler if not already done so
145                    if (!statsHandlerInPlace) {
146                        handlerCollection.addHandler(statsHandler);
147                        statsHandlerInPlace = true;
148                    }
149                    // clear previous data and set start time
150                    resetStats();
151                    // start the handler
152                    statsHandler.start();
153                } else {
154                    statsHandler.stop();
155                    // hack because stats collection really doesn't really stop when statsHandler.stop() is invoked
156                    if (statsHandlerInPlace) {
157                        handlerCollection.removeHandler(statsHandler);
158                        statsHandlerInPlace=false;
159                    }
160                }
161                statsOn = on;
162            } catch(Exception e) {
163                e.printStackTrace();
164            }
165        }
166    
167        public Stats getStats() {
168            if (isStatsOn()) {
169                stats.setLastSampleTime();
170    
171                /* set active request range values */
172                stats.getActiveRequestCountImpl().setCurrent((long)statsHandler.getRequestsActive());
173                stats.getActiveRequestCountImpl().setLowWaterMark((long)statsHandler.getRequestsActiveMin());
174                stats.getActiveRequestCountImpl().setHighWaterMark((long)statsHandler.getRequestsActiveMax());
175        
176                /* set request duration time values, avg = Totaltime/Count */
177                /* set active request count */
178                stats.getRequestDurationImpl().setCount((long)statsHandler.getRequests());
179                stats.getRequestDurationImpl().setMaxTime((long)statsHandler.getRequestsDurationMax());
180                stats.getRequestDurationImpl().setMinTime((long)statsHandler.getRequestsDurationMin());
181                stats.getRequestDurationImpl().setTotalTime((long)statsHandler.getRequestsDurationTotal());
182        
183                /* set request count values*/
184                stats.getResponses1xxImpl().setCount((long)statsHandler.getResponses1xx());
185                stats.getResponses2xxImpl().setCount((long)statsHandler.getResponses2xx());
186                stats.getResponses3xxImpl().setCount((long)statsHandler.getResponses3xx());
187                stats.getResponses4xxImpl().setCount((long)statsHandler.getResponses4xx());
188                stats.getResponses5xxImpl().setCount((long)statsHandler.getResponses5xx());
189        
190                /* set elapsed time for stats collection */
191                stats.getStatsOnMsImpl().setCount((long)statsHandler.getStatsOnMs());
192            }
193            return stats;
194        }
195    
196        public void addListener(Connector listener) {
197            server.addConnector(listener);
198        }
199    
200        public void removeListener(Connector listener) {
201            server.removeConnector(listener);
202        }
203    
204        public void addContext(AbstractHandlerContainer context) {
205            contextHandlerCollection.addHandler(context);
206        }
207    
208        public void removeContext(AbstractHandlerContainer context) {
209            contextHandlerCollection.removeHandler(context);
210        }
211    
212        public InternalJAASJettyRealm addRealm(String realmName) {
213            InternalJAASJettyRealm realm = (InternalJAASJettyRealm) realms.get(realmName);
214            if (realm == null) {
215                realm = new InternalJAASJettyRealm(realmName);
216                realms.put(realmName, realm);
217            } else {
218                realm.addUse();
219            }
220            return realm;
221        }
222    
223        public void removeRealm(String realmName) {
224            InternalJAASJettyRealm realm = (InternalJAASJettyRealm) realms.get(realmName);
225            if (realm != null) {
226                if (realm.removeUse() == 0) {
227                    realms.remove(realmName);
228                }
229            }
230        }
231    
232        public void addWebService(String contextPath, String[] virtualHosts, WebServiceContainer webServiceContainer, String securityRealmName, String realmName, String transportGuarantee, String authMethod, ClassLoader classLoader) throws Exception {
233            InternalJAASJettyRealm internalJAASJettyRealm = securityRealmName == null ? null : addRealm(securityRealmName);
234            JettyEJBWebServiceContext webServiceContext = new JettyEJBWebServiceContext(contextPath, webServiceContainer, internalJAASJettyRealm, realmName, transportGuarantee, authMethod, classLoader);
235            webServiceContext.setVirtualHosts(virtualHosts);
236            addContext(webServiceContext);
237            webServiceContext.start();
238            webServices.put(contextPath, webServiceContext);
239        }
240    
241        public void removeWebService(String contextPath) {
242            JettyEJBWebServiceContext webServiceContext = (JettyEJBWebServiceContext) webServices.remove(contextPath);
243            String securityRealmName = webServiceContext.getSecurityRealmName();
244            if (securityRealmName != null) {
245                removeRealm(securityRealmName);
246            }
247            try {
248                removeContext(webServiceContext);
249            } catch (Exception e) {
250                throw new IllegalStateException(e.getMessage(), e);
251            }
252        }
253    
254        public void setRequestLog(RequestLog log) {
255            this.requestLogHandler.setRequestLog(log);
256        }
257    
258        public File resolveToJettyHome(String workDir) {
259            if (workDir == null) {
260                return null;
261            }
262            return new File(jettyHomeDir, workDir);
263        }
264    
265        public RequestLog getRequestLog() {
266            return this.requestLogHandler.getRequestLog();
267        }
268    
269        public void doStart() throws Exception {
270            jettyHomeDir = new File(serverInfo.resolveServerPath(jettyHome != null ? jettyHome : DEFAULT_JETTY_HOME));
271            if (!jettyHomeDir.exists()) {
272                jettyHomeDir.mkdirs();
273            }
274            // start the server
275            server.start();
276        }
277    
278        public void doStop() {
279            try {
280                server.stop();
281            } catch (Exception e) {
282            }
283        }
284    
285        public void doFail() {
286            try {
287                server.stop();
288            } catch (Exception e) {
289                // continue
290            }
291        }
292    
293        public static final GBeanInfo GBEAN_INFO;
294    
295        static {
296            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("Jetty Web Container", JettyContainerImpl.class);
297            infoBuilder.addAttribute("statsOn", Boolean.TYPE, true);
298            infoBuilder.addAttribute("collectStatisticsStarted", Long.TYPE, false);
299            infoBuilder.addAttribute("objectName", String.class, false);
300            infoBuilder.addAttribute("jettyHome", String.class, true);
301    
302            infoBuilder.addReference("WebManager", WebManager.class);
303            infoBuilder.addReference("ServerInfo", ServerInfo.class, "GBean");
304    
305            // this is needed because the getters/setters are not added automatically
306            infoBuilder.addOperation("setStatsOn", new Class[] { boolean.class }, "void");
307            infoBuilder.addOperation("resetStats");
308    
309            infoBuilder.addInterface(SoapHandler.class);
310            infoBuilder.addInterface(JettyContainer.class);
311            infoBuilder.addInterface(LazyStatisticsProvider.class);
312    
313            infoBuilder.setConstructor(new String[]{"objectName", "WebManager", "jettyHome", "ServerInfo"});
314    
315            GBEAN_INFO = infoBuilder.getBeanInfo();
316        }
317    
318        public static GBeanInfo getGBeanInfo() {
319            return GBEAN_INFO;
320        }
321    
322    
323    }