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 }