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    }