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