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