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    
019    package org.apache.geronimo.jetty.deployment;
020    
021    import java.io.File;
022    import java.io.FileNotFoundException;
023    import java.io.IOException;
024    import java.net.URL;
025    import java.security.Permission;
026    import java.security.PermissionCollection;
027    import java.security.Permissions;
028    import java.util.ArrayList;
029    import java.util.Collection;
030    import java.util.Collections;
031    import java.util.Comparator;
032    import java.util.Enumeration;
033    import java.util.HashMap;
034    import java.util.HashSet;
035    import java.util.Iterator;
036    import java.util.List;
037    import java.util.Map;
038    import java.util.Set;
039    import java.util.TreeSet;
040    import java.util.jar.JarFile;
041    
042    import javax.management.ObjectName;
043    import javax.servlet.Servlet;
044    
045    import org.apache.commons.logging.Log;
046    import org.apache.commons.logging.LogFactory;
047    import org.apache.geronimo.common.DeploymentException;
048    import org.apache.geronimo.deployment.ModuleIDBuilder;
049    import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
050    import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
051    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
052    import org.apache.geronimo.deployment.util.DeploymentUtil;
053    import org.apache.geronimo.deployment.xbeans.EnvironmentType;
054    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
055    import org.apache.geronimo.gbean.AbstractName;
056    import org.apache.geronimo.gbean.AbstractNameQuery;
057    import org.apache.geronimo.gbean.GBeanData;
058    import org.apache.geronimo.gbean.GBeanInfo;
059    import org.apache.geronimo.gbean.GBeanInfoBuilder;
060    import org.apache.geronimo.gbean.SingleElementCollection;
061    import org.apache.geronimo.j2ee.deployment.EARContext;
062    import org.apache.geronimo.j2ee.deployment.Module;
063    import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
064    import org.apache.geronimo.j2ee.deployment.NamingBuilder;
065    import org.apache.geronimo.j2ee.deployment.WebModule;
066    import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
067    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
068    import org.apache.geronimo.jetty.DefaultWebApplicationHandlerFactory;
069    import org.apache.geronimo.jetty.Host;
070    import org.apache.geronimo.jetty.JettyDefaultServletHolder;
071    import org.apache.geronimo.jetty.JettyFilterHolder;
072    import org.apache.geronimo.jetty.JettyFilterMapping;
073    import org.apache.geronimo.jetty.JettyServletHolder;
074    import org.apache.geronimo.jetty.JettyWebAppContext;
075    import org.apache.geronimo.jetty.NonAuthenticator;
076    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
077    import org.apache.geronimo.kernel.GBeanNotFoundException;
078    import org.apache.geronimo.kernel.Kernel;
079    import org.apache.geronimo.kernel.Naming;
080    import org.apache.geronimo.kernel.config.Configuration;
081    import org.apache.geronimo.kernel.config.ConfigurationData;
082    import org.apache.geronimo.kernel.repository.Environment;
083    import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
084    import org.apache.geronimo.naming.deployment.GBeanResourceEnvironmentBuilder;
085    import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
086    import org.apache.geronimo.security.deploy.DefaultPrincipal;
087    import org.apache.geronimo.security.deployment.SecurityConfiguration;
088    import org.apache.geronimo.security.jacc.ComponentPermissions;
089    import org.apache.geronimo.web.deployment.AbstractWebModuleBuilder;
090    import org.apache.geronimo.web.deployment.GenericToSpecificPlanConverter;
091    import org.apache.geronimo.xbeans.geronimo.web.jetty.JettyWebAppDocument;
092    import org.apache.geronimo.xbeans.geronimo.web.jetty.JettyWebAppType;
093    import org.apache.geronimo.xbeans.geronimo.web.jetty.config.GerJettyDocument;
094    import org.apache.geronimo.xbeans.j2ee.DispatcherType;
095    import org.apache.geronimo.xbeans.j2ee.ErrorPageType;
096    import org.apache.geronimo.xbeans.j2ee.FilterMappingType;
097    import org.apache.geronimo.xbeans.j2ee.FilterType;
098    import org.apache.geronimo.xbeans.j2ee.FormLoginConfigType;
099    import org.apache.geronimo.xbeans.j2ee.JspConfigType;
100    import org.apache.geronimo.xbeans.j2ee.ListenerType;
101    import org.apache.geronimo.xbeans.j2ee.LocaleEncodingMappingListType;
102    import org.apache.geronimo.xbeans.j2ee.LocaleEncodingMappingType;
103    import org.apache.geronimo.xbeans.j2ee.LoginConfigType;
104    import org.apache.geronimo.xbeans.j2ee.MimeMappingType;
105    import org.apache.geronimo.xbeans.j2ee.ParamValueType;
106    import org.apache.geronimo.xbeans.j2ee.ServletMappingType;
107    import org.apache.geronimo.xbeans.j2ee.ServletType;
108    import org.apache.geronimo.xbeans.j2ee.TaglibType;
109    import org.apache.geronimo.xbeans.j2ee.WebAppDocument;
110    import org.apache.geronimo.xbeans.j2ee.WebAppType;
111    import org.apache.geronimo.xbeans.j2ee.WelcomeFileListType;
112    import org.apache.xmlbeans.XmlException;
113    import org.apache.xmlbeans.XmlObject;
114    import org.mortbay.http.BasicAuthenticator;
115    import org.mortbay.http.ClientCertAuthenticator;
116    import org.mortbay.http.DigestAuthenticator;
117    import org.mortbay.jetty.servlet.FormAuthenticator;
118    
119    
120    /**
121     * @version $Rev:385659 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
122     */
123    public class JettyModuleBuilder extends AbstractWebModuleBuilder {
124        private final static Log log = LogFactory.getLog(JettyModuleBuilder.class);
125        private final Environment defaultEnvironment;
126        private final AbstractNameQuery jettyContainerObjectName;
127        private final Collection defaultServlets;
128        private final Collection defaultFilters;
129        private final Collection defaultFilterMappings;
130        private final GBeanData pojoWebServiceTemplate;
131    
132        private final SingleElementCollection webServiceBuilder;
133        protected final NamespaceDrivenBuilderCollection clusteringBuilders;
134    
135        private final List defaultWelcomeFiles;
136        private final Integer defaultSessionTimeoutSeconds;
137    
138        private static final String JETTY_NAMESPACE = JettyWebAppDocument.type.getDocumentElementName().getNamespaceURI();
139    
140        public JettyModuleBuilder(Environment defaultEnvironment,
141                Integer defaultSessionTimeoutSeconds,
142                List defaultWelcomeFiles,
143                AbstractNameQuery jettyContainerName,
144                Collection defaultServlets,
145                Collection defaultFilters,
146                Collection defaultFilterMappings,
147                Object pojoWebServiceTemplate,
148                Collection webServiceBuilder,
149                Collection clusteringBuilders,
150                Collection securityBuilders,
151                Collection serviceBuilders,
152                NamingBuilder namingBuilders,
153                ResourceEnvironmentSetter resourceEnvironmentSetter,
154                Kernel kernel) throws GBeanNotFoundException {
155            super(kernel, securityBuilders, serviceBuilders, namingBuilders, resourceEnvironmentSetter);
156            this.defaultEnvironment = defaultEnvironment;
157            this.defaultSessionTimeoutSeconds = (defaultSessionTimeoutSeconds == null) ? new Integer(30 * 60) : defaultSessionTimeoutSeconds;
158            this.jettyContainerObjectName = jettyContainerName;
159            this.defaultServlets = defaultServlets;
160            this.defaultFilters = defaultFilters;
161            this.defaultFilterMappings = defaultFilterMappings;
162            this.pojoWebServiceTemplate = getGBeanData(kernel, pojoWebServiceTemplate);
163            this.webServiceBuilder = new SingleElementCollection(webServiceBuilder);
164            this.clusteringBuilders = new NamespaceDrivenBuilderCollection(clusteringBuilders);
165    
166            //todo locale mappings
167    
168            this.defaultWelcomeFiles = defaultWelcomeFiles;
169        }
170    
171        private WebServiceBuilder getWebServiceBuilder() {
172            return (WebServiceBuilder) webServiceBuilder.getElement();
173        }
174        
175        private static GBeanData getGBeanData(Kernel kernel, Object template) throws GBeanNotFoundException {
176            if (template == null) {
177                return null;
178            }
179            AbstractName templateName = kernel.getAbstractNameFor(template);
180            return kernel.getGBeanData(templateName);
181        }
182    
183        protected Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, boolean standAlone, String contextRoot, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
184            assert moduleFile != null: "moduleFile is null";
185            assert targetPath != null: "targetPath is null";
186            assert !targetPath.endsWith("/"): "targetPath must not end with a '/'";
187    
188            // parse the spec dd
189            String specDD;
190            WebAppType webApp;
191            try {
192                if (specDDUrl == null) {
193                    specDDUrl = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/web.xml");
194                }
195    
196                // read in the entire specDD as a string, we need this for getDeploymentDescriptor
197                // on the J2ee management object
198                specDD = DeploymentUtil.readAll(specDDUrl);
199            } catch (Exception e) {
200                //no web.xml, not for us
201                return null;
202            }
203            //we found web.xml, if it won't parse that's an error.
204            try {
205                // parse it
206                XmlObject parsed = XmlBeansUtil.parse(specDD);
207                WebAppDocument webAppDoc = convertToServletSchema(parsed);
208                webApp = webAppDoc.getWebApp();
209            } catch (XmlException xmle) {
210                // Output the target path in the error to make it clearer to the user which webapp
211                // has the problem.  The targetPath is used, as moduleFile may have an unhelpful
212                // value such as C:\geronimo-1.1\var\temp\geronimo-deploymentUtil22826.tmpdir
213                throw new DeploymentException("Error parsing web.xml for " + targetPath, xmle);
214            }
215            check(webApp);
216    
217            // parse vendor dd
218            JettyWebAppType jettyWebApp = getJettyWebApp(plan, moduleFile, standAlone, targetPath, webApp);
219            if (contextRoot == null || contextRoot.trim().equals("")) {
220                if (jettyWebApp.isSetContextRoot()) {
221                    contextRoot = jettyWebApp.getContextRoot();
222                } else {
223                    contextRoot = determineDefaultContextRoot(webApp, standAlone, moduleFile, targetPath);
224                }
225            }
226    
227            contextRoot = contextRoot.trim();
228    
229            EnvironmentType environmentType = jettyWebApp.getEnvironment();
230            Environment environment = EnvironmentBuilder.buildEnvironment(environmentType, defaultEnvironment);
231            
232            Boolean distributable = webApp.getDistributableArray().length == 1 ? Boolean.TRUE : Boolean.FALSE;
233            if (Boolean.TRUE == distributable) {
234                clusteringBuilders.buildEnvironment(jettyWebApp, environment);
235            }
236    
237            getNamingBuilders().buildEnvironment(webApp, jettyWebApp, environment);
238            
239            // Note: logic elsewhere depends on the default artifact ID being the file name less extension (ConfigIDExtractor)
240            String warName = new File(moduleFile.getName()).getName();
241            if (warName.lastIndexOf('.') > -1) {
242                warName = warName.substring(0, warName.lastIndexOf('.'));
243            }
244            idBuilder.resolve(environment, warName, "war");
245    
246            Map servletNameToPathMap = buildServletNameToPathMap(webApp, contextRoot);
247    
248            Map portMap = getWebServiceBuilder().findWebServices(moduleFile, false, servletNameToPathMap, environment);
249            AbstractName moduleName;
250            if (earName == null) {
251                earName = naming.createRootName(environment.getConfigId(), NameFactory.NULL, NameFactory.J2EE_APPLICATION);
252                moduleName = naming.createChildName(earName, environment.getConfigId().toString(), NameFactory.WEB_MODULE);
253            } else {
254                moduleName = naming.createChildName(earName, targetPath, NameFactory.WEB_MODULE);
255            }
256    
257            return new WebModule(standAlone, moduleName, environment, moduleFile, targetPath, webApp, jettyWebApp, specDD, contextRoot, portMap, JETTY_NAMESPACE);
258        }
259    
260        JettyWebAppType getJettyWebApp(Object plan, JarFile moduleFile, boolean standAlone, String targetPath, WebAppType webApp) throws DeploymentException {
261            XmlObject rawPlan = null;
262            try {
263                // load the geronimo-web.xml from either the supplied plan or from the earFile
264                try {
265                    if (plan instanceof XmlObject) {
266                        rawPlan = (XmlObject) plan;
267                    } else {
268                        if (plan != null) {
269                            rawPlan = XmlBeansUtil.parse(((File) plan).toURL(), getClass().getClassLoader());
270                        } else {
271                            URL path = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/geronimo-web.xml");
272                            try {
273                                rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
274                            } catch (FileNotFoundException e) {
275                                path = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/geronimo-jetty.xml");
276                                try {
277                                    rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
278                                } catch (FileNotFoundException e1) {
279                                    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.");
280                                }
281                            }
282                        }
283                    }
284                } catch (IOException e) {
285                    log.warn(e);
286                }
287    
288                JettyWebAppType jettyWebApp;
289                if (rawPlan != null) {
290                    XmlObject webPlan = new GenericToSpecificPlanConverter(GerJettyDocument.type.getDocumentElementName().getNamespaceURI(),
291                            JettyWebAppDocument.type.getDocumentElementName().getNamespaceURI(), "jetty").convertToSpecificPlan(rawPlan);
292                    jettyWebApp = (JettyWebAppType) webPlan.changeType(JettyWebAppType.type);
293                    XmlBeansUtil.validateDD(jettyWebApp);
294                } else {
295                    String defaultContextRoot = determineDefaultContextRoot(webApp, standAlone, moduleFile, targetPath);
296                    jettyWebApp = createDefaultPlan(defaultContextRoot);
297                }
298                return jettyWebApp;
299            } catch (XmlException e) {
300                throw new DeploymentException("xml problem for web app " + targetPath, e);
301            }
302        }
303    
304        private JettyWebAppType createDefaultPlan(String contextRoot) {
305            JettyWebAppType jettyWebApp = JettyWebAppType.Factory.newInstance();
306            jettyWebApp.setContextRoot(contextRoot);
307            return jettyWebApp;
308        }
309    
310        public void initContext(EARContext earContext, Module module, ClassLoader cl) throws DeploymentException {
311            WebAppType webApp = (WebAppType) module.getSpecDD();
312    //        MessageDestinationType[] messageDestinations = webApp.getMessageDestinationArray();
313            JettyWebAppType gerWebApp = (JettyWebAppType) module.getVendorDD();
314    //        GerMessageDestinationType[] gerMessageDestinations = gerWebApp.getMessageDestinationArray();
315    
316    //        ENCConfigBuilder.registerMessageDestinations(earContext, module.getName(), messageDestinations, gerMessageDestinations);
317            getNamingBuilders().initContext(webApp, gerWebApp, module.getEarContext().getConfiguration(), earContext.getConfiguration(), module);
318            if ((webApp.getSecurityConstraintArray().length > 0 || webApp.getSecurityRoleArray().length > 0) &&
319                    !gerWebApp.isSetSecurityRealmName()) {
320                throw new DeploymentException("web.xml for web app " + module.getName() + " includes security elements but Geronimo deployment plan is not provided or does not contain <security-realm-name> element necessary to configure security accordingly.");
321            }
322            boolean hasSecurityRealmName = gerWebApp.isSetSecurityRealmName();
323            buildSubstitutionGroups(gerWebApp, hasSecurityRealmName, module, earContext);
324        }
325    
326        public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repository) throws DeploymentException {
327            EARContext moduleContext = module.getEarContext();
328            AbstractName moduleName = moduleContext.getModuleName();
329            WebModule webModule = (WebModule) module;
330    
331            WebAppType webApp = (WebAppType) webModule.getSpecDD();
332            JettyWebAppType jettyWebApp = (JettyWebAppType) webModule.getVendorDD();
333    
334    
335            GBeanData webModuleData = new GBeanData(moduleName, JettyWebAppContext.GBEAN_INFO);
336            try {
337                moduleContext.addGBean(webModuleData);
338                if (moduleContext.getServerName() != null) {
339                    webModuleData.setReferencePattern("J2EEServer", moduleContext.getServerName());
340                }
341                if (!module.isStandAlone()) {
342                    webModuleData.setReferencePattern("J2EEApplication", earContext.getModuleName());
343                }
344    
345                webModuleData.setAttribute("deploymentDescriptor", module.getOriginalSpecDD());
346                Set securityRoles = collectRoleNames(webApp);
347                Map rolePermissions = new HashMap();
348    
349                // configure hosts and virtual-hosts
350                configureHosts(earContext, jettyWebApp, webModuleData);
351    
352                //Add dependencies on managed connection factories and ejbs in this app
353                //This is overkill, but allows for people not using java:comp context (even though we don't support it)
354                //and sidesteps the problem of circular references between ejbs.
355                Set dependencies = findGBeanDependencies(earContext);
356                webModuleData.addDependencies(dependencies);
357    
358                //N.B. we use the ear context which has all the gbeans we could possibly be looking up from this ear.
359                Map buildingContext = new HashMap();
360                buildingContext.put(NamingBuilder.JNDI_KEY, new HashMap());
361                buildingContext.put(NamingBuilder.GBEAN_NAME_KEY, moduleName);
362                Configuration earConfiguration = earContext.getConfiguration();
363                getNamingBuilders().buildNaming(webApp, jettyWebApp, earConfiguration, earConfiguration, (Module)webModule, buildingContext);
364                Map compContext = (Map) buildingContext.get(NamingBuilder.JNDI_KEY);
365    
366                webModuleData.setAttribute("componentContext", compContext);
367                //classpath may have been augmented with enhanced classes
368    //            webModuleData.setAttribute("webClassPath", webModule.getWebClasspath());
369                // unsharableResources, applicationManagedSecurityResources
370                GBeanResourceEnvironmentBuilder rebuilder = new GBeanResourceEnvironmentBuilder(webModuleData);
371                //N.B. use earContext not moduleContext
372                resourceEnvironmentSetter.setResourceEnvironment(rebuilder, webApp.getResourceRefArray(), jettyWebApp.getResourceRefArray());
373    
374                webModuleData.setAttribute("contextPath", webModule.getContextRoot());
375    
376                webModuleData.setReferencePattern("TransactionManager", moduleContext.getTransactionManagerName());
377                webModuleData.setReferencePattern("TrackedConnectionAssociator", moduleContext.getConnectionTrackerName());
378                if (jettyWebApp.isSetWebContainer()) {
379                    AbstractNameQuery webContainerName = ENCConfigBuilder.getGBeanQuery(NameFactory.GERONIMO_SERVICE, jettyWebApp.getWebContainer());
380                    webModuleData.setReferencePattern("JettyContainer", webContainerName);
381                } else {
382                    webModuleData.setReferencePattern("JettyContainer", jettyContainerObjectName);
383                }
384                //stuff that jetty used to do
385                if (webApp.getDisplayNameArray().length > 0) {
386                    webModuleData.setAttribute("displayName", webApp.getDisplayNameArray()[0].getStringValue());
387                }
388    
389                // configure context parameters.
390                configureContextParams(webApp, webModuleData);
391    
392                // configure listeners.
393                configureListeners(webApp, webModuleData);
394    
395                webModuleData.setAttribute(JettyWebAppContext.GBEAN_ATTR_SESSION_TIMEOUT,
396                        (webApp.getSessionConfigArray().length == 1 && webApp.getSessionConfigArray(0).getSessionTimeout() != null) ?
397                                new Integer(webApp.getSessionConfigArray(0).getSessionTimeout().getBigIntegerValue().intValue() * 60) :
398                                    defaultSessionTimeoutSeconds);
399                
400                Boolean distributable = webApp.getDistributableArray().length == 1 ? Boolean.TRUE : Boolean.FALSE;
401                webModuleData.setAttribute("distributable", distributable);
402                if (Boolean.TRUE == distributable) {
403                    clusteringBuilders.build(jettyWebApp, earContext, moduleContext);
404                    if (webModuleData.getReferencePatterns(JettyWebAppContext.GBEAN_REF_WEB_APPLICATION_HANDLER_FACTORY) == null) {
405                        log.warn("No clustering builders configured: app will not be clustered");
406                        configureNoClustering(moduleContext, webModuleData);
407                    }
408                } else {
409                    configureNoClustering(moduleContext, webModuleData);
410                }
411                
412    
413                // configure mime mappings.
414                configureMimeMappings(webApp, webModuleData);
415    
416                // configure welcome file lists.
417                configureWelcomeFileLists(webApp, webModuleData);
418    
419                // configure local encoding mapping lists.
420                configureLocalEncodingMappingLists(webApp, webModuleData);
421    
422                // configure error pages.
423                configureErrorPages(webApp, webModuleData);
424    
425                // configure tag libs.
426                configureTagLibs(module, webApp, webModuleData);
427    
428                // configure login configs.
429                configureLoginConfigs(module, webApp, jettyWebApp, webModuleData);
430                
431                // Make sure that servlet mappings point to available servlets and never add a duplicate pattern.
432                Set knownServletMappings = new HashSet();
433                Map servletMappings = new HashMap();
434    
435                buildServletMappings(module, webApp, servletMappings, knownServletMappings);
436    
437                //"previous" filter mapping for linked list to keep dd's ordering.
438                AbstractName previous = null;
439    
440                //add default filters
441                if (defaultFilters != null) {
442                    previous = addDefaultFiltersGBeans(earContext, moduleContext, moduleName, previous);
443                }
444    
445                //add default filtermappings
446    //            if (defaultFilterMappings != null) {
447    //                for (Iterator iterator = defaultFilterMappings.iterator(); iterator.hasNext();) {
448    //                    Object defaultFilterMapping = iterator.next();
449    //                    GBeanData filterMappingGBeanData = getGBeanData(kernel, defaultFilterMapping);
450    //                    String filterName = (String) filterMappingGBeanData.getAttribute("filterName");
451    //                    ObjectName defaultFilterMappingObjectName;
452    //                    if (filterMappingGBeanData.getAttribute("urlPattern") != null) {
453    //                        String urlPattern = (String) filterMappingGBeanData.getAttribute("urlPattern");
454    //                        defaultFilterMappingObjectName = NameFactory.getWebFilterMappingName(null, null, null, null, filterName, null, urlPattern, moduleName);
455    //                    } else {
456    //                        Set servletNames = filterMappingGBeanData.getReferencePatterns("Servlet");
457    //                        if (servletNames == null || servletNames.size() != 1) {
458    //                            throw new DeploymentException("Exactly one servlet name must be supplied");
459    //                        }
460    //                        ObjectName servletObjectName = (ObjectName) servletNames.iterator().next();
461    //                        String servletName = servletObjectName.getKeyProperty("name");
462    //                        defaultFilterMappingObjectName = NameFactory.getWebFilterMappingName(null, null, null, null, filterName, servletName, null, moduleName);
463    //                    }
464    //                    filterMappingGBeanData.setName(defaultFilterMappingObjectName);
465    //                    filterMappingGBeanData.setReferencePattern("JettyFilterMappingRegistration", webModuleName);
466    //                    moduleContext.addGBean(filterMappingGBeanData);
467    //                }
468    //            }
469    
470                // add filter mapping GBeans.
471                addFilterMappingsGBeans(earContext, moduleContext, moduleName, webApp, previous);
472    
473                // add filter GBeans.
474                addFiltersGBeans(earContext, moduleContext, moduleName, webApp);
475    
476                //add default servlets
477                if (defaultServlets != null) {
478                    addDefaultServletsGBeans(earContext, moduleContext, moduleName, knownServletMappings);
479                }
480    
481                //set up servlet gbeans.
482                Map portMap = webModule.getPortMap();
483    
484                ServletType[] servletTypes = webApp.getServletArray();
485                addServlets(moduleName, webModule, servletTypes, servletMappings, securityRoles, rolePermissions, portMap, moduleContext);
486    
487                if (jettyWebApp.isSetSecurityRealmName()) {
488                    configureSecurityRealm(earContext, webApp, jettyWebApp, webModuleData, securityRoles, rolePermissions);
489                }
490                if (!module.isStandAlone()) {
491                    ConfigurationData moduleConfigurationData = moduleContext.getConfigurationData();
492                    earContext.addChildConfiguration(module.getTargetPath(), moduleConfigurationData);
493                }
494            } catch (DeploymentException de) {
495                throw de;
496            } catch (Exception e) {
497                throw new DeploymentException("Unable to initialize webapp GBean for " + module.getName(), e);
498            }
499        }
500    
501        private void configureNoClustering(EARContext moduleContext, GBeanData webModuleData) throws GBeanAlreadyExistsException {
502            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(), 
503                    "DefaultWebApplicationHandlerFactory", 
504                    NameFactory.GERONIMO_SERVICE);
505            GBeanData beanData = new GBeanData(name, DefaultWebApplicationHandlerFactory.GBEAN_INFO);
506            webModuleData.setReferencePattern(JettyWebAppContext.GBEAN_REF_WEB_APPLICATION_HANDLER_FACTORY, name);
507            moduleContext.addGBean(beanData);
508        }
509    
510        private void configureSecurityRealm(EARContext earContext, WebAppType webApp, JettyWebAppType jettyWebApp, GBeanData webModuleData, Set securityRoles, Map rolePermissions) throws DeploymentException {
511            AbstractName moduleName = webModuleData.getAbstractName();
512            if (earContext.getSecurityConfiguration() == null) {
513                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)");
514            }
515            String securityRealmName = jettyWebApp.getSecurityRealmName().trim();
516            webModuleData.setAttribute("securityRealmName", securityRealmName);
517    
518            /**
519             * TODO - go back to commented version when possible.
520             */
521            String policyContextID = moduleName.toString().replaceAll("[, :]", "_");
522            //String policyContextID = webModuleName.getCanonicalName();
523            webModuleData.setAttribute("policyContextID", policyContextID);
524    
525            ComponentPermissions componentPermissions = buildSpecSecurityConfig(webApp, securityRoles, rolePermissions);
526            webModuleData.setAttribute("excludedPermissions", componentPermissions.getExcludedPermissions());
527            PermissionCollection checkedPermissions = new Permissions();
528            for (Iterator iterator = rolePermissions.values().iterator(); iterator.hasNext();) {
529                PermissionCollection permissionsForRole = (PermissionCollection) iterator.next();
530                for (Enumeration iterator2 = permissionsForRole.elements(); iterator2.hasMoreElements();) {
531                    Permission permission = (Permission) iterator2.nextElement();
532                    checkedPermissions.add(permission);
533                }
534            }
535            webModuleData.setAttribute("checkedPermissions", checkedPermissions);
536    
537            earContext.addSecurityContext(policyContextID, componentPermissions);
538            DefaultPrincipal defaultPrincipal = ((SecurityConfiguration) earContext.getSecurityConfiguration()).getDefaultPrincipal();
539            webModuleData.setAttribute("defaultPrincipal", defaultPrincipal);
540        }
541    
542        private void addDefaultServletsGBeans(EARContext earContext, EARContext moduleContext, AbstractName moduleName, Set knownServletMappings) throws GBeanNotFoundException, GBeanAlreadyExistsException {
543            for (Iterator iterator = defaultServlets.iterator(); iterator.hasNext();) {
544                Object defaultServlet = iterator.next();
545                GBeanData servletGBeanData = getGBeanData(kernel, defaultServlet);
546                AbstractName defaultServletObjectName = earContext.getNaming().createChildName(moduleName, (String) servletGBeanData.getAttribute("servletName"), NameFactory.SERVLET);
547                servletGBeanData.setAbstractName(defaultServletObjectName);
548                servletGBeanData.setReferencePattern("JettyServletRegistration", moduleName);
549                Set defaultServletMappings = new HashSet((Collection) servletGBeanData.getAttribute("servletMappings"));
550                defaultServletMappings.removeAll(knownServletMappings);
551                servletGBeanData.setAttribute("servletMappings", defaultServletMappings);
552                moduleContext.addGBean(servletGBeanData);
553            }
554        }
555    
556        private void addFiltersGBeans(EARContext earContext, EARContext moduleContext, AbstractName moduleName, WebAppType webApp) throws GBeanAlreadyExistsException {
557            FilterType[] filterArray = webApp.getFilterArray();
558            for (int i = 0; i < filterArray.length; i++) {
559                FilterType filterType = filterArray[i];
560                String filterName = filterType.getFilterName().getStringValue().trim();
561                AbstractName filterAbstractName = earContext.getNaming().createChildName(moduleName, filterName, NameFactory.WEB_FILTER);
562                GBeanData filterData = new GBeanData(filterAbstractName, JettyFilterHolder.GBEAN_INFO);
563                filterData.setAttribute("filterName", filterName);
564                filterData.setAttribute("filterClass", filterType.getFilterClass().getStringValue().trim());
565                Map initParams = new HashMap();
566                ParamValueType[] initParamArray = filterType.getInitParamArray();
567                for (int j = 0; j < initParamArray.length; j++) {
568                    ParamValueType paramValueType = initParamArray[j];
569                    initParams.put(paramValueType.getParamName().getStringValue().trim(), paramValueType.getParamValue().getStringValue().trim());
570                }
571                filterData.setAttribute("initParams", initParams);
572                filterData.setReferencePattern("JettyServletRegistration", moduleName);
573                moduleContext.addGBean(filterData);
574            }
575        }
576    
577        private void addFilterMappingsGBeans(EARContext earContext, EARContext moduleContext, AbstractName moduleName, WebAppType webApp, AbstractName previous) throws GBeanAlreadyExistsException {
578            FilterMappingType[] filterMappingArray = webApp.getFilterMappingArray();
579            for (int i = 0; i < filterMappingArray.length; i++) {
580                FilterMappingType filterMappingType = filterMappingArray[i];
581                String filterName = filterMappingType.getFilterName().getStringValue().trim();
582                GBeanData filterMappingData = new GBeanData(JettyFilterMapping.GBEAN_INFO);
583                if (previous != null) {
584                    filterMappingData.setReferencePattern("Previous", previous);
585                }
586                filterMappingData.setReferencePattern("JettyServletRegistration", moduleName);
587                AbstractName filterAbstractName = earContext.getNaming().createChildName(moduleName, filterName, NameFactory.WEB_FILTER);
588    
589                AbstractName filterMappingName = null;
590                if (filterMappingType.isSetUrlPattern()) {
591                    String urlPattern = filterMappingType.getUrlPattern().getStringValue().trim();
592                    filterMappingData.setAttribute("urlPattern", urlPattern);
593                    filterMappingName = earContext.getNaming().createChildName(filterAbstractName, ObjectName.quote(urlPattern), NameFactory.URL_WEB_FILTER_MAPPING);
594                }
595                if (filterMappingType.isSetServletName()) {
596                    String servletName = filterMappingType.getServletName().getStringValue().trim();
597                    AbstractName servletAbstractName = earContext.getNaming().createChildName(moduleName, servletName, NameFactory.SERVLET);
598                    filterMappingData.setReferencePattern("Servlet", servletAbstractName);
599                    filterMappingName = earContext.getNaming().createChildName(filterAbstractName, servletName, NameFactory.SERVLET_WEB_FILTER_MAPPING);
600                }
601                filterMappingData.setAbstractName(filterMappingName);
602                previous = filterMappingName;
603    
604                boolean request = filterMappingType.getDispatcherArray().length == 0;
605                boolean forward = false;
606                boolean include = false;
607                boolean error = false;
608                for (int j = 0; j < filterMappingType.getDispatcherArray().length; j++) {
609                    DispatcherType dispatcherType = filterMappingType.getDispatcherArray()[j];
610                    if (dispatcherType.getStringValue().equals("REQUEST")) {
611                        request = true;
612                    } else if (dispatcherType.getStringValue().equals("FORWARD")) {
613                        forward = true;
614                    } else if (dispatcherType.getStringValue().equals("INCLUDE")) {
615                        include = true;
616                    } else if (dispatcherType.getStringValue().equals("ERROR")) {
617                        error = true;
618                    }
619                }
620                filterMappingData.setAttribute("requestDispatch", Boolean.valueOf(request));
621                filterMappingData.setAttribute("forwardDispatch", Boolean.valueOf(forward));
622                filterMappingData.setAttribute("includeDispatch", Boolean.valueOf(include));
623                filterMappingData.setAttribute("errorDispatch", Boolean.valueOf(error));
624                filterMappingData.setReferencePattern("Filter", filterAbstractName);
625                moduleContext.addGBean(filterMappingData);
626            }
627        }
628    
629        private AbstractName addDefaultFiltersGBeans(EARContext earContext, EARContext moduleContext, AbstractName moduleName, AbstractName previous) throws GBeanNotFoundException, GBeanAlreadyExistsException {
630            for (Iterator iterator = defaultFilters.iterator(); iterator.hasNext();) {
631                Object defaultFilter = iterator.next();
632                GBeanData filterGBeanData = getGBeanData(kernel, defaultFilter);
633                String filterName = (String) filterGBeanData.getAttribute("filterName");
634                AbstractName defaultFilterAbstractName = earContext.getNaming().createChildName(moduleName, filterName, NameFactory.WEB_FILTER);
635                filterGBeanData.setAbstractName(defaultFilterAbstractName);
636                filterGBeanData.setReferencePattern("JettyServletRegistration", moduleName);
637                moduleContext.addGBean(filterGBeanData);
638                //add a mapping to /*
639    
640                GBeanData filterMappingGBeanData = new GBeanData(JettyFilterMapping.GBEAN_INFO);
641                if (previous != null) {
642                    filterMappingGBeanData.setReferencePattern("Previous", previous);
643                }
644                filterMappingGBeanData.setReferencePattern("JettyServletRegistration", moduleName);
645                String urlPattern = "/*";
646                filterMappingGBeanData.setAttribute("urlPattern", urlPattern);
647                AbstractName filterMappingName = earContext.getNaming().createChildName(defaultFilterAbstractName, urlPattern, NameFactory.URL_WEB_FILTER_MAPPING);
648                filterMappingGBeanData.setAbstractName(filterMappingName);
649                previous = filterMappingName;
650    
651    
652                filterMappingGBeanData.setAttribute("requestDispatch", Boolean.TRUE);
653                filterMappingGBeanData.setAttribute("forwardDispatch", Boolean.TRUE);
654                filterMappingGBeanData.setAttribute("includeDispatch", Boolean.TRUE);
655                filterMappingGBeanData.setAttribute("errorDispatch", Boolean.FALSE);
656                filterMappingGBeanData.setReferencePattern("Filter", defaultFilterAbstractName);
657                moduleContext.addGBean(filterMappingGBeanData);
658            }
659            return previous;
660        }
661    
662        private Map buildServletMappings(Module module, WebAppType webApp, Map servletMappings, Set knownServletMappings) throws DeploymentException {
663            ServletType[] servletTypes = webApp.getServletArray();
664            Set knownServlets = new HashSet();
665            for (int i = 0; i < servletTypes.length; i++) {
666                ServletType type = servletTypes[i];
667                knownServlets.add(type.getServletName().getStringValue().trim());
668            }
669    
670            ServletMappingType[] servletMappingArray = webApp.getServletMappingArray();
671            for (int i = 0; i < servletMappingArray.length; i++) {
672                ServletMappingType servletMappingType = servletMappingArray[i];
673                String servletName = servletMappingType.getServletName().getStringValue().trim();
674                if (!knownServlets.contains(servletName)) {
675                    throw new DeploymentException("Web app " + module.getName() +
676                            " contains a servlet mapping that refers to servlet '" + servletName +
677                            "' but no such servlet was found!");
678                }
679                String urlPattern = servletMappingType.getUrlPattern().getStringValue().trim();
680                if (!knownServletMappings.contains(urlPattern)) {
681                    knownServletMappings.add(urlPattern);
682                    checkString(urlPattern);
683                    Set urlsForServlet = (Set) servletMappings.get(servletName);
684                    if (urlsForServlet == null) {
685                        urlsForServlet = new HashSet();
686                        servletMappings.put(servletName, urlsForServlet);
687                    }
688                    urlsForServlet.add(urlPattern);
689                }
690            }
691            
692            return servletMappings;
693        }
694    
695        private void configureLoginConfigs(Module module, WebAppType webApp, JettyWebAppType jettyWebApp, GBeanData webModuleData) throws DeploymentException {
696            LoginConfigType[] loginConfigArray = webApp.getLoginConfigArray();
697            if (loginConfigArray.length > 1) {
698                throw new DeploymentException("Web app " + module.getName() + " cannot have more than one login-config element.  Currently has " + loginConfigArray.length + " login-config elements.");
699            }
700            if (loginConfigArray.length == 1) {
701                LoginConfigType loginConfig = loginConfigArray[0];
702                if (loginConfig.isSetAuthMethod()) {
703                    String authMethod = loginConfig.getAuthMethod().getStringValue();
704                    if ("BASIC".equals(authMethod)) {
705                        webModuleData.setAttribute("authenticator", new BasicAuthenticator());
706                    } else if ("DIGEST".equals(authMethod)) {
707                        webModuleData.setAttribute("authenticator", new DigestAuthenticator());
708                    } else if ("FORM".equals(authMethod)) {
709    
710                        FormAuthenticator formAuthenticator = new FormAuthenticator();
711                        webModuleData.setAttribute("authenticator", formAuthenticator);
712                        if (loginConfig.isSetFormLoginConfig()) {
713                            FormLoginConfigType formLoginConfig = loginConfig.getFormLoginConfig();
714                            formAuthenticator.setLoginPage(formLoginConfig.getFormLoginPage().getStringValue());
715                            formAuthenticator.setErrorPage(formLoginConfig.getFormErrorPage().getStringValue());
716                        }
717                    } else if ("CLIENT-CERT".equals(authMethod)) {
718                        webModuleData.setAttribute("authenticator", new ClientCertAuthenticator());
719                    }
720                }
721                if (loginConfig.isSetRealmName()) {
722                    webModuleData.setAttribute("realmName", loginConfig.getRealmName().getStringValue());
723                }
724    
725            } else if (jettyWebApp.isSetSecurityRealmName()) {
726                webModuleData.setAttribute("authenticator", new NonAuthenticator());
727            }
728        }
729    
730        private void configureTagLibs(Module module, WebAppType webApp, GBeanData webModuleData) throws DeploymentException {
731            JspConfigType[] jspConfigArray = webApp.getJspConfigArray();
732            if (jspConfigArray.length > 1) {
733                throw new DeploymentException("Web app "+ module.getName() +" cannot have more than one jsp-config element.  Currently has " + jspConfigArray.length +" jsp-config elements.");
734            }
735            Map tagLibMap = new HashMap();
736            for (int i = 0; i < jspConfigArray.length; i++) {
737                TaglibType[] tagLibArray = jspConfigArray[i].getTaglibArray();
738                for (int j = 0; j < tagLibArray.length; j++) {
739                    TaglibType taglib = tagLibArray[j];
740                    tagLibMap.put(taglib.getTaglibUri().getStringValue().trim(), taglib.getTaglibLocation().getStringValue().trim());
741                }
742            }
743            webModuleData.setAttribute("tagLibMap", tagLibMap);
744        }
745    
746        private void configureErrorPages(WebAppType webApp, GBeanData webModuleData) {
747            ErrorPageType[] errorPageArray = webApp.getErrorPageArray();
748            Map errorPageMap = new HashMap();
749            for (int i = 0; i < errorPageArray.length; i++) {
750                ErrorPageType errorPageType = errorPageArray[i];
751                if (errorPageType.isSetErrorCode()) {
752                    errorPageMap.put(errorPageType.getErrorCode().getStringValue(), errorPageType.getLocation().getStringValue());
753                } else {
754                    errorPageMap.put(errorPageType.getExceptionType().getStringValue(), errorPageType.getLocation().getStringValue());
755                }
756            }
757            webModuleData.setAttribute("errorPages", errorPageMap);
758        }
759    
760        private void configureLocalEncodingMappingLists(WebAppType webApp, GBeanData webModuleData) {
761            LocaleEncodingMappingListType[] localeEncodingMappingListArray = webApp.getLocaleEncodingMappingListArray();
762            Map localeEncodingMappingMap = new HashMap();
763            for (int i = 0; i < localeEncodingMappingListArray.length; i++) {
764                LocaleEncodingMappingType[] localeEncodingMappingArray = localeEncodingMappingListArray[i].getLocaleEncodingMappingArray();
765                for (int j = 0; j < localeEncodingMappingArray.length; j++) {
766                    LocaleEncodingMappingType localeEncodingMapping = localeEncodingMappingArray[j];
767                    localeEncodingMappingMap.put(localeEncodingMapping.getLocale(), localeEncodingMapping.getEncoding());
768                }
769            }
770            webModuleData.setAttribute("localeEncodingMapping", localeEncodingMappingMap);
771        }
772    
773        private void configureWelcomeFileLists(WebAppType webApp, GBeanData webModuleData) {
774            WelcomeFileListType[] welcomeFileArray = webApp.getWelcomeFileListArray();
775            List welcomeFiles;
776            if (welcomeFileArray.length > 0) {
777                welcomeFiles = new ArrayList();
778                for (int i = 0; i < welcomeFileArray.length; i++) {
779                    String[] welcomeFileListType = welcomeFileArray[i].getWelcomeFileArray();
780                    for (int j = 0; j < welcomeFileListType.length; j++) {
781                        String welcomeFile = welcomeFileListType[j].trim();
782                        welcomeFiles.add(welcomeFile);
783                    }
784                }
785            } else {
786                welcomeFiles = new ArrayList(defaultWelcomeFiles);
787            }
788            webModuleData.setAttribute("welcomeFiles", welcomeFiles.toArray(new String[welcomeFiles.size()]));
789        }
790    
791        private void configureMimeMappings(WebAppType webApp, GBeanData webModuleData) {
792            MimeMappingType[] mimeMappingArray = webApp.getMimeMappingArray();
793            Map mimeMappingMap = new HashMap();
794            for (int i = 0; i < mimeMappingArray.length; i++) {
795                MimeMappingType mimeMappingType = mimeMappingArray[i];
796                mimeMappingMap.put(mimeMappingType.getExtension().getStringValue(), mimeMappingType.getMimeType().getStringValue());
797            }
798            webModuleData.setAttribute("mimeMap", mimeMappingMap);
799        }
800    
801        private void configureListeners(WebAppType webApp, GBeanData webModuleData) {
802            ListenerType[] listenerArray = webApp.getListenerArray();
803            Collection listeners = new ArrayList();
804            for (int i = 0; i < listenerArray.length; i++) {
805                ListenerType listenerType = listenerArray[i];
806                listeners.add(listenerType.getListenerClass().getStringValue());
807            }
808            webModuleData.setAttribute("listenerClassNames", listeners);
809        }
810    
811        private void configureContextParams(WebAppType webApp, GBeanData webModuleData) {
812            ParamValueType[] contextParamArray = webApp.getContextParamArray();
813            Map contextParams = new HashMap();
814            for (int i = 0; i < contextParamArray.length; i++) {
815                ParamValueType contextParam = contextParamArray[i];
816                contextParams.put(contextParam.getParamName().getStringValue().trim(), contextParam.getParamValue().getStringValue().trim());
817            }
818            webModuleData.setAttribute("contextParamMap", contextParams);
819        }
820    
821        private void configureHosts(EARContext earContext, JettyWebAppType jettyWebApp, GBeanData webModuleData) throws GBeanAlreadyExistsException {
822            String[] hosts = jettyWebApp.getHostArray();
823            for (int i = 0; i < hosts.length; i++) {
824                hosts[i] = hosts[i].trim();
825            }
826            String[] virtualHosts = jettyWebApp.getVirtualHostArray();
827            for (int i = 0; i < virtualHosts.length; i++) {
828                virtualHosts[i] = virtualHosts[i].trim();
829            }
830            if (hosts.length > 0 || virtualHosts.length > 0) {
831                //use name same as module
832                AbstractName hostName = earContext.getNaming().createChildName(webModuleData.getAbstractName(), "Host", "Host");
833                GBeanData hostData = new GBeanData(hostName, Host.GBEAN_INFO);
834                hostData.setAttribute("hosts", hosts);
835                hostData.setAttribute("virtualHosts", virtualHosts);
836                earContext.addGBean(hostData);
837                webModuleData.setReferencePattern("Host", hostName);
838            }
839        }
840    
841        public String getSchemaNamespace() {
842            return JETTY_NAMESPACE;
843        }
844    
845        /**
846         * Adds the provided servlets, taking into account the load-on-startup ordering.
847         *
848         * @param webModuleName   an <code>ObjectName</code> value
849         * @param module          a <code>WebModule</code> value
850         * @param servletTypes    a <code>ServletType[]</code> value, contains the <code>servlet</code> entries from <code>web.xml</code>.
851         * @param servletMappings a <code>Map</code> value
852         * @param securityRoles   a <code>Set</code> value
853         * @param rolePermissions a <code>Map</code> value
854         * @param portMap         a <code>Map</code> value
855         * @param moduleContext
856         * @throws DeploymentException if an error occurs
857         */
858        private void addServlets(AbstractName webModuleName,
859                WebModule module,
860                ServletType[] servletTypes,
861                Map servletMappings,
862                Set securityRoles,
863                Map rolePermissions,
864                Map portMap,
865                EARContext moduleContext) throws DeploymentException {
866    
867            // this TreeSet will order the ServletTypes based on whether
868            // they have a load-on-startup element and what its value is
869            TreeSet loadOrder = new TreeSet(new StartupOrderComparator());
870    
871            // add all of the servlets to the sorted set
872            for (int i = 0; i < servletTypes.length; i++) {
873                loadOrder.add(servletTypes[i]);
874            }
875    
876            // now that they're sorted, read them in order and add them to
877            // the context.  we'll use a GBean reference to enforce the
878            // load order.  Each servlet GBean (except the first) has a
879            // reference to the previous GBean.  The kernel will ensure
880            // that each "previous" GBean is running before it starts any
881            // other GBeans that reference it.  See also
882            // o.a.g.jetty.JettyFilterMapping which provided the example
883            // of how to do this.
884            // http://issues.apache.org/jira/browse/GERONIMO-645
885            AbstractName previousServlet = null;
886            for (Iterator servlets = loadOrder.iterator(); servlets.hasNext();) {
887                ServletType servletType = (ServletType) servlets.next();
888                previousServlet = addServlet(webModuleName, module, previousServlet, servletType, servletMappings, securityRoles, rolePermissions, portMap, moduleContext);
889            }
890    
891            // JACC v1.0 secion B.19
892            addUnmappedJSPPermissions(securityRoles, rolePermissions);
893        }
894    
895        /**
896         * @param webModuleName
897         * @param module
898         * @param previousServlet
899         * @param servletType
900         * @param servletMappings
901         * @param securityRoles
902         * @param rolePermissions
903         * @param portMap
904         * @param moduleContext
905         * @return AbstractName of servlet gbean added
906         * @throws DeploymentException
907         */
908        private AbstractName addServlet(AbstractName webModuleName,
909                WebModule module,
910                AbstractName previousServlet,
911                ServletType servletType,
912                Map servletMappings,
913                Set securityRoles,
914                Map rolePermissions,
915                Map portMap,
916                EARContext moduleContext) throws DeploymentException {
917            ClassLoader webClassLoader = moduleContext.getClassLoader();
918            String servletName = servletType.getServletName().getStringValue().trim();
919            AbstractName servletAbstractName = moduleContext.getNaming().createChildName(webModuleName, servletName, NameFactory.SERVLET);
920            GBeanData servletData;
921            Map initParams = new HashMap();
922            Class baseServletClass;
923            try {
924                baseServletClass = webClassLoader.loadClass(Servlet.class.getName());
925            } catch (ClassNotFoundException e) {
926                throw new DeploymentException("Could not load javax.servlet.Servlet in web classloader", e); // TODO identify web app in message
927            }
928            if (servletType.isSetServletClass()) {
929                String servletClassName = servletType.getServletClass().getStringValue().trim();
930                Class servletClass;
931                try {
932                    servletClass = webClassLoader.loadClass(servletClassName);
933                } catch (ClassNotFoundException e) {
934                    throw new DeploymentException("Could not load servlet class " + servletClassName, e); // TODO identify web app in message
935                }
936                if (baseServletClass.isAssignableFrom(servletClass)) {
937                    servletData = new GBeanData(servletAbstractName, JettyServletHolder.GBEAN_INFO);
938                    servletData.setAttribute("servletClass", servletClassName);
939                } else {
940                    servletData = new GBeanData(pojoWebServiceTemplate);
941                    servletData.setAbstractName(servletAbstractName);
942                    //let the web service builder deal with configuring the gbean with the web service stack
943                    Object portInfo = portMap.get(servletName);
944    //                if (portInfo == null) {
945    //                    throw new DeploymentException("No web service deployment info for servlet name " + servletName); // TODO identify web app in message
946    //                }
947                    getWebServiceBuilder().configurePOJO(servletData, module, portInfo, servletClassName, moduleContext);
948                }
949            } else if (servletType.isSetJspFile()) {
950                servletData = new GBeanData(servletAbstractName, JettyServletHolder.GBEAN_INFO);
951                servletData.setAttribute("jspFile", servletType.getJspFile().getStringValue().trim());
952                //TODO MAKE THIS CONFIGURABLE!!! Jetty uses the servlet mapping set up from the default-web.xml
953                servletData.setAttribute("servletClass", "org.apache.jasper.servlet.JspServlet");
954                initParams.put("development", "false");
955            } else {
956                throw new DeploymentException("Neither servlet class nor jsp file is set for " + servletName); // TODO identify web app in message
957            }
958    
959            // link to previous servlet, if there is one, so that we
960            // preserve the <load-on-startup> ordering.
961            // http://issues.apache.org/jira/browse/GERONIMO-645
962            if (null != previousServlet) {
963                servletData.setReferencePattern("Previous", previousServlet);
964            }
965    
966            //TODO in init param setter, add classpath if jspFile is not null.
967            servletData.setReferencePattern("JettyServletRegistration", webModuleName);
968            servletData.setAttribute("servletName", servletName);
969            ParamValueType[] initParamArray = servletType.getInitParamArray();
970            for (int j = 0; j < initParamArray.length; j++) {
971                ParamValueType paramValueType = initParamArray[j];
972                initParams.put(paramValueType.getParamName().getStringValue().trim(), paramValueType.getParamValue().getStringValue().trim());
973            }
974            servletData.setAttribute("initParams", initParams);
975            if (servletType.isSetLoadOnStartup()) {
976                Integer loadOnStartup = new Integer(servletType.getLoadOnStartup().getBigIntegerValue().intValue());
977                servletData.setAttribute("loadOnStartup", loadOnStartup);
978            }
979    
980            Set mappings = (Set) servletMappings.get(servletName);
981            servletData.setAttribute("servletMappings", mappings == null ? Collections.EMPTY_SET : mappings);
982    
983            //run-as
984            if (servletType.isSetRunAs()) {
985                servletData.setAttribute("runAsRole", servletType.getRunAs().getRoleName().getStringValue().trim());
986            }
987    
988            processRoleRefPermissions(servletType, securityRoles, rolePermissions);
989    
990            try {
991                moduleContext.addGBean(servletData);
992            } catch (GBeanAlreadyExistsException e) {
993                throw new DeploymentException("Could not add servlet gbean to context", e); // TODO identify web app in message
994            }
995            return servletAbstractName;
996        }
997    
998        public static final GBeanInfo GBEAN_INFO;
999    
1000        static {
1001            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(JettyModuleBuilder.class, NameFactory.MODULE_BUILDER);
1002            infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
1003            infoBuilder.addAttribute("defaultSessionTimeoutSeconds", Integer.class, true, true);
1004            infoBuilder.addAttribute("defaultWelcomeFiles", List.class, true, true);
1005            infoBuilder.addAttribute("jettyContainerObjectName", AbstractNameQuery.class, true, true);
1006            infoBuilder.addReference("DefaultServlets", JettyDefaultServletHolder.class, NameFactory.SERVLET_TEMPLATE);
1007            infoBuilder.addReference("DefaultFilters", Object.class);
1008            infoBuilder.addReference("DefaultFilterMappings", Object.class);
1009            infoBuilder.addReference("PojoWebServiceTemplate", Object.class, NameFactory.SERVLET_WEB_SERVICE_TEMPLATE);
1010            infoBuilder.addReference("WebServiceBuilder", WebServiceBuilder.class, NameFactory.MODULE_BUILDER);
1011            infoBuilder.addReference("ClusteringBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
1012            infoBuilder.addReference("SecurityBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
1013            infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
1014            infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER);
1015            infoBuilder.addReference("ResourceEnvironmentSetter", ResourceEnvironmentSetter.class, NameFactory.MODULE_BUILDER);
1016            infoBuilder.addAttribute("kernel", Kernel.class, false);
1017            infoBuilder.addInterface(ModuleBuilder.class);
1018    
1019            infoBuilder.setConstructor(new String[]{
1020                    "defaultEnvironment",
1021                    "defaultSessionTimeoutSeconds",
1022                    "defaultWelcomeFiles",
1023                    "jettyContainerObjectName",
1024                    "DefaultServlets",
1025                    "DefaultFilters",
1026                    "DefaultFilterMappings",
1027                    "PojoWebServiceTemplate",
1028                    "WebServiceBuilder",
1029                    "ClusteringBuilders",
1030                    "SecurityBuilders",
1031                    "ServiceBuilders",
1032                    "NamingBuilders",
1033                    "ResourceEnvironmentSetter",
1034                    "kernel"});
1035            GBEAN_INFO = infoBuilder.getBeanInfo();
1036        }
1037    
1038        public static GBeanInfo getGBeanInfo() {
1039            return GBEAN_INFO;
1040        }
1041    
1042        static class StartupOrderComparator implements Comparator {
1043            /**
1044             * comparator that compares first on the basis of startup order, and then on the lexicographical
1045             * ordering of servlet name.  Since the servlet names have a uniqueness constraint, this should
1046             * provide a total ordering consistent with equals.  All servlets with no startup order are after
1047             * all servlets with a startup order.
1048             *
1049             * @param o1 first ServletType object
1050             * @param o2 second ServletType object
1051             * @return an int < 0 if o1 precedes o2, 0 if they are equal, and > 0 if o2 preceeds o1.
1052             */
1053            public int compare(Object o1, Object o2) {
1054                ServletType s1 = (ServletType) o1;
1055                ServletType s2 = (ServletType) o2;
1056    
1057                // load-on-startup is set for neither.  the
1058                // ordering at this point doesn't matter, but we
1059                // should return "0" only if the two objects say
1060                // they are equal
1061                if (!s1.isSetLoadOnStartup() && !s2.isSetLoadOnStartup()) {
1062                    return s1.equals(s2) ? 0 : s1.getServletName().getStringValue().trim().compareTo(s2.getServletName().getStringValue().trim());
1063                }
1064    
1065                // load-on-startup is set for one but not the
1066                // other.  whichever one is set will be "less
1067                // than", i.e. it will be loaded first
1068                if (s1.isSetLoadOnStartup() && !s2.isSetLoadOnStartup()) {
1069                    return -1;
1070                }
1071                if (!s1.isSetLoadOnStartup() && s2.isSetLoadOnStartup()) {
1072                    return 1;
1073                }
1074    
1075                // load-on-startup is set for both.  whichever one
1076                // has a smaller value is "less than"
1077                int comp = s1.getLoadOnStartup().getBigIntegerValue().compareTo(s2.getLoadOnStartup().getBigIntegerValue());
1078                if (comp == 0) {
1079                    return s1.getServletName().getStringValue().trim().compareTo(s2.getServletName().getStringValue().trim());
1080                }
1081                return comp;
1082            }
1083        }
1084    }