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 }