1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.geronimo.tomcat;
19
20 import java.io.File;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.net.URLStreamHandlerFactory;
24 import java.net.URL;
25
26 import javax.management.ObjectName;
27
28 import org.apache.catalina.Container;
29 import org.apache.catalina.Context;
30 import org.apache.catalina.Engine;
31 import org.apache.catalina.Realm;
32 import org.apache.catalina.connector.Connector;
33 import org.apache.catalina.realm.JAASRealm;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.geronimo.gbean.GBeanInfo;
37 import org.apache.geronimo.gbean.GBeanInfoBuilder;
38 import org.apache.geronimo.gbean.GBeanLifecycle;
39 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
40 import org.apache.geronimo.kernel.ObjectNameUtil;
41 import org.apache.geronimo.management.geronimo.NetworkConnector;
42 import org.apache.geronimo.management.geronimo.WebManager;
43 import org.apache.geronimo.system.serverinfo.ServerInfo;
44 import org.apache.geronimo.tomcat.realm.TomcatGeronimoRealm;
45 import org.apache.geronimo.tomcat.realm.TomcatJAASRealm;
46 import org.apache.geronimo.tomcat.util.SecurityHolder;
47 import org.apache.geronimo.webservices.SoapHandler;
48 import org.apache.geronimo.webservices.WebServiceContainer;
49 import org.apache.naming.resources.DirContextURLStreamHandlerFactory;
50
51
52 /**
53 * Apache Tomcat GBean
54 * http://wiki.apache.org/geronimo/Tomcat
55 * http://nagoya.apache.org/jira/browse/GERONIMO-215
56 *
57 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
58 */
59 public class TomcatContainer implements SoapHandler, GBeanLifecycle, TomcatWebContainer {
60
61 private static final Log log = LogFactory.getLog(TomcatContainer.class);
62
63 /**
64 * The default value of CATALINA_HOME variable
65 */
66 private static final String DEFAULT_CATALINA_HOME = "var/catalina";
67
68 /**
69 * Reference to the org.apache.catalina.Embedded embedded.
70 */
71 private TomcatGeronimoEmbedded embedded;
72
73 /**
74 * Tomcat Engine that will contain the host
75 */
76 private Engine engine;
77
78 /**
79 * Geronimo class loader
80 */
81 private ClassLoader classLoader;
82
83 private final Map webServices = new HashMap();
84 private final String objectName;
85 private final WebManager manager;
86 private static boolean first = true;
87
88
89 public TomcatContainer() {
90 this.objectName = null;
91 setCatalinaHome(DEFAULT_CATALINA_HOME);
92 manager = null;
93 }
94
95 /**
96 * GBean constructor (invoked dynamically when the gbean is declared in a plan)
97 */
98 public TomcatContainer(ClassLoader classLoader, String catalinaHome, ObjectRetriever engineGBean, ServerInfo serverInfo, String objectName, WebManager manager) {
99
100 URLStreamHandlerFactory streamHandlerFactory =
101 new DirContextURLStreamHandlerFactory();
102 if (first) {
103 first = false;
104 try {
105 URL.setURLStreamHandlerFactory(streamHandlerFactory);
106 } catch (Exception e) {
107
108 log.error("Error registering jndi stream handler", e);
109 } catch (Throwable t) {
110
111 log.info("Dual registration of jndi stream handler: "
112 + t.getMessage());
113 }
114 }
115
116
117 if (catalinaHome == null)
118 catalinaHome = DEFAULT_CATALINA_HOME;
119
120 setCatalinaHome(serverInfo.resolveServerPath(catalinaHome));
121
122 if (classLoader == null) {
123 throw new IllegalArgumentException("classLoader cannot be null.");
124 }
125
126 if (engineGBean == null) {
127 throw new IllegalArgumentException("engineGBean cannot be null.");
128 }
129
130 this.classLoader = classLoader;
131
132 this.engine = (Engine) engineGBean.getInternalObject();
133
134 this.objectName = objectName;
135 this.manager = manager;
136 }
137
138 public String getObjectName() {
139 return objectName;
140 }
141
142 public boolean isStateManageable() {
143 return true;
144 }
145
146 public boolean isStatisticsProvider() {
147 return false;
148 }
149
150 public boolean isEventProvider() {
151 return true;
152 }
153
154 public NetworkConnector[] getConnectors() {
155 return manager.getConnectorsForContainer(this);
156 }
157
158 public NetworkConnector[] getConnectors(String protocol) {
159 return manager.getConnectorsForContainer(this, protocol);
160 }
161
162 public void doFail() {
163 try {
164 doStop();
165 } catch (Exception ignored) {
166 }
167 }
168
169 /**
170 * Instantiate and start up Tomcat's Embedded class
171 * <p/>
172 * See org.apache.catalina.startup.Embedded for details (TODO: provide the link to the javadoc)
173 */
174 public void doStart() throws Exception {
175 log.debug("doStart()");
176
177 log.debug("Endorsed Dirs set to:" + System.getProperty("java.endorsed.dirs"));
178
179
180
181
182 if (embedded == null) {
183 embedded = new TomcatGeronimoEmbedded();
184 }
185
186
187
188
189
190
191
192
193
194
195 embedded.setUseNaming(false);
196
197
198 File rootContext = new File(System.getProperty("catalina.home") + "/ROOT");
199
200 String docBase = "";
201 if (rootContext.exists()) {
202 docBase = "ROOT";
203 }
204
205 Container[] hosts = engine.findChildren();
206 Context defaultContext;
207 for (int i = 0; i < hosts.length; i++) {
208 defaultContext = embedded.createContext("", docBase, classLoader);
209 if (defaultContext instanceof GeronimoStandardContext) {
210 GeronimoStandardContext ctx = (GeronimoStandardContext) defaultContext;
211
212
213 ctx.setJ2EEApplication(null);
214
215 ctx.setJ2EEServer("geronimo");
216 }
217 hosts[i].addChild(defaultContext);
218 }
219
220
221
222 embedded.addEngine(engine);
223
224
225
226 embedded.start();
227 }
228
229 public void doStop() throws Exception {
230 if (embedded != null) {
231 embedded.stop();
232 embedded = null;
233 }
234
235 }
236
237 /**
238 * Creates and adds the context to the running host
239 * <p/>
240 * It simply delegates the call to Tomcat's Embedded and Host classes
241 *
242 * @param ctx the context to be added
243 * @see org.apache.catalina.startup.Embedded
244 * @see org.apache.catalina.Host
245 */
246 public void addContext(TomcatContext ctx) throws Exception {
247 Context anotherCtxObj = embedded.createContext(ctx.getContextPath(), ctx.getDocBase(), ctx.getClassLoader());
248
249
250 ctx.setContext(anotherCtxObj);
251
252
253 if (anotherCtxObj instanceof GeronimoStandardContext) {
254 ((GeronimoStandardContext) anotherCtxObj).setContextProperties(ctx);
255 }
256
257 String virtualServer = ctx.getVirtualServer();
258 if (virtualServer == null) {
259 virtualServer = engine.getDefaultHost();
260 }
261 Container host = engine.findChild(virtualServer);
262 if (host == null) {
263 throw new IllegalArgumentException("Invalid virtual host '" + virtualServer + "'. Do you have a matching Host entry in the plan?");
264 }
265
266
267 String securityRealmName = null;
268 SecurityHolder secHolder = ctx.getSecurityHolder();
269 if (secHolder != null)
270 securityRealmName = secHolder.getSecurityRealm();
271
272
273 if (ctx.getRealm() != null) {
274 Realm realm = ctx.getRealm();
275
276
277
278 if (securityRealmName != null) {
279 if (realm instanceof JAASRealm) {
280 ((JAASRealm) realm).setAppName(securityRealmName);
281 }
282 }
283 anotherCtxObj.setRealm(realm);
284 } else {
285 Realm realm = host.getRealm();
286
287 if (securityRealmName != null) {
288 String parentRealmName = null;
289 if (realm instanceof JAASRealm) {
290 parentRealmName = ((JAASRealm) realm).getAppName();
291 }
292
293
294 if (!securityRealmName.equals(parentRealmName)) {
295
296
297
298 if (secHolder.isSecurity()) {
299
300 realm = new TomcatGeronimoRealm();
301 } else {
302
303 realm = new TomcatJAASRealm();
304 }
305
306 log.debug("The security-realm-name '" + securityRealmName +
307 "' was specified and a parent (Engine/Host) is not named the same or no RealmGBean was configured for this context. " +
308 "Creating a default " + realm.getClass().getName() +
309 " adapter for this context.");
310
311 ((JAASRealm) realm).setUserClassNames("org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal");
312 ((JAASRealm) realm).setRoleClassNames("org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal");
313 ((JAASRealm) realm).setAppName(securityRealmName);
314
315 anotherCtxObj.setRealm(realm);
316 } else {
317
318 anotherCtxObj.setRealm(realm);
319 }
320 } else {
321 anotherCtxObj.setRealm(realm);
322 }
323 }
324
325 host.addChild(anotherCtxObj);
326 }
327
328 public void removeContext(TomcatContext ctx) {
329 Context context = ctx.getContext();
330
331 if (context != null) {
332 if (context instanceof GeronimoStandardContext) {
333 GeronimoStandardContext stdctx = (GeronimoStandardContext) context;
334
335 try {
336 stdctx.stop();
337 stdctx.destroy();
338 } catch (Exception e) {
339 throw new RuntimeException(e);
340 }
341
342 }
343 context.getParent().removeChild(context);
344 }
345
346 }
347
348 public void setCatalinaHome(String catalinaHome) {
349 System.setProperty("catalina.home", catalinaHome);
350 }
351
352 public void addConnector(Connector connector) {
353 embedded.addConnector(connector);
354 }
355
356 public void removeConnector(Connector connector) {
357 embedded.removeConnector(connector);
358 }
359
360 public void addWebService(String contextPath, String[] virtualHosts, WebServiceContainer webServiceContainer, String securityRealmName, String realmName, String transportGuarantee, String authMethod, ClassLoader classLoader) throws Exception {
361 Context webServiceContext = embedded.createEJBWebServiceContext(contextPath, webServiceContainer, securityRealmName, realmName, transportGuarantee, authMethod, classLoader);
362
363 String virtualServer;
364 if (virtualHosts != null && virtualHosts.length > 0) {
365 virtualServer = virtualHosts[0];
366 } else {
367 virtualServer = engine.getDefaultHost();
368 }
369
370 Container host = engine.findChild(virtualServer);
371 if (host == null) {
372 throw new IllegalArgumentException("Invalid virtual host '" + virtualServer + "'. Do you have a matchiing Host entry in the plan?");
373 }
374
375 host.addChild(webServiceContext);
376 webServices.put(contextPath, webServiceContext);
377 }
378
379 public void removeWebService(String contextPath) {
380 TomcatEJBWebServiceContext context = (TomcatEJBWebServiceContext) webServices.get(contextPath);
381 try {
382 context.stop();
383 context.destroy();
384 } catch (Exception e) {
385 throw new RuntimeException(e);
386 }
387 context.getParent().removeChild(context);
388 webServices.remove(contextPath);
389 }
390
391 public static final GBeanInfo GBEAN_INFO;
392
393 static {
394 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Tomcat Web Container", TomcatContainer.class);
395
396 infoFactory.setConstructor(new String[]{"classLoader", "catalinaHome", "EngineGBean", "ServerInfo", "objectName", "WebManager"});
397
398 infoFactory.addAttribute("classLoader", ClassLoader.class, false);
399
400 infoFactory.addAttribute("catalinaHome", String.class, true);
401
402 infoFactory.addAttribute("objectName", String.class, false);
403
404 infoFactory.addReference("EngineGBean", ObjectRetriever.class, NameFactory.GERONIMO_SERVICE);
405
406 infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean");
407 infoFactory.addReference("WebManager", WebManager.class);
408
409 infoFactory.addOperation("addContext", new Class[]{TomcatContext.class});
410 infoFactory.addOperation("removeContext", new Class[]{TomcatContext.class});
411
412 infoFactory.addOperation("addConnector", new Class[]{Connector.class});
413 infoFactory.addOperation("removeConnector", new Class[]{Connector.class});
414
415 infoFactory.addInterface(SoapHandler.class);
416 infoFactory.addInterface(TomcatWebContainer.class);
417
418 GBEAN_INFO = infoFactory.getBeanInfo();
419 }
420
421 public static GBeanInfo getGBeanInfo() {
422 return GBEAN_INFO;
423 }
424
425 }