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 }