001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.geronimo.tomcat;
019
020 import java.beans.PropertyChangeListener;
021 import java.io.IOException;
022 import java.util.Iterator;
023 import java.util.List;
024 import java.util.Map;
025
026 import javax.naming.NamingException;
027 import javax.security.auth.Subject;
028 import javax.security.jacc.PolicyContext;
029 import javax.servlet.Servlet;
030 import javax.servlet.ServletException;
031
032 import org.apache.catalina.Container;
033 import org.apache.catalina.LifecycleException;
034 import org.apache.catalina.Loader;
035 import org.apache.catalina.Manager;
036 import org.apache.catalina.Valve;
037 import org.apache.catalina.Wrapper;
038 import org.apache.catalina.cluster.CatalinaCluster;
039 import org.apache.catalina.connector.Request;
040 import org.apache.catalina.connector.Response;
041 import org.apache.catalina.core.StandardContext;
042 import org.apache.catalina.valves.ValveBase;
043 import org.apache.commons.logging.Log;
044 import org.apache.commons.logging.LogFactory;
045 import org.apache.geronimo.common.DeploymentException;
046 import org.apache.geronimo.naming.enc.EnterpriseNamingContext;
047 import org.apache.geronimo.security.ContextManager;
048 import org.apache.geronimo.security.IdentificationPrincipal;
049 import org.apache.geronimo.security.SubjectId;
050 import org.apache.geronimo.security.deploy.DefaultPrincipal;
051 import org.apache.geronimo.security.util.ConfigurationUtil;
052 import org.apache.geronimo.tomcat.interceptor.BeforeAfter;
053 import org.apache.geronimo.tomcat.interceptor.ComponentContextBeforeAfter;
054 import org.apache.geronimo.tomcat.interceptor.InstanceContextBeforeAfter;
055 import org.apache.geronimo.tomcat.interceptor.PolicyContextBeforeAfter;
056 import org.apache.geronimo.tomcat.util.SecurityHolder;
057 import org.apache.geronimo.tomcat.valve.DefaultSubjectValve;
058 import org.apache.geronimo.tomcat.valve.GeronimoBeforeAfterValve;
059 import org.apache.geronimo.webservices.POJOWebServiceServlet;
060 import org.apache.geronimo.webservices.WebServiceContainer;
061 import org.apache.geronimo.webservices.WebServiceContainerInvoker;
062
063
064 public class GeronimoStandardContext extends StandardContext {
065
066 private static final Log log = LogFactory.getLog(GeronimoStandardContext.class);
067
068 private static final long serialVersionUID = 3834587716552831032L;
069
070 private Subject defaultSubject = null;
071
072 private Map webServiceMap = null;
073
074 private boolean pipelineInitialized;
075
076 private BeforeAfter beforeAfter = null;
077 private int contextCount = 0;
078
079 public void setContextProperties(TomcatContext ctx) throws DeploymentException {
080 //try to make sure this mbean properties match those of the TomcatWebAppContext
081 if (ctx instanceof TomcatWebAppContext) {
082 TomcatWebAppContext tctx = (TomcatWebAppContext) ctx;
083 setJavaVMs(tctx.getJavaVMs());
084 setServer(tctx.getServer());
085 setJ2EEApplication(tctx.getJ2EEApplication());
086 setJ2EEServer(tctx.getJ2EEServer());
087 }
088 // Create ReadOnlyContext
089 javax.naming.Context enc = null;
090 Map componentContext = ctx.getComponentContext();
091 try {
092 if (componentContext != null) {
093 enc = EnterpriseNamingContext.createEnterpriseNamingContext(componentContext, ctx.getUserTransaction(), ctx.getKernel(), ctx.getClassLoader());
094 }
095 } catch (NamingException ne) {
096 log.error(ne);
097 }
098
099 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 }