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
19 package org.apache.geronimo.tomcat;
20
21 import java.net.MalformedURLException;
22 import java.net.URI;
23 import java.net.URL;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.Hashtable;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import javax.management.MalformedObjectNameException;
33 import javax.management.ObjectName;
34 import javax.naming.directory.DirContext;
35 import javax.transaction.TransactionManager;
36 import javax.transaction.UserTransaction;
37
38 import org.apache.catalina.Context;
39 import org.apache.catalina.Manager;
40 import org.apache.catalina.Realm;
41 import org.apache.catalina.Valve;
42 import org.apache.catalina.cluster.CatalinaCluster;
43 import org.apache.catalina.core.StandardContext;
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46 import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
47 import org.apache.geronimo.gbean.AbstractName;
48 import org.apache.geronimo.gbean.GBeanInfo;
49 import org.apache.geronimo.gbean.GBeanInfoBuilder;
50 import org.apache.geronimo.gbean.GBeanLifecycle;
51 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
52 import org.apache.geronimo.j2ee.management.impl.InvalidObjectNameException;
53 import org.apache.geronimo.kernel.Kernel;
54 import org.apache.geronimo.kernel.ObjectNameUtil;
55 import org.apache.geronimo.management.J2EEApplication;
56 import org.apache.geronimo.management.J2EEServer;
57 import org.apache.geronimo.management.geronimo.WebConnector;
58 import org.apache.geronimo.management.geronimo.WebContainer;
59 import org.apache.geronimo.management.geronimo.WebModule;
60 import org.apache.geronimo.tomcat.cluster.CatalinaClusterGBean;
61 import org.apache.geronimo.tomcat.util.SecurityHolder;
62 import org.apache.geronimo.transaction.GeronimoUserTransaction;
63 import org.apache.geronimo.webservices.WebServiceContainer;
64 import org.apache.geronimo.webservices.WebServiceContainerFactory;
65 import org.apache.naming.resources.DirContextURLStreamHandler;
66
67 /**
68 * Wrapper for a WebApplicationContext that sets up its J2EE environment.
69 *
70 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
71 */
72 public class TomcatWebAppContext implements GBeanLifecycle, TomcatContext, WebModule {
73
74 private static Log log = LogFactory.getLog(TomcatWebAppContext.class);
75
76 protected final TomcatContainer container;
77
78 private final ClassLoader classLoader;
79
80 protected Context context = null;
81
82 private String path = null;
83
84 private String docBase = null;
85
86 private String virtualServer = null;
87
88 private final Realm realm;
89
90 private final List valveChain;
91
92 private final CatalinaCluster catalinaCluster;
93
94 private final Manager manager;
95
96 private final boolean crossContext;
97
98 private final boolean disableCookies;
99
100 private final UserTransaction userTransaction;
101
102 private final Map componentContext;
103
104 private final Kernel kernel;
105
106 private final Set unshareableResources;
107
108 private final Set applicationManagedSecurityResources;
109
110 private final TrackedConnectionAssociator trackedConnectionAssociator;
111
112 private final SecurityHolder securityHolder;
113
114 private final J2EEServer server;
115
116 private final Map webServices;
117
118 private final String objectName;
119
120 private final String originalSpecDD;
121
122 private final URL configurationBaseURL;
123
124
125
126 private final String j2EEServer;
127
128 private final String j2EEApplication;
129
130 public TomcatWebAppContext(
131 ClassLoader classLoader,
132 String objectName,
133 String originalSpecDD,
134 URL configurationBaseUrl,
135 SecurityHolder securityHolder,
136 String virtualServer,
137 Map componentContext,
138 Set unshareableResources,
139 Set applicationManagedSecurityResources,
140 TransactionManager transactionManager,
141 TrackedConnectionAssociator trackedConnectionAssociator,
142 TomcatContainer container,
143 ObjectRetriever tomcatRealm,
144 ValveGBean tomcatValveChain,
145 CatalinaClusterGBean cluster,
146 ManagerGBean manager,
147 boolean crossContext,
148 boolean disableCookies,
149 Map webServices,
150 J2EEServer server,
151 J2EEApplication application,
152 Kernel kernel)
153 throws Exception {
154
155 assert classLoader != null;
156 assert configurationBaseUrl != null;
157 assert transactionManager != null;
158 assert trackedConnectionAssociator != null;
159 assert componentContext != null;
160 assert container != null;
161
162
163 this.objectName = objectName;
164 URI root;
165
166 if (configurationBaseUrl.getProtocol().equalsIgnoreCase("file")) {
167 root = new URI("file", configurationBaseUrl.getPath(), null);
168 } else {
169 root = URI.create(configurationBaseUrl.toString());
170 }
171 this.setDocBase(root.getPath());
172 this.container = container;
173 this.originalSpecDD = originalSpecDD;
174
175 this.virtualServer = virtualServer;
176 this.securityHolder = securityHolder;
177
178 this.userTransaction = new GeronimoUserTransaction(transactionManager);
179 this.componentContext = componentContext;
180 this.unshareableResources = unshareableResources;
181 this.applicationManagedSecurityResources = applicationManagedSecurityResources;
182 this.trackedConnectionAssociator = trackedConnectionAssociator;
183
184 this.server = server;
185
186 this.configurationBaseURL = configurationBaseUrl;
187
188 if (tomcatRealm != null){
189 realm = (Realm)tomcatRealm.getInternalObject();
190 if (realm == null){
191 throw new IllegalArgumentException("tomcatRealm must be an instance of org.apache.catalina.Realm.");
192 }
193 } else{
194 realm = null;
195 }
196
197
198 if (tomcatValveChain != null){
199 ArrayList chain = new ArrayList();
200 ValveGBean valveGBean = tomcatValveChain;
201 while(valveGBean != null){
202 chain.add((Valve)valveGBean.getInternalObject());
203 valveGBean = valveGBean.getNextValve();
204 }
205 valveChain = chain;
206 } else {
207 valveChain = null;
208 }
209
210
211 if (cluster != null) {
212 catalinaCluster = (CatalinaCluster) cluster.getInternalObject();
213 } else {
214 catalinaCluster = null;
215 }
216
217
218 if (manager != null) {
219 this.manager = (Manager) manager.getInternalObject();
220 } else {
221 this.manager = null;
222 }
223
224 this.crossContext = crossContext;
225
226 this.disableCookies = disableCookies;
227
228 this.webServices = createWebServices(webServices, kernel);
229
230 this.classLoader = classLoader;
231
232 this.kernel = kernel;
233
234 if (objectName != null) {
235 ObjectName myObjectName = ObjectNameUtil.getObjectName(objectName);
236 verifyObjectName(myObjectName);
237 j2EEServer = myObjectName.getKeyProperty(NameFactory.J2EE_SERVER);
238 j2EEApplication = myObjectName.getKeyProperty(NameFactory.J2EE_APPLICATION);
239 } else {
240
241 j2EEServer = null;
242 j2EEApplication = null;
243 }
244 }
245
246 private Map createWebServices(Map webServiceFactoryMap, Kernel kernel) throws Exception {
247 Map webServices = new HashMap();
248 if (webServiceFactoryMap != null) {
249 for (Iterator iterator = webServiceFactoryMap.entrySet().iterator(); iterator.hasNext();) {
250 Map.Entry entry = (Map.Entry) iterator.next();
251 String servletName = (String) entry.getKey();
252 AbstractName factoryName = (AbstractName) entry.getValue();
253 WebServiceContainerFactory webServiceContainerFactory = (WebServiceContainerFactory) kernel.getGBean(factoryName);
254 WebServiceContainer webServiceContainer = webServiceContainerFactory.getWebServiceContainer();
255 webServices.put(servletName, webServiceContainer);
256 }
257 }
258 return webServices;
259 }
260
261 public String getObjectName() {
262 return objectName;
263 }
264
265 public String getJ2EEApplication() {
266 return j2EEApplication;
267 }
268
269 public String getJ2EEServer() {
270 return j2EEServer;
271 }
272
273 public boolean isStateManageable() {
274 return true;
275 }
276
277 public boolean isStatisticsProvider() {
278 return false;
279 }
280
281 public boolean isEventProvider() {
282 return true;
283 }
284
285 public URL getWARDirectory() {
286 return configurationBaseURL;
287 }
288
289 public String getWARName() {
290
291 try {
292 return ObjectName.getInstance(objectName).getKeyProperty(NameFactory.J2EE_NAME);
293 } catch (MalformedObjectNameException e) {
294 return null;
295 }
296 }
297
298 public WebContainer getContainer() {
299 return container;
300 }
301
302 public String getServer() {
303 return server == null? null: server.getObjectName();
304 }
305
306 public String getDocBase() {
307 return docBase;
308 }
309
310 public void setDocBase(String docBase) {
311 this.docBase = docBase;
312 }
313
314 public UserTransaction getUserTransaction() {
315 return userTransaction;
316 }
317
318 public Map getComponentContext() {
319 return componentContext;
320 }
321
322 public String getVirtualServer() {
323 return virtualServer;
324 }
325
326 public ClassLoader getClassLoader() {
327 return classLoader;
328 }
329
330 public Kernel getKernel() {
331 return kernel;
332 }
333
334 public boolean isDisableCookies() {
335 return disableCookies;
336 }
337
338 public Context getContext() {
339 return context;
340 }
341
342 public void setContext(Context context) {
343 this.context = context;
344 }
345
346 public URL getURLFor() {
347 WebConnector[] connectors = (WebConnector[]) container.getConnectors();
348 Map map = new HashMap();
349 for (int i = 0; i < connectors.length; i++) {
350 WebConnector connector = connectors[i];
351 map.put(connector.getProtocol(), connector.getConnectUrl());
352 }
353 String urlPrefix;
354 if((urlPrefix = (String) map.get("HTTP")) == null) {
355 if((urlPrefix = (String) map.get("HTTPS")) == null) {
356 urlPrefix = (String) map.get("AJP");
357 }
358 }
359 if(urlPrefix == null) {
360 return null;
361 }
362 try {
363 return new URL(urlPrefix + getContextPath());
364 } catch (MalformedURLException e) {
365 log.error("Bad URL to connect to web app", e);
366 return null;
367 }
368 }
369
370 public String getContextPath() {
371 return path;
372 }
373
374 public void setContextPath(String path) {
375 this.path = path.startsWith("/") ? path : "/" + path;
376 }
377
378 public SecurityHolder getSecurityHolder() {
379 return securityHolder;
380 }
381
382
383 public Set getApplicationManagedSecurityResources() {
384 return applicationManagedSecurityResources;
385 }
386
387 public TrackedConnectionAssociator getTrackedConnectionAssociator() {
388 return trackedConnectionAssociator;
389 }
390
391 public Set getUnshareableResources() {
392 return unshareableResources;
393 }
394
395 public Realm getRealm() {
396 return realm;
397 }
398
399 public List getValveChain() {
400 return valveChain;
401 }
402
403 public CatalinaCluster getCluster() {
404 return catalinaCluster;
405 }
406
407 public Manager getManager() {
408 return manager;
409 }
410
411 public boolean isCrossContext() {
412 return crossContext;
413 }
414
415 public Map getWebServices(){
416 return webServices;
417 }
418
419 public String[] getServlets(){
420 String[] result = null;
421 if ((context != null) && (context instanceof StandardContext)) {
422 result = ((StandardContext) context).getServlets();
423 }
424
425 return result;
426 }
427
428 /**
429 * ObjectName must match this pattern: <p/>
430 * domain:j2eeType=WebModule,name=MyName,J2EEServer=MyServer,J2EEApplication=MyApplication
431 */
432 private void verifyObjectName(ObjectName objectName) {
433 if (objectName.isPattern()) {
434 throw new InvalidObjectNameException(
435 "ObjectName can not be a pattern", objectName);
436 }
437 Hashtable keyPropertyList = objectName.getKeyPropertyList();
438 if (!NameFactory.WEB_MODULE.equals(keyPropertyList.get("j2eeType"))) {
439 throw new InvalidObjectNameException(
440 "WebModule object name j2eeType property must be 'WebModule'",
441 objectName);
442 }
443 if (!keyPropertyList.containsKey(NameFactory.J2EE_NAME)) {
444 throw new InvalidObjectNameException(
445 "WebModule object must contain a name property", objectName);
446 }
447 if (!keyPropertyList.containsKey(NameFactory.J2EE_SERVER)) {
448 throw new InvalidObjectNameException(
449 "WebModule object name must contain a J2EEServer property",
450 objectName);
451 }
452 if (!keyPropertyList.containsKey(NameFactory.J2EE_APPLICATION)) {
453 throw new InvalidObjectNameException(
454 "WebModule object name must contain a J2EEApplication property",
455 objectName);
456 }
457 if (keyPropertyList.size() != 4) {
458 throw new InvalidObjectNameException(
459 "WebModule object name can only have j2eeType, name, J2EEApplication, and J2EEServer properties",
460 objectName);
461 }
462 }
463
464 public String[] getJavaVMs() {
465 return server == null? new String[0]: server.getJavaVMs();
466 }
467
468 public String getDeploymentDescriptor() {
469 return originalSpecDD;
470 }
471
472 public void doStart() throws Exception {
473
474
475 container.addContext(this);
476
477
478
479 DirContext resources = context.getResources();
480 DirContextURLStreamHandler.bind(classLoader, resources);
481
482 log.debug("TomcatWebAppContext started for " + path);
483 }
484
485 public void doStop() throws Exception {
486 container.removeContext(this);
487 DirContextURLStreamHandler.unbind(classLoader);
488
489
490
491
492 log.debug("TomcatWebAppContext stopped");
493 }
494
495 public void doFail() {
496 container.removeContext(this);
497
498
499
500
501 log.warn("TomcatWebAppContext failed");
502 }
503
504 public static final GBeanInfo GBEAN_INFO;
505
506 static {
507 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("Tomcat WebApplication Context", TomcatWebAppContext.class, NameFactory.WEB_MODULE);
508
509 infoBuilder.addAttribute("classLoader", ClassLoader.class, false);
510 infoBuilder.addAttribute("objectName", String.class, false);
511 infoBuilder.addAttribute("deploymentDescriptor", String.class, true);
512 infoBuilder.addAttribute("configurationBaseUrl", URL.class, true);
513
514 infoBuilder.addAttribute("contextPath", String.class, true);
515
516 infoBuilder.addAttribute("securityHolder", SecurityHolder.class, true);
517 infoBuilder.addAttribute("virtualServer", String.class, true);
518 infoBuilder.addAttribute("componentContext", Map.class, true);
519 infoBuilder.addAttribute("unshareableResources", Set.class, true);
520 infoBuilder.addAttribute("applicationManagedSecurityResources", Set.class, true);
521 infoBuilder.addReference("TransactionManager", TransactionManager.class, NameFactory.TRANSACTION_MANAGER);
522 infoBuilder.addReference("TrackedConnectionAssociator", TrackedConnectionAssociator.class, NameFactory.JCA_CONNECTION_TRACKER);
523
524 infoBuilder.addReference("Container", TomcatContainer.class, NameFactory.GERONIMO_SERVICE);
525 infoBuilder.addReference("TomcatRealm", ObjectRetriever.class);
526 infoBuilder.addReference("TomcatValveChain", ValveGBean.class);
527 infoBuilder.addReference("Cluster", CatalinaClusterGBean.class, CatalinaClusterGBean.J2EE_TYPE);
528 infoBuilder.addReference("Manager", ManagerGBean.class);
529 infoBuilder.addAttribute("crossContext", boolean.class, true);
530 infoBuilder.addAttribute("disableCookies", boolean.class, true);
531 infoBuilder.addAttribute("webServices", Map.class, true);
532 infoBuilder.addReference("J2EEServer", J2EEServer.class);
533 infoBuilder.addReference("J2EEApplication", J2EEApplication.class);
534 infoBuilder.addAttribute("kernel", Kernel.class, false);
535
536 infoBuilder.addInterface(WebModule.class);
537
538 infoBuilder.setConstructor(new String[] {
539 "classLoader",
540 "objectName",
541 "deploymentDescriptor",
542 "configurationBaseUrl",
543 "securityHolder",
544 "virtualServer",
545 "componentContext",
546 "unshareableResources",
547 "applicationManagedSecurityResources",
548 "TransactionManager",
549 "TrackedConnectionAssociator",
550 "Container",
551 "TomcatRealm",
552 "TomcatValveChain",
553 "Cluster",
554 "Manager",
555 "crossContext",
556 "disableCookies",
557 "webServices",
558 "J2EEServer",
559 "J2EEApplication",
560 "kernel"
561 }
562 );
563
564 GBEAN_INFO = infoBuilder.getBeanInfo();
565 }
566
567 public static GBeanInfo getGBeanInfo() {
568 return GBEAN_INFO;
569 }
570 }