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