View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  
19  package org.apache.geronimo.jetty.deployment;
20  
21  import java.io.File;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.net.URL;
25  import java.security.Permission;
26  import java.security.PermissionCollection;
27  import java.security.Permissions;
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.Comparator;
32  import java.util.Enumeration;
33  import java.util.HashMap;
34  import java.util.HashSet;
35  import java.util.Iterator;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Set;
39  import java.util.TreeSet;
40  import java.util.jar.JarFile;
41  
42  import javax.management.ObjectName;
43  import javax.servlet.Servlet;
44  
45  import org.apache.commons.logging.Log;
46  import org.apache.commons.logging.LogFactory;
47  import org.apache.geronimo.common.DeploymentException;
48  import org.apache.geronimo.deployment.ModuleIDBuilder;
49  import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
50  import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
51  import org.apache.geronimo.deployment.service.EnvironmentBuilder;
52  import org.apache.geronimo.deployment.util.DeploymentUtil;
53  import org.apache.geronimo.deployment.xbeans.EnvironmentType;
54  import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
55  import org.apache.geronimo.gbean.AbstractName;
56  import org.apache.geronimo.gbean.AbstractNameQuery;
57  import org.apache.geronimo.gbean.GBeanData;
58  import org.apache.geronimo.gbean.GBeanInfo;
59  import org.apache.geronimo.gbean.GBeanInfoBuilder;
60  import org.apache.geronimo.gbean.SingleElementCollection;
61  import org.apache.geronimo.j2ee.deployment.EARContext;
62  import org.apache.geronimo.j2ee.deployment.Module;
63  import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
64  import org.apache.geronimo.j2ee.deployment.NamingBuilder;
65  import org.apache.geronimo.j2ee.deployment.WebModule;
66  import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
67  import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
68  import org.apache.geronimo.jetty.DefaultWebApplicationHandlerFactory;
69  import org.apache.geronimo.jetty.Host;
70  import org.apache.geronimo.jetty.JettyDefaultServletHolder;
71  import org.apache.geronimo.jetty.JettyFilterHolder;
72  import org.apache.geronimo.jetty.JettyFilterMapping;
73  import org.apache.geronimo.jetty.JettyServletHolder;
74  import org.apache.geronimo.jetty.JettyWebAppContext;
75  import org.apache.geronimo.jetty.NonAuthenticator;
76  import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
77  import org.apache.geronimo.kernel.GBeanNotFoundException;
78  import org.apache.geronimo.kernel.Kernel;
79  import org.apache.geronimo.kernel.Naming;
80  import org.apache.geronimo.kernel.config.Configuration;
81  import org.apache.geronimo.kernel.config.ConfigurationData;
82  import org.apache.geronimo.kernel.repository.Environment;
83  import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
84  import org.apache.geronimo.naming.deployment.GBeanResourceEnvironmentBuilder;
85  import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
86  import org.apache.geronimo.security.deploy.DefaultPrincipal;
87  import org.apache.geronimo.security.deployment.SecurityConfiguration;
88  import org.apache.geronimo.security.jacc.ComponentPermissions;
89  import org.apache.geronimo.web.deployment.AbstractWebModuleBuilder;
90  import org.apache.geronimo.web.deployment.GenericToSpecificPlanConverter;
91  import org.apache.geronimo.xbeans.geronimo.web.jetty.JettyWebAppDocument;
92  import org.apache.geronimo.xbeans.geronimo.web.jetty.JettyWebAppType;
93  import org.apache.geronimo.xbeans.geronimo.web.jetty.config.GerJettyDocument;
94  import org.apache.geronimo.xbeans.j2ee.DispatcherType;
95  import org.apache.geronimo.xbeans.j2ee.ErrorPageType;
96  import org.apache.geronimo.xbeans.j2ee.FilterMappingType;
97  import org.apache.geronimo.xbeans.j2ee.FilterType;
98  import org.apache.geronimo.xbeans.j2ee.FormLoginConfigType;
99  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 }