001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.tomcat.deployment;
019    
020    import static java.lang.Boolean.FALSE;
021    import static java.lang.Boolean.TRUE;
022    
023    import java.io.File;
024    import java.io.FileNotFoundException;
025    import java.io.FileWriter;
026    import java.io.IOException;
027    import java.net.URL;
028    import java.security.PermissionCollection;
029    import java.util.Collection;
030    import java.util.HashMap;
031    import java.util.Map;
032    import java.util.Set;
033    import java.util.jar.JarFile;
034    
035    import javax.servlet.Servlet;
036    
037    import org.apache.commons.logging.Log;
038    import org.apache.commons.logging.LogFactory;
039    import org.apache.geronimo.common.DeploymentException;
040    import org.apache.geronimo.deployment.ModuleIDBuilder;
041    import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
042    import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
043    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
044    import org.apache.geronimo.deployment.util.DeploymentUtil;
045    import org.apache.geronimo.deployment.xbeans.EnvironmentType;
046    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
047    import org.apache.geronimo.gbean.AbstractName;
048    import org.apache.geronimo.gbean.AbstractNameQuery;
049    import org.apache.geronimo.gbean.GBeanData;
050    import org.apache.geronimo.gbean.GBeanInfo;
051    import org.apache.geronimo.gbean.GBeanInfoBuilder;
052    import org.apache.geronimo.gbean.ReferencePatterns;
053    import org.apache.geronimo.gbean.GBeanLifecycle;
054    import org.apache.geronimo.j2ee.deployment.EARContext;
055    import org.apache.geronimo.j2ee.deployment.Module;
056    import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
057    import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
058    import org.apache.geronimo.j2ee.deployment.NamingBuilder;
059    import org.apache.geronimo.j2ee.deployment.WebModule;
060    import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
061    import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedWebApp;
062    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
063    import org.apache.geronimo.kernel.Kernel;
064    import org.apache.geronimo.kernel.Naming;
065    import org.apache.geronimo.kernel.config.ConfigurationData;
066    import org.apache.geronimo.kernel.repository.Environment;
067    import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
068    import org.apache.geronimo.naming.deployment.GBeanResourceEnvironmentBuilder;
069    import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
070    import org.apache.geronimo.security.jacc.ComponentPermissions;
071    import org.apache.geronimo.tomcat.LifecycleListenerGBean;
072    import org.apache.geronimo.tomcat.ManagerGBean;
073    import org.apache.geronimo.tomcat.RealmGBean;
074    import org.apache.geronimo.tomcat.TomcatWebAppContext;
075    import org.apache.geronimo.tomcat.ValveGBean;
076    import org.apache.geronimo.tomcat.cluster.CatalinaClusterGBean;
077    import org.apache.geronimo.tomcat.util.SecurityHolder;
078    import org.apache.geronimo.web.deployment.GenericToSpecificPlanConverter;
079    import org.apache.geronimo.web25.deployment.AbstractWebModuleBuilder;
080    import org.apache.geronimo.xbeans.geronimo.j2ee.GerClusteringDocument;
081    import org.apache.geronimo.xbeans.geronimo.web.tomcat.TomcatWebAppDocument;
082    import org.apache.geronimo.xbeans.geronimo.web.tomcat.TomcatWebAppType;
083    import org.apache.geronimo.xbeans.geronimo.web.tomcat.config.GerTomcatDocument;
084    import org.apache.geronimo.xbeans.javaee.EjbLocalRefType;
085    import org.apache.geronimo.xbeans.javaee.EjbRefType;
086    import org.apache.geronimo.xbeans.javaee.EnvEntryType;
087    import org.apache.geronimo.xbeans.javaee.LifecycleCallbackType;
088    import org.apache.geronimo.xbeans.javaee.MessageDestinationRefType;
089    import org.apache.geronimo.xbeans.javaee.MessageDestinationType;
090    import org.apache.geronimo.xbeans.javaee.PersistenceContextRefType;
091    import org.apache.geronimo.xbeans.javaee.PersistenceUnitRefType;
092    import org.apache.geronimo.xbeans.javaee.ResourceEnvRefType;
093    import org.apache.geronimo.xbeans.javaee.ResourceRefType;
094    import org.apache.geronimo.xbeans.javaee.ServiceRefType;
095    import org.apache.geronimo.xbeans.javaee.ServletType;
096    import org.apache.geronimo.xbeans.javaee.WebAppDocument;
097    import org.apache.geronimo.xbeans.javaee.WebAppType;
098    import org.apache.xmlbeans.XmlCursor;
099    import org.apache.xmlbeans.XmlException;
100    import org.apache.xmlbeans.XmlObject;
101    import org.apache.xmlbeans.XmlOptions;
102    
103    /**
104     * @version $Rev:385659 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
105     */
106    public class TomcatModuleBuilder extends AbstractWebModuleBuilder implements GBeanLifecycle {
107    
108        private static final Log log = LogFactory.getLog(TomcatModuleBuilder.class);
109    
110        private static final String TOMCAT_NAMESPACE = TomcatWebAppDocument.type.getDocumentElementName().getNamespaceURI();
111        private static final String IS_JAVAEE = "IS_JAVAEE";
112        private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>();
113        static {
114            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
115            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-1.1", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
116            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-1.2", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
117            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-2.0", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
118            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/tomcat", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
119            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-1.1", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
120            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-1.2", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
121            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
122            NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/tomcat/config", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat/config-1.0");
123        }
124    
125        private final Environment defaultEnvironment;
126        private final AbstractNameQuery tomcatContainerName;
127        protected final NamespaceDrivenBuilderCollection clusteringBuilders;
128    
129        public TomcatModuleBuilder(Environment defaultEnvironment,
130                AbstractNameQuery tomcatContainerName,
131                Collection<WebServiceBuilder> webServiceBuilder,
132                Collection securityBuilders,
133                Collection serviceBuilders,
134                NamingBuilder namingBuilders,
135                Collection<NamespaceDrivenBuilder> clusteringBuilders,
136                Collection<ModuleBuilderExtension> moduleBuilderExtensions,
137                ResourceEnvironmentSetter resourceEnvironmentSetter,
138                Kernel kernel) {
139            super(kernel, securityBuilders, serviceBuilders, namingBuilders, resourceEnvironmentSetter, webServiceBuilder, moduleBuilderExtensions);
140            this.defaultEnvironment = defaultEnvironment;
141            this.clusteringBuilders = new NamespaceDrivenBuilderCollection(clusteringBuilders, GerClusteringDocument.type.getDocumentElementName());
142            this.tomcatContainerName = tomcatContainerName;
143        }
144    
145        public void doStart() throws Exception {
146            XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES);
147        }
148    
149        public void doStop() {
150            XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES);
151        }
152    
153        public void doFail() {
154            doStop();
155        }
156    
157        protected Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, boolean standAlone, String contextRoot, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
158            assert moduleFile != null : "moduleFile is null";
159            assert targetPath != null : "targetPath is null";
160            assert !targetPath.endsWith("/") : "targetPath must not end with a '/'";
161    
162            // parse the spec dd
163            String specDD = null;
164            WebAppType webApp = null;
165            Boolean isJavaee;
166            try {
167                if (specDDUrl == null) {
168                    specDDUrl = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/web.xml");
169                }
170    
171                // read in the entire specDD as a string, we need this for getDeploymentDescriptor
172                // on the J2ee management object
173                specDD = DeploymentUtil.readAll(specDDUrl);
174    
175                // we found web.xml, if it won't parse that's an error.
176                XmlObject parsed = XmlBeansUtil.parse(specDD);
177                //Dont save updated xml if it isn't javaee
178                XmlCursor cursor = parsed.newCursor();
179                try {
180                    cursor.toStartDoc();
181                    cursor.toFirstChild();
182                    isJavaee = "http://java.sun.com/xml/ns/javaee".equals(cursor.getName().getNamespaceURI());
183                } finally {
184                    cursor.dispose();
185                }
186                WebAppDocument webAppDoc = convertToServletSchema(parsed);
187                webApp = webAppDoc.getWebApp();
188                check(webApp);
189            } catch (XmlException e) {
190                // Output the target path in the error to make it clearer to the user which webapp
191                // has the problem.  The targetPath is used, as moduleFile may have an unhelpful
192                // value such as C:\geronimo-1.1\var\temp\geronimo-deploymentUtil22826.tmpdir
193                throw new DeploymentException("Error parsing web.xml for " + targetPath, e);
194            } catch (Exception e) {
195                if (!moduleFile.getName().endsWith(".war")) {
196                    //not for us
197                    return null;
198                }
199                isJavaee = true;
200                //else ignore as jee5 allows optional spec dd for .war's
201            }
202    
203            if (webApp == null)
204                webApp = WebAppType.Factory.newInstance();
205    
206            // parse vendor dd
207            TomcatWebAppType tomcatWebApp = getTomcatWebApp(plan, moduleFile, standAlone, targetPath, webApp);
208            contextRoot = getContextRoot(tomcatWebApp, contextRoot, webApp, standAlone, moduleFile, targetPath);
209    
210            EnvironmentType environmentType = tomcatWebApp.getEnvironment();
211            Environment environment = EnvironmentBuilder.buildEnvironment(environmentType, defaultEnvironment);
212    
213            Boolean distributable = webApp.getDistributableArray().length == 1 ? TRUE : FALSE;
214            if (TRUE == distributable) {
215                clusteringBuilders.buildEnvironment(tomcatWebApp, environment);
216            }
217            
218            // Note: logic elsewhere depends on the default artifact ID being the file name less extension (ConfigIDExtractor)
219            String warName = "";
220            File temp = new File(moduleFile.getName());
221            if (temp.isFile()) {
222                warName = temp.getName();
223                if (warName.lastIndexOf('.') > -1) {
224                    warName = warName.substring(0, warName.lastIndexOf('.'));
225                }
226            } else {
227                try {
228                    warName = temp.getCanonicalFile().getName();
229                    if (warName.equals("")) {
230                        // Root directory
231                        warName = "$root-dir$";
232                    }
233                } catch (IOException e) {
234                    //really?
235                }
236            }
237            idBuilder.resolve(environment, warName, "war");
238    
239            AbstractName moduleName;
240            if (earName == null) {
241                earName = naming.createRootName(environment.getConfigId(), NameFactory.NULL, NameFactory.J2EE_APPLICATION);
242                moduleName = naming.createChildName(earName, environment.getConfigId().toString(), NameFactory.WEB_MODULE);
243            } else {
244                moduleName = naming.createChildName(earName, targetPath, NameFactory.WEB_MODULE);
245            }
246    
247            // Create the AnnotatedApp interface for the WebModule
248            AnnotatedWebApp annotatedWebApp = new AnnotatedWebApp(webApp);
249    
250            WebModule module = new WebModule(standAlone, moduleName, environment, moduleFile, targetPath, webApp, tomcatWebApp, specDD, contextRoot, TOMCAT_NAMESPACE, annotatedWebApp);
251            for (ModuleBuilderExtension mbe : moduleBuilderExtensions) {
252                mbe.createModule(module, plan, moduleFile, targetPath, specDDUrl, environment, contextRoot, earName, naming, idBuilder);
253            }
254            module.getSharedContext().put(IS_JAVAEE, isJavaee);
255            return module;
256        }
257    
258        private String getContextRoot(TomcatWebAppType tomcatWebApp, String contextRoot, WebAppType webApp, boolean standAlone, JarFile moduleFile, String targetPath) {
259            //If we have a context root, override everything
260            if (tomcatWebApp.isSetContextRoot()) {
261                contextRoot = tomcatWebApp.getContextRoot();
262            } else if (contextRoot == null || contextRoot.trim().equals("")) {
263                //Otherwise if no contextRoot was passed in from the ear, then make up a default
264                contextRoot = determineDefaultContextRoot(webApp, standAlone, moduleFile, targetPath);
265            }
266            contextRoot = contextRoot.trim();
267            if (contextRoot.length() > 0) {
268                // only force the context root to start with a forward slash
269                // if it is not null
270                if (!contextRoot.startsWith("/")) {
271                    //I'm not sure if we should always fix up peculiar context roots.
272                    contextRoot = "/" + contextRoot;
273                }
274            }
275            return contextRoot;
276        }
277    
278    
279        TomcatWebAppType getTomcatWebApp(Object plan, JarFile moduleFile, boolean standAlone, String targetPath, WebAppType webApp) throws DeploymentException {
280            XmlObject rawPlan = null;
281            try {
282                // load the geronimo-web.xml from either the supplied plan or from the earFile
283                try {
284                    if (plan instanceof XmlObject) {
285                        rawPlan = (XmlObject) plan;
286                    } else {
287                        if (plan != null) {
288                            rawPlan = XmlBeansUtil.parse(((File) plan).toURL(), getClass().getClassLoader());
289                        } else {
290                            URL path = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/geronimo-web.xml");
291                            try {
292                                rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
293                            } catch (FileNotFoundException e) {
294                                path = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/geronimo-tomcat.xml");
295                                try {
296                                    rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
297                                } catch (FileNotFoundException e1) {
298                                    log.warn("Web application " + targetPath + " does not contain a WEB-INF/geronimo-web.xml deployment plan.  This may or may not be a problem, depending on whether you have things like resource references that need to be resolved.  You can also give the deployer a separate deployment plan file on the command line.");
299                                }
300                            }
301                        }
302                    }
303                } catch (IOException e) {
304                    log.warn(e);
305                }
306    
307                TomcatWebAppType tomcatWebApp;
308                if (rawPlan != null) {
309                    XmlObject webPlan = new GenericToSpecificPlanConverter(GerTomcatDocument.type.getDocumentElementName().getNamespaceURI(),
310                            TomcatWebAppDocument.type.getDocumentElementName().getNamespaceURI(), "tomcat").convertToSpecificPlan(rawPlan);
311                    tomcatWebApp = (TomcatWebAppType) webPlan.changeType(TomcatWebAppType.type);
312                    XmlBeansUtil.validateDD(tomcatWebApp);
313                } else {
314                    tomcatWebApp = createDefaultPlan();
315                }
316                return tomcatWebApp;
317            } catch (XmlException e) {
318                throw new DeploymentException("xml problem for web app " + targetPath, e);
319            }
320        }
321    
322        private TomcatWebAppType createDefaultPlan() {
323            return TomcatWebAppType.Factory.newInstance();
324        }
325    
326    
327        public void initContext(EARContext earContext, Module module, ClassLoader cl) throws DeploymentException {
328            TomcatWebAppType gerWebApp = (TomcatWebAppType) module.getVendorDD();
329            boolean hasSecurityRealmName = gerWebApp.isSetSecurityRealmName();
330            basicInitContext(earContext, module, gerWebApp, hasSecurityRealmName);
331            for (ModuleBuilderExtension mbe : moduleBuilderExtensions) {
332                mbe.initContext(earContext, module, cl);
333            }
334        }
335    
336        public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repository) throws DeploymentException {
337            EARContext moduleContext = module.getEarContext();
338            ClassLoader webClassLoader = moduleContext.getClassLoader();
339            AbstractName moduleName = moduleContext.getModuleName();
340            WebModule webModule = (WebModule) module;
341    
342            WebAppType webApp = (WebAppType) webModule.getSpecDD();
343    
344            TomcatWebAppType tomcatWebApp = (TomcatWebAppType) webModule.getVendorDD();
345    
346            GBeanData webModuleData = new GBeanData(moduleName, TomcatWebAppContext.GBEAN_INFO);
347            configureBasicWebModuleAttributes(webApp, tomcatWebApp, moduleContext, earContext, webModule, webModuleData);
348            try {
349                moduleContext.addGBean(webModuleData);
350                Set<String> securityRoles = collectRoleNames(webApp);
351                Map<String, PermissionCollection> rolePermissions = new HashMap<String, PermissionCollection>();
352                webModuleData.setAttribute("contextPath", webModule.getContextRoot());
353                // unsharableResources, applicationManagedSecurityResources
354                GBeanResourceEnvironmentBuilder rebuilder = new GBeanResourceEnvironmentBuilder(webModuleData);
355                //N.B. use earContext not moduleContext
356                resourceEnvironmentSetter.setResourceEnvironment(rebuilder, webApp.getResourceRefArray(), tomcatWebApp.getResourceRefArray());
357    
358                if (tomcatWebApp.isSetWebContainer()) {
359                    AbstractNameQuery webContainerName = ENCConfigBuilder.getGBeanQuery(NameFactory.GERONIMO_SERVICE, tomcatWebApp.getWebContainer());
360                    webModuleData.setReferencePattern("Container", webContainerName);
361                } else {
362                    webModuleData.setReferencePattern("Container", tomcatContainerName);
363                }
364                // Process the Tomcat container-config elements
365                if (tomcatWebApp.isSetHost()) {
366                    String virtualServer = tomcatWebApp.getHost().trim();
367                    webModuleData.setAttribute("virtualServer", virtualServer);
368                }
369                if (tomcatWebApp.isSetCrossContext()) {
370                    webModuleData.setAttribute("crossContext", Boolean.TRUE);
371                }
372                if (tomcatWebApp.isSetWorkDir()) {
373                    String workDir = tomcatWebApp.getWorkDir();
374                    webModuleData.setAttribute("workDir", workDir);
375                }
376                if (tomcatWebApp.isSetDisableCookies()) {
377                    webModuleData.setAttribute("disableCookies", Boolean.TRUE);
378                }
379                if (tomcatWebApp.isSetTomcatRealm()) {
380                    String tomcatRealm = tomcatWebApp.getTomcatRealm().trim();
381                    AbstractName realmName = earContext.getNaming().createChildName(moduleName, tomcatRealm, RealmGBean.GBEAN_INFO.getJ2eeType());
382                    webModuleData.setReferencePattern("TomcatRealm", realmName);
383                }
384                if (tomcatWebApp.isSetValveChain()) {
385                    String valveChain = tomcatWebApp.getValveChain().trim();
386                    AbstractName valveName = earContext.getNaming().createChildName(moduleName, valveChain, ValveGBean.J2EE_TYPE);
387                    webModuleData.setReferencePattern("TomcatValveChain", valveName);
388                }
389                
390                if (tomcatWebApp.isSetListenerChain()) {
391                    String listenerChain = tomcatWebApp.getListenerChain().trim();
392                    AbstractName listenerName = earContext.getNaming().createChildName(moduleName, listenerChain, LifecycleListenerGBean.J2EE_TYPE);
393                    webModuleData.setReferencePattern("LifecycleListenerChain", listenerName);
394                }
395    
396                if (tomcatWebApp.isSetCluster()) {
397                    String cluster = tomcatWebApp.getCluster().trim();
398                    AbstractName clusterName = earContext.getNaming().createChildName(moduleName, cluster, CatalinaClusterGBean.J2EE_TYPE);
399                    webModuleData.setReferencePattern("Cluster", clusterName);
400                }
401    
402                if (tomcatWebApp.isSetManager()) {
403                    String manager = tomcatWebApp.getManager().trim();
404                    AbstractName managerName = earContext.getNaming().createChildName(moduleName, manager, ManagerGBean.J2EE_TYPE);
405                    webModuleData.setReferencePattern("Manager", managerName);
406                }
407                
408                Boolean distributable = webApp.getDistributableArray().length == 1 ? TRUE : FALSE;
409                if (TRUE == distributable) {
410                    clusteringBuilders.build(tomcatWebApp, earContext, moduleContext);
411                    if (null == webModuleData.getReferencePatterns(TomcatWebAppContext.GBEAN_REF_CLUSTERED_VALVE_RETRIEVER)) {
412                        log.warn("No clustering builders configured: app will not be clustered");
413                    }
414                }
415    
416                //Handle the role permissions and webservices on the servlets.
417                ServletType[] servletTypes = webApp.getServletArray();
418                Map<String, AbstractName> webServices = new HashMap<String, AbstractName>();
419                Class baseServletClass;
420                try {
421                    baseServletClass = webClassLoader.loadClass(Servlet.class.getName());
422                } catch (ClassNotFoundException e) {
423                    throw new DeploymentException("Could not load javax.servlet.Servlet in web classloader", e); // TODO identify web app in message
424                }
425                for (ServletType servletType : servletTypes) {
426                    //Handle the Role Ref Permissions
427                    processRoleRefPermissions(servletType, securityRoles, rolePermissions);
428    
429                    if (servletType.isSetServletClass()) {
430                        String servletName = servletType.getServletName().getStringValue().trim();
431                        String servletClassName = servletType.getServletClass().getStringValue().trim();
432                        Class servletClass;
433                        try {
434                            servletClass = webClassLoader.loadClass(servletClassName);
435                        } catch (ClassNotFoundException e) {
436                            throw new DeploymentException("Could not load servlet class " + servletClassName, e); // TODO identify web app in message
437                        }
438                        if (!baseServletClass.isAssignableFrom(servletClass)) {
439                            //fake servletData
440                            AbstractName servletAbstractName = moduleContext.getNaming().createChildName(moduleName, servletName, NameFactory.SERVLET);
441                            GBeanData servletData = new GBeanData();
442                            servletData.setAbstractName(servletAbstractName);
443                            //let the web service builder deal with configuring the gbean with the web service stack
444                            //Here we just extract the factory reference
445                            boolean configured = false;
446                            for (WebServiceBuilder serviceBuilder : webServiceBuilder) {
447                                if (serviceBuilder.configurePOJO(servletData, servletName, module, servletClassName, moduleContext)) {
448                                    configured = true;
449                                    break;
450                                }
451                            }
452                            if (!configured) {
453                                throw new DeploymentException("POJO web service: " + servletName + " not configured by any web service builder");
454                            }
455                            ReferencePatterns patterns = servletData.getReferencePatterns("WebServiceContainerFactory");
456                            AbstractName wsContainerFactoryName = patterns.getAbstractName();
457                            webServices.put(servletName, wsContainerFactoryName);
458                            //force all the factories to start before the web app that needs them.
459                            webModuleData.addDependency(wsContainerFactoryName);
460                        }
461    
462                    }
463                }
464    
465                // JACC v1.0 secion B.19
466                addUnmappedJSPPermissions(securityRoles, rolePermissions);
467    
468                webModuleData.setAttribute("webServices", webServices);
469    
470                if (tomcatWebApp.isSetSecurityRealmName()) {
471                    if (earContext.getSecurityConfiguration() == null) {
472                        throw new DeploymentException("You have specified a <security-realm-name> for the webapp " + moduleName + " but no <security> configuration (role mapping) is supplied in the Geronimo plan for the web application (or the Geronimo plan for the EAR if the web app is in an EAR)");
473                    }
474    
475                    SecurityHolder securityHolder = new SecurityHolder();
476                    securityHolder.setSecurityRealm(tomcatWebApp.getSecurityRealmName().trim());
477    
478                    webModuleData.setReferencePattern("RunAsSource", earContext.getJaccManagerName());
479    
480                    /**
481                     * TODO - go back to commented version when possible.
482                     */
483                    String policyContextID = moduleName.toString().replaceAll("[, :]", "_");
484                    securityHolder.setPolicyContextID(policyContextID);
485    
486                    ComponentPermissions componentPermissions = buildSpecSecurityConfig(webApp, securityRoles, rolePermissions);
487                    earContext.addSecurityContext(policyContextID, componentPermissions);
488                    //TODO WTF is this for?
489                    securityHolder.setSecurity(true);
490    
491                    webModuleData.setAttribute("securityHolder", securityHolder);
492                }
493    
494                //listeners added directly to the StandardContext will get loaded by the tomcat classloader, not the app classloader!
495                //TODO this may definitely not be the best place for this!
496                for (ModuleBuilderExtension mbe : moduleBuilderExtensions) {
497                    mbe.addGBeans(earContext, module, cl, repository);
498                }
499                //not truly metadata complete until MBEs have run
500                if (!webApp.getMetadataComplete()) {
501                    webApp.setMetadataComplete(true);
502                    module.setOriginalSpecDD(module.getSpecDD().toString());
503                }
504                webModuleData.setAttribute("deploymentDescriptor", module.getOriginalSpecDD());
505                /**
506                 * This next bit of code is kind of a kludge to get Tomcat to get a default
507                 * web.xml if one does not exist.  This is primarily for jaxws.  This code is
508                 * necessary because Tomcat either has a bug or there is a problem dynamically
509                 * adding a wrapper to an already running context.  Although the wrapper
510                 * can be added, the url mappings do not get picked up at the proper level
511                 * and therefore Tomcat cannot dispatch the request.  Hence, creating and
512                 * writing out a web.xml to the deployed location is the only way around this
513                 * until Tomcat fixes that bug.
514                 *
515                 * For myfaces/jsf, the spec dd may have been updated with a listener.  So, we need to write it out again whether or not
516                 * there originally was one. This might not work on windows due to file locking problems.
517                 */
518    
519                if ((Boolean)module.getSharedContext().get(IS_JAVAEE)) {
520                    WebAppType shortWebApp = (WebAppType) webApp.copy();
521                    shortWebApp.setEjbLocalRefArray(new EjbLocalRefType[0]);
522                    shortWebApp.setEjbRefArray(new EjbRefType[0]);
523                    shortWebApp.setEnvEntryArray(new EnvEntryType[0]);
524                    shortWebApp.setMessageDestinationArray(new MessageDestinationType[0]);
525                    shortWebApp.setMessageDestinationRefArray(new MessageDestinationRefType[0]);
526                    shortWebApp.setPersistenceContextRefArray(new PersistenceContextRefType[0]);
527                    shortWebApp.setPersistenceUnitRefArray(new PersistenceUnitRefType[0]);
528                    shortWebApp.setPostConstructArray(new LifecycleCallbackType[0]);
529                    shortWebApp.setPreDestroyArray(new LifecycleCallbackType[0]);
530                    shortWebApp.setResourceEnvRefArray(new ResourceEnvRefType[0]);
531                    shortWebApp.setResourceRefArray(new ResourceRefType[0]);
532                    shortWebApp.setServiceRefArray(new ServiceRefType[0]);
533                    // TODO Tomcat will fail web services tck tests if the following security settings are set in shortWebApp
534                    // need to figure out why...
535                    //One clue is that without this stuff tomcat does not install an authenticator.... so there's no security
536    //                 shortWebApp.setSecurityConstraintArray(new SecurityConstraintType[0]);
537    //                 shortWebApp.setSecurityRoleArray(new SecurityRoleType[0]);
538                    File webXml = new File(moduleContext.getBaseDir(), "/WEB-INF/web.xml");
539                    File inPlaceDir = moduleContext.getInPlaceConfigurationDir();
540                    if (inPlaceDir != null) {
541                        webXml = new File(inPlaceDir, "/WEB-INF/web.xml");
542                    }
543    //        boolean webXmlExists = (inPlaceDir != null && new File(inPlaceDir,"/WEB-INF/web.xml").exists()) || webXml.exists();
544    //        if (!webXmlExists) {
545                    webXml.getParentFile().mkdirs();
546                    try {
547                        FileWriter outFile = new FileWriter(webXml);
548    
549                        XmlOptions opts = new XmlOptions();
550                        opts.setSaveAggressiveNamespaces();
551                        opts.setSaveSyntheticDocumentElement(WebAppDocument.type.getDocumentElementName());
552                        opts.setUseDefaultNamespace();
553                        opts.setSavePrettyPrint();
554    
555        //                WebAppDocument doc = WebAppDocument.Factory.newInstance();
556        //                doc.setWebApp(webApp);
557    
558                        outFile.write(shortWebApp.xmlText(opts));
559                        outFile.flush();
560                        outFile.close();
561                    } catch (Exception e) {
562                        throw new DeploymentException(e);
563                    }
564    //        }
565                }
566    
567                if (!module.isStandAlone()) {
568                    ConfigurationData moduleConfigurationData = moduleContext.getConfigurationData();
569                    earContext.addChildConfiguration(module.getTargetPath(), moduleConfigurationData);
570                }
571            } catch (DeploymentException de) {
572                throw de;
573            } catch (Exception e) {
574                throw new DeploymentException("Unable to initialize GBean for web app " + module.getName(), e);
575            }
576        }
577    
578        public String getSchemaNamespace() {
579            return TOMCAT_NAMESPACE;
580        }
581    
582    
583        public static final GBeanInfo GBEAN_INFO;
584        public static final String GBEAN_REF_CLUSTERING_BUILDERS = "ClusteringBuilders";
585    
586        static {
587            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(TomcatModuleBuilder.class, NameFactory.MODULE_BUILDER);
588            infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
589            infoBuilder.addAttribute("tomcatContainerName", AbstractNameQuery.class, true, true);
590            infoBuilder.addReference("WebServiceBuilder", WebServiceBuilder.class, NameFactory.MODULE_BUILDER);
591            infoBuilder.addReference("SecurityBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
592            infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
593            infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER);
594            infoBuilder.addReference(GBEAN_REF_CLUSTERING_BUILDERS, NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
595            infoBuilder.addReference("ModuleBuilderExtensions", ModuleBuilderExtension.class, NameFactory.MODULE_BUILDER);
596            infoBuilder.addReference("ResourceEnvironmentSetter", ResourceEnvironmentSetter.class, NameFactory.MODULE_BUILDER);
597            infoBuilder.addAttribute("kernel", Kernel.class, false);
598            infoBuilder.addInterface(ModuleBuilder.class);
599    
600            infoBuilder.setConstructor(new String[]{
601                    "defaultEnvironment",
602                    "tomcatContainerName",
603                    "WebServiceBuilder",
604                    "SecurityBuilders",
605                    "ServiceBuilders",
606                    "NamingBuilders",
607                    GBEAN_REF_CLUSTERING_BUILDERS,
608                    "ModuleBuilderExtensions",
609                    "ResourceEnvironmentSetter",
610                    "kernel"});
611            GBEAN_INFO = infoBuilder.getBeanInfo();
612        }
613    
614        public static GBeanInfo getGBeanInfo() {
615            return GBEAN_INFO;
616        }
617    
618    }