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  package org.apache.geronimo.tomcat;
19  
20  import java.beans.PropertyChangeListener;
21  import java.io.IOException;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.naming.NamingException;
27  import javax.security.auth.Subject;
28  import javax.security.jacc.PolicyContext;
29  import javax.servlet.Servlet;
30  import javax.servlet.ServletException;
31  
32  import org.apache.catalina.Container;
33  import org.apache.catalina.LifecycleException;
34  import org.apache.catalina.Loader;
35  import org.apache.catalina.Manager;
36  import org.apache.catalina.Valve;
37  import org.apache.catalina.Wrapper;
38  import org.apache.catalina.cluster.CatalinaCluster;
39  import org.apache.catalina.connector.Request;
40  import org.apache.catalina.connector.Response;
41  import org.apache.catalina.core.StandardContext;
42  import org.apache.catalina.valves.ValveBase;
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  import org.apache.geronimo.common.DeploymentException;
46  import org.apache.geronimo.naming.enc.EnterpriseNamingContext;
47  import org.apache.geronimo.security.ContextManager;
48  import org.apache.geronimo.security.IdentificationPrincipal;
49  import org.apache.geronimo.security.SubjectId;
50  import org.apache.geronimo.security.deploy.DefaultPrincipal;
51  import org.apache.geronimo.security.util.ConfigurationUtil;
52  import org.apache.geronimo.tomcat.interceptor.BeforeAfter;
53  import org.apache.geronimo.tomcat.interceptor.ComponentContextBeforeAfter;
54  import org.apache.geronimo.tomcat.interceptor.InstanceContextBeforeAfter;
55  import org.apache.geronimo.tomcat.interceptor.PolicyContextBeforeAfter;
56  import org.apache.geronimo.tomcat.util.SecurityHolder;
57  import org.apache.geronimo.tomcat.valve.DefaultSubjectValve;
58  import org.apache.geronimo.tomcat.valve.GeronimoBeforeAfterValve;
59  import org.apache.geronimo.webservices.POJOWebServiceServlet;
60  import org.apache.geronimo.webservices.WebServiceContainer;
61  import org.apache.geronimo.webservices.WebServiceContainerInvoker;
62  
63  
64  public class GeronimoStandardContext extends StandardContext {
65  
66      private static final Log log = LogFactory.getLog(GeronimoStandardContext.class);
67  
68      private static final long serialVersionUID = 3834587716552831032L;
69  
70      private Subject defaultSubject = null;
71  
72      private Map webServiceMap = null;
73  
74      private boolean pipelineInitialized;
75  
76      private BeforeAfter beforeAfter = null;
77      private int contextCount = 0;
78  
79      public void setContextProperties(TomcatContext ctx) throws DeploymentException {
80          //try to make sure this mbean properties match those of the TomcatWebAppContext
81          if (ctx instanceof TomcatWebAppContext) {
82              TomcatWebAppContext tctx = (TomcatWebAppContext) ctx;
83              setJavaVMs(tctx.getJavaVMs());
84              setServer(tctx.getServer());
85              setJ2EEApplication(tctx.getJ2EEApplication());
86              setJ2EEServer(tctx.getJ2EEServer());
87          }
88          // Create ReadOnlyContext
89          javax.naming.Context enc = null;
90          Map componentContext = ctx.getComponentContext();
91          try {
92              if (componentContext != null) {
93                  enc = EnterpriseNamingContext.createEnterpriseNamingContext(componentContext, ctx.getUserTransaction(), ctx.getKernel(), ctx.getClassLoader());
94              }
95          } catch (NamingException ne) {
96              log.error(ne);
97          }
98  
99          int index = 0;
100         BeforeAfter interceptor = new InstanceContextBeforeAfter(null, index++,
101                 ctx.getUnshareableResources(),
102                 ctx.getApplicationManagedSecurityResources(),
103                 ctx.getTrackedConnectionAssociator());
104 
105         // Set ComponentContext BeforeAfter
106         if (enc != null) {
107             interceptor = new ComponentContextBeforeAfter(interceptor, index++, enc);
108         }
109 
110         //Set a PolicyContext BeforeAfter
111         SecurityHolder securityHolder = ctx.getSecurityHolder();
112         if (securityHolder != null) {
113             if (securityHolder.getPolicyContextID() != null) {
114 
115                 PolicyContext.setContextID(securityHolder.getPolicyContextID());
116 
117                 /**
118                  * Register our default subject with the ContextManager
119                  */
120                 DefaultPrincipal defaultPrincipal = securityHolder.getDefaultPrincipal();
121                 if (defaultPrincipal != null) {
122                     defaultSubject = ConfigurationUtil.generateDefaultSubject(defaultPrincipal, ctx.getClassLoader());
123                     ContextManager.registerSubject(defaultSubject);
124                     SubjectId id = ContextManager.getSubjectId(defaultSubject);
125                     defaultSubject.getPrincipals().add(new IdentificationPrincipal(id));
126                 }
127 
128                 interceptor = new PolicyContextBeforeAfter(interceptor, index++, index++, securityHolder.getPolicyContextID());
129             }
130         }
131 
132         //Set the BeforeAfters as a valve
133         GeronimoBeforeAfterValve geronimoBAValve = new GeronimoBeforeAfterValve(interceptor, index);
134         addValve(geronimoBAValve);
135         beforeAfter = interceptor;
136         contextCount = index;
137 
138         //Not clear if user defined valves should be involved in init processing.  Probably not since
139         //request and response are null.
140 
141         addValve(new SystemMethodValve());
142 
143         // Add User Defined Valves
144         List valveChain = ctx.getValveChain();
145         if (valveChain != null) {
146             Iterator iterator = valveChain.iterator();
147             while (iterator.hasNext()) {
148                 Valve valve = (Valve) iterator.next();
149                 addValve(valve);
150             }
151         }
152 
153         CatalinaCluster cluster = ctx.getCluster();
154         if (cluster != null)
155             this.setCluster(cluster);
156 
157         Manager manager = ctx.getManager();
158         if (manager != null)
159             this.setManager(manager);
160 
161         pipelineInitialized = true;
162         this.webServiceMap = ctx.getWebServices();
163 
164         this.setCrossContext(ctx.isCrossContext());
165 
166         this.setCookies(!ctx.isDisableCookies());
167 
168         //Set the Dispatch listener
169         this.addInstanceListener("org.apache.geronimo.tomcat.listener.DispatchListener");
170     }
171 
172     public synchronized void start() throws LifecycleException {
173         if (pipelineInitialized) {
174             try {
175                 Valve valve = getFirst();
176                 valve.invoke(null, null);
177                 //Install the DefaultSubjectValve after the authentication valve so the default subject is supplied
178                 //only if no real subject is authenticated.
179 
180                 Valve defaultSubjectValve = new DefaultSubjectValve(defaultSubject);
181                 addValve(defaultSubjectValve);
182             } catch (IOException e) {
183                 if (e.getCause() instanceof LifecycleException) {
184                     throw (LifecycleException) e.getCause();
185                 }
186                 throw new LifecycleException(e);
187             } catch (ServletException e) {
188                 throw new LifecycleException(e);
189             }
190         } else
191             super.start();
192     }
193 
194     public synchronized void stop() throws LifecycleException {
195         // Remove the defaultSubject
196         if (defaultSubject != null) {
197             ContextManager.unregisterSubject(defaultSubject);
198         }
199 
200         super.stop();
201     }
202 
203     public void addChild(Container child) {
204         Wrapper wrapper = (Wrapper) child;
205 
206         String servletClassName = wrapper.getServletClass();
207         if (servletClassName == null) {
208             super.addChild(child);
209             return;
210         }
211 
212         ClassLoader cl = this.getParentClassLoader();
213 
214         Class baseServletClass;
215         Class servletClass;
216         try {
217             baseServletClass = cl.loadClass(Servlet.class.getName());
218             servletClass = cl.loadClass(servletClassName);
219             //Check if the servlet is of type Servlet class
220             if (!baseServletClass.isAssignableFrom(servletClass)) {
221                 //Nope - its probably a webservice, so lets see...
222                 if (webServiceMap != null) {
223                     WebServiceContainer webServiceContainer = (WebServiceContainer) webServiceMap.get(wrapper.getName());
224 
225                     if (webServiceContainer != null) {
226                         //Yep its a web service
227                         //So swap it out with a POJOWebServiceServlet
228                         wrapper.setServletClass("org.apache.geronimo.webservices.POJOWebServiceServlet");
229 
230                         //Set the WebServiceContainer stuff
231                         String webServicecontainerID = wrapper.getName() + WebServiceContainerInvoker.WEBSERVICE_CONTAINER + webServiceContainer.hashCode();
232                         getServletContext().setAttribute(webServicecontainerID, webServiceContainer);
233                         wrapper.addInitParameter(WebServiceContainerInvoker.WEBSERVICE_CONTAINER, webServicecontainerID);
234 
235                         //Set the SEI Class in the attribute
236                         String pojoClassID = wrapper.getName() + POJOWebServiceServlet.POJO_CLASS + servletClass.hashCode();
237                         getServletContext().setAttribute(pojoClassID, servletClass);
238                         wrapper.addInitParameter(POJOWebServiceServlet.POJO_CLASS, pojoClassID);
239                     }
240                 }
241             }
242         } catch (ClassNotFoundException e) {
243             throw new RuntimeException(e.getMessage(), e);
244         }
245 
246         super.addChild(child);
247     }
248 
249     public synchronized void setLoader(final Loader delegate) {
250         Loader loader = new Loader() {
251 
252             public void backgroundProcess() {
253                 delegate.backgroundProcess();
254             }
255 
256             public ClassLoader getClassLoader() {
257                 // Implementation Note: the actual CL to be used by this 
258                 // context is the Geronimo one and not the Tomcat one.
259                 return parentClassLoader;
260             }
261 
262             public Container getContainer() {
263                 return delegate.getContainer();
264             }
265 
266             public void setContainer(Container container) {
267                 delegate.setContainer(container);
268             }
269 
270             public boolean getDelegate() {
271                 return delegate.getDelegate();
272             }
273 
274             public void setDelegate(boolean delegateBoolean) {
275                 delegate.setDelegate(delegateBoolean);
276             }
277 
278             public String getInfo() {
279                 return delegate.getInfo();
280             }
281 
282             public boolean getReloadable() {
283                 return false;
284             }
285 
286             public void setReloadable(boolean reloadable) {
287                 if (reloadable) {
288                     throw new UnsupportedOperationException("Reloadable context is not supported.");
289                 }
290             }
291 
292             public void addPropertyChangeListener(PropertyChangeListener listener) {
293                 delegate.addPropertyChangeListener(listener);
294             }
295 
296             public void addRepository(String repository) {
297                 delegate.addRepository(repository);
298             }
299 
300             public String[] findRepositories() {
301                 return delegate.findRepositories();
302             }
303 
304             public boolean modified() {
305                 return delegate.modified();
306             }
307 
308             public void removePropertyChangeListener(PropertyChangeListener listener) {
309                 delegate.removePropertyChangeListener(listener);
310             }
311         };
312 
313         super.setLoader(loader);
314     }
315 
316     private class SystemMethodValve extends ValveBase {
317 
318         public void invoke(Request request, Response response) throws IOException, ServletException {
319             if (request == null && response == null) {
320                 try {
321                     GeronimoStandardContext.super.start();
322                 } catch (LifecycleException e) {
323                     throw (IOException) new IOException("wrapping lifecycle exception").initCause(e);
324                 }
325             } else {
326                 getNext().invoke(request, response);
327             }
328 
329         }
330     }
331 
332 
333     public BeforeAfter getBeforeAfter() {
334         return beforeAfter;
335     }
336 
337     public int getContextCount() {
338         return contextCount;
339     }
340 
341 }