View Javadoc

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     // JSR 77 
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 //        TODO is there a simpler way to do this?
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         //Add the valve list
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         //Add the cluster
211         if (cluster != null) {
212             catalinaCluster = (CatalinaCluster) cluster.getInternalObject();
213         } else {
214             catalinaCluster = null;
215         }
216 
217         //Add the manager
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             // StandardContext uses default value of these as "none"
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         //todo: make this return something more consistent
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         // See the note of TomcatContainer::addContext
475         container.addContext(this);
476         // Is it necessary - doesn't Tomcat Embedded take care of it?
477         // super.start();
478         //register the classloader <> dir context association so that tomcat's jndi based getResources works.
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         // No more logging will occur for this ClassLoader. Inform the LogFactory to avoid a memory leak.
490 //        LogFactory.release(classLoader);
491 
492         log.debug("TomcatWebAppContext stopped");
493     }
494 
495     public void doFail() {
496         container.removeContext(this);
497 
498         // No more logging will occur for this ClassLoader. Inform the LogFactory to avoid a memory leak.
499 //        LogFactory.release(classLoader);
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 }