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.tomcat.deployment;
019
020 import static java.lang.Boolean.FALSE;
021 import static java.lang.Boolean.TRUE;
022
023 import java.io.File;
024 import java.io.FileNotFoundException;
025 import java.io.FileWriter;
026 import java.io.IOException;
027 import java.net.URL;
028 import java.security.PermissionCollection;
029 import java.util.Collection;
030 import java.util.HashMap;
031 import java.util.Map;
032 import java.util.Set;
033 import java.util.jar.JarFile;
034
035 import javax.servlet.Servlet;
036
037 import org.apache.commons.logging.Log;
038 import org.apache.commons.logging.LogFactory;
039 import org.apache.geronimo.common.DeploymentException;
040 import org.apache.geronimo.deployment.ModuleIDBuilder;
041 import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
042 import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
043 import org.apache.geronimo.deployment.service.EnvironmentBuilder;
044 import org.apache.geronimo.deployment.util.DeploymentUtil;
045 import org.apache.geronimo.deployment.xbeans.EnvironmentType;
046 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
047 import org.apache.geronimo.gbean.AbstractName;
048 import org.apache.geronimo.gbean.AbstractNameQuery;
049 import org.apache.geronimo.gbean.GBeanData;
050 import org.apache.geronimo.gbean.GBeanInfo;
051 import org.apache.geronimo.gbean.GBeanInfoBuilder;
052 import org.apache.geronimo.gbean.ReferencePatterns;
053 import org.apache.geronimo.gbean.GBeanLifecycle;
054 import org.apache.geronimo.j2ee.deployment.EARContext;
055 import org.apache.geronimo.j2ee.deployment.Module;
056 import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
057 import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
058 import org.apache.geronimo.j2ee.deployment.NamingBuilder;
059 import org.apache.geronimo.j2ee.deployment.WebModule;
060 import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
061 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedWebApp;
062 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
063 import org.apache.geronimo.kernel.Kernel;
064 import org.apache.geronimo.kernel.Naming;
065 import org.apache.geronimo.kernel.config.ConfigurationData;
066 import org.apache.geronimo.kernel.repository.Environment;
067 import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
068 import org.apache.geronimo.naming.deployment.GBeanResourceEnvironmentBuilder;
069 import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
070 import org.apache.geronimo.security.jacc.ComponentPermissions;
071 import org.apache.geronimo.tomcat.LifecycleListenerGBean;
072 import org.apache.geronimo.tomcat.ManagerGBean;
073 import org.apache.geronimo.tomcat.RealmGBean;
074 import org.apache.geronimo.tomcat.TomcatWebAppContext;
075 import org.apache.geronimo.tomcat.ValveGBean;
076 import org.apache.geronimo.tomcat.cluster.CatalinaClusterGBean;
077 import org.apache.geronimo.tomcat.util.SecurityHolder;
078 import org.apache.geronimo.web.deployment.GenericToSpecificPlanConverter;
079 import org.apache.geronimo.web25.deployment.AbstractWebModuleBuilder;
080 import org.apache.geronimo.xbeans.geronimo.j2ee.GerClusteringDocument;
081 import org.apache.geronimo.xbeans.geronimo.web.tomcat.TomcatWebAppDocument;
082 import org.apache.geronimo.xbeans.geronimo.web.tomcat.TomcatWebAppType;
083 import org.apache.geronimo.xbeans.geronimo.web.tomcat.config.GerTomcatDocument;
084 import org.apache.geronimo.xbeans.javaee.EjbLocalRefType;
085 import org.apache.geronimo.xbeans.javaee.EjbRefType;
086 import org.apache.geronimo.xbeans.javaee.EnvEntryType;
087 import org.apache.geronimo.xbeans.javaee.LifecycleCallbackType;
088 import org.apache.geronimo.xbeans.javaee.MessageDestinationRefType;
089 import org.apache.geronimo.xbeans.javaee.MessageDestinationType;
090 import org.apache.geronimo.xbeans.javaee.PersistenceContextRefType;
091 import org.apache.geronimo.xbeans.javaee.PersistenceUnitRefType;
092 import org.apache.geronimo.xbeans.javaee.ResourceEnvRefType;
093 import org.apache.geronimo.xbeans.javaee.ResourceRefType;
094 import org.apache.geronimo.xbeans.javaee.ServiceRefType;
095 import org.apache.geronimo.xbeans.javaee.ServletType;
096 import org.apache.geronimo.xbeans.javaee.WebAppDocument;
097 import org.apache.geronimo.xbeans.javaee.WebAppType;
098 import org.apache.xmlbeans.XmlCursor;
099 import org.apache.xmlbeans.XmlException;
100 import org.apache.xmlbeans.XmlObject;
101 import org.apache.xmlbeans.XmlOptions;
102
103 /**
104 * @version $Rev:385659 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
105 */
106 public class TomcatModuleBuilder extends AbstractWebModuleBuilder implements GBeanLifecycle {
107
108 private static final Log log = LogFactory.getLog(TomcatModuleBuilder.class);
109
110 private static final String TOMCAT_NAMESPACE = TomcatWebAppDocument.type.getDocumentElementName().getNamespaceURI();
111 private static final String IS_JAVAEE = "IS_JAVAEE";
112 private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>();
113 static {
114 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
115 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-1.1", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
116 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-1.2", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
117 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web-2.0", "http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1");
118 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/tomcat", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
119 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-1.1", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
120 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-1.2", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
121 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1");
122 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/web/tomcat/config", "http://geronimo.apache.org/xml/ns/j2ee/web/tomcat/config-1.0");
123 }
124
125 private final Environment defaultEnvironment;
126 private final AbstractNameQuery tomcatContainerName;
127 protected final NamespaceDrivenBuilderCollection clusteringBuilders;
128
129 public TomcatModuleBuilder(Environment defaultEnvironment,
130 AbstractNameQuery tomcatContainerName,
131 Collection<WebServiceBuilder> webServiceBuilder,
132 Collection securityBuilders,
133 Collection serviceBuilders,
134 NamingBuilder namingBuilders,
135 Collection<NamespaceDrivenBuilder> clusteringBuilders,
136 Collection<ModuleBuilderExtension> moduleBuilderExtensions,
137 ResourceEnvironmentSetter resourceEnvironmentSetter,
138 Kernel kernel) {
139 super(kernel, securityBuilders, serviceBuilders, namingBuilders, resourceEnvironmentSetter, webServiceBuilder, moduleBuilderExtensions);
140 this.defaultEnvironment = defaultEnvironment;
141 this.clusteringBuilders = new NamespaceDrivenBuilderCollection(clusteringBuilders, GerClusteringDocument.type.getDocumentElementName());
142 this.tomcatContainerName = tomcatContainerName;
143 }
144
145 public void doStart() throws Exception {
146 XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES);
147 }
148
149 public void doStop() {
150 XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES);
151 }
152
153 public void doFail() {
154 doStop();
155 }
156
157 protected Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, boolean standAlone, String contextRoot, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
158 assert moduleFile != null : "moduleFile is null";
159 assert targetPath != null : "targetPath is null";
160 assert !targetPath.endsWith("/") : "targetPath must not end with a '/'";
161
162 // parse the spec dd
163 String specDD = null;
164 WebAppType webApp = null;
165 Boolean isJavaee;
166 try {
167 if (specDDUrl == null) {
168 specDDUrl = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/web.xml");
169 }
170
171 // read in the entire specDD as a string, we need this for getDeploymentDescriptor
172 // on the J2ee management object
173 specDD = DeploymentUtil.readAll(specDDUrl);
174
175 // we found web.xml, if it won't parse that's an error.
176 XmlObject parsed = XmlBeansUtil.parse(specDD);
177 //Dont save updated xml if it isn't javaee
178 XmlCursor cursor = parsed.newCursor();
179 try {
180 cursor.toStartDoc();
181 cursor.toFirstChild();
182 isJavaee = "http://java.sun.com/xml/ns/javaee".equals(cursor.getName().getNamespaceURI());
183 } finally {
184 cursor.dispose();
185 }
186 WebAppDocument webAppDoc = convertToServletSchema(parsed);
187 webApp = webAppDoc.getWebApp();
188 check(webApp);
189 } catch (XmlException e) {
190 // Output the target path in the error to make it clearer to the user which webapp
191 // has the problem. The targetPath is used, as moduleFile may have an unhelpful
192 // value such as C:\geronimo-1.1\var\temp\geronimo-deploymentUtil22826.tmpdir
193 throw new DeploymentException("Error parsing web.xml for " + targetPath, e);
194 } catch (Exception e) {
195 if (!moduleFile.getName().endsWith(".war")) {
196 //not for us
197 return null;
198 }
199 isJavaee = true;
200 //else ignore as jee5 allows optional spec dd for .war's
201 }
202
203 if (webApp == null)
204 webApp = WebAppType.Factory.newInstance();
205
206 // parse vendor dd
207 TomcatWebAppType tomcatWebApp = getTomcatWebApp(plan, moduleFile, standAlone, targetPath, webApp);
208 contextRoot = getContextRoot(tomcatWebApp, contextRoot, webApp, standAlone, moduleFile, targetPath);
209
210 EnvironmentType environmentType = tomcatWebApp.getEnvironment();
211 Environment environment = EnvironmentBuilder.buildEnvironment(environmentType, defaultEnvironment);
212
213 Boolean distributable = webApp.getDistributableArray().length == 1 ? TRUE : FALSE;
214 if (TRUE == distributable) {
215 clusteringBuilders.buildEnvironment(tomcatWebApp, environment);
216 }
217
218 // Note: logic elsewhere depends on the default artifact ID being the file name less extension (ConfigIDExtractor)
219 String warName = "";
220 File temp = new File(moduleFile.getName());
221 if (temp.isFile()) {
222 warName = temp.getName();
223 if (warName.lastIndexOf('.') > -1) {
224 warName = warName.substring(0, warName.lastIndexOf('.'));
225 }
226 } else {
227 try {
228 warName = temp.getCanonicalFile().getName();
229 if (warName.equals("")) {
230 // Root directory
231 warName = "$root-dir$";
232 }
233 } catch (IOException e) {
234 //really?
235 }
236 }
237 idBuilder.resolve(environment, warName, "war");
238
239 AbstractName moduleName;
240 if (earName == null) {
241 earName = naming.createRootName(environment.getConfigId(), NameFactory.NULL, NameFactory.J2EE_APPLICATION);
242 moduleName = naming.createChildName(earName, environment.getConfigId().toString(), NameFactory.WEB_MODULE);
243 } else {
244 moduleName = naming.createChildName(earName, targetPath, NameFactory.WEB_MODULE);
245 }
246
247 // Create the AnnotatedApp interface for the WebModule
248 AnnotatedWebApp annotatedWebApp = new AnnotatedWebApp(webApp);
249
250 WebModule module = new WebModule(standAlone, moduleName, environment, moduleFile, targetPath, webApp, tomcatWebApp, specDD, contextRoot, TOMCAT_NAMESPACE, annotatedWebApp);
251 for (ModuleBuilderExtension mbe : moduleBuilderExtensions) {
252 mbe.createModule(module, plan, moduleFile, targetPath, specDDUrl, environment, contextRoot, earName, naming, idBuilder);
253 }
254 module.getSharedContext().put(IS_JAVAEE, isJavaee);
255 return module;
256 }
257
258 private String getContextRoot(TomcatWebAppType tomcatWebApp, String contextRoot, WebAppType webApp, boolean standAlone, JarFile moduleFile, String targetPath) {
259 //If we have a context root, override everything
260 if (tomcatWebApp.isSetContextRoot()) {
261 contextRoot = tomcatWebApp.getContextRoot();
262 } else if (contextRoot == null || contextRoot.trim().equals("")) {
263 //Otherwise if no contextRoot was passed in from the ear, then make up a default
264 contextRoot = determineDefaultContextRoot(webApp, standAlone, moduleFile, targetPath);
265 }
266 contextRoot = contextRoot.trim();
267 if (contextRoot.length() > 0) {
268 // only force the context root to start with a forward slash
269 // if it is not null
270 if (!contextRoot.startsWith("/")) {
271 //I'm not sure if we should always fix up peculiar context roots.
272 contextRoot = "/" + contextRoot;
273 }
274 }
275 return contextRoot;
276 }
277
278
279 TomcatWebAppType getTomcatWebApp(Object plan, JarFile moduleFile, boolean standAlone, String targetPath, WebAppType webApp) throws DeploymentException {
280 XmlObject rawPlan = null;
281 try {
282 // load the geronimo-web.xml from either the supplied plan or from the earFile
283 try {
284 if (plan instanceof XmlObject) {
285 rawPlan = (XmlObject) plan;
286 } else {
287 if (plan != null) {
288 rawPlan = XmlBeansUtil.parse(((File) plan).toURL(), getClass().getClassLoader());
289 } else {
290 URL path = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/geronimo-web.xml");
291 try {
292 rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
293 } catch (FileNotFoundException e) {
294 path = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/geronimo-tomcat.xml");
295 try {
296 rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
297 } catch (FileNotFoundException e1) {
298 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.");
299 }
300 }
301 }
302 }
303 } catch (IOException e) {
304 log.warn(e);
305 }
306
307 TomcatWebAppType tomcatWebApp;
308 if (rawPlan != null) {
309 XmlObject webPlan = new GenericToSpecificPlanConverter(GerTomcatDocument.type.getDocumentElementName().getNamespaceURI(),
310 TomcatWebAppDocument.type.getDocumentElementName().getNamespaceURI(), "tomcat").convertToSpecificPlan(rawPlan);
311 tomcatWebApp = (TomcatWebAppType) webPlan.changeType(TomcatWebAppType.type);
312 XmlBeansUtil.validateDD(tomcatWebApp);
313 } else {
314 tomcatWebApp = createDefaultPlan();
315 }
316 return tomcatWebApp;
317 } catch (XmlException e) {
318 throw new DeploymentException("xml problem for web app " + targetPath, e);
319 }
320 }
321
322 private TomcatWebAppType createDefaultPlan() {
323 return TomcatWebAppType.Factory.newInstance();
324 }
325
326
327 public void initContext(EARContext earContext, Module module, ClassLoader cl) throws DeploymentException {
328 TomcatWebAppType gerWebApp = (TomcatWebAppType) module.getVendorDD();
329 boolean hasSecurityRealmName = gerWebApp.isSetSecurityRealmName();
330 basicInitContext(earContext, module, gerWebApp, hasSecurityRealmName);
331 for (ModuleBuilderExtension mbe : moduleBuilderExtensions) {
332 mbe.initContext(earContext, module, cl);
333 }
334 }
335
336 public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repository) throws DeploymentException {
337 EARContext moduleContext = module.getEarContext();
338 ClassLoader webClassLoader = moduleContext.getClassLoader();
339 AbstractName moduleName = moduleContext.getModuleName();
340 WebModule webModule = (WebModule) module;
341
342 WebAppType webApp = (WebAppType) webModule.getSpecDD();
343
344 TomcatWebAppType tomcatWebApp = (TomcatWebAppType) webModule.getVendorDD();
345
346 GBeanData webModuleData = new GBeanData(moduleName, TomcatWebAppContext.GBEAN_INFO);
347 configureBasicWebModuleAttributes(webApp, tomcatWebApp, moduleContext, earContext, webModule, webModuleData);
348 try {
349 moduleContext.addGBean(webModuleData);
350 Set<String> securityRoles = collectRoleNames(webApp);
351 Map<String, PermissionCollection> rolePermissions = new HashMap<String, PermissionCollection>();
352 webModuleData.setAttribute("contextPath", webModule.getContextRoot());
353 // unsharableResources, applicationManagedSecurityResources
354 GBeanResourceEnvironmentBuilder rebuilder = new GBeanResourceEnvironmentBuilder(webModuleData);
355 //N.B. use earContext not moduleContext
356 resourceEnvironmentSetter.setResourceEnvironment(rebuilder, webApp.getResourceRefArray(), tomcatWebApp.getResourceRefArray());
357
358 if (tomcatWebApp.isSetWebContainer()) {
359 AbstractNameQuery webContainerName = ENCConfigBuilder.getGBeanQuery(NameFactory.GERONIMO_SERVICE, tomcatWebApp.getWebContainer());
360 webModuleData.setReferencePattern("Container", webContainerName);
361 } else {
362 webModuleData.setReferencePattern("Container", tomcatContainerName);
363 }
364 // Process the Tomcat container-config elements
365 if (tomcatWebApp.isSetHost()) {
366 String virtualServer = tomcatWebApp.getHost().trim();
367 webModuleData.setAttribute("virtualServer", virtualServer);
368 }
369 if (tomcatWebApp.isSetCrossContext()) {
370 webModuleData.setAttribute("crossContext", Boolean.TRUE);
371 }
372 if (tomcatWebApp.isSetWorkDir()) {
373 String workDir = tomcatWebApp.getWorkDir();
374 webModuleData.setAttribute("workDir", workDir);
375 }
376 if (tomcatWebApp.isSetDisableCookies()) {
377 webModuleData.setAttribute("disableCookies", Boolean.TRUE);
378 }
379 if (tomcatWebApp.isSetTomcatRealm()) {
380 String tomcatRealm = tomcatWebApp.getTomcatRealm().trim();
381 AbstractName realmName = earContext.getNaming().createChildName(moduleName, tomcatRealm, RealmGBean.GBEAN_INFO.getJ2eeType());
382 webModuleData.setReferencePattern("TomcatRealm", realmName);
383 }
384 if (tomcatWebApp.isSetValveChain()) {
385 String valveChain = tomcatWebApp.getValveChain().trim();
386 AbstractName valveName = earContext.getNaming().createChildName(moduleName, valveChain, ValveGBean.J2EE_TYPE);
387 webModuleData.setReferencePattern("TomcatValveChain", valveName);
388 }
389
390 if (tomcatWebApp.isSetListenerChain()) {
391 String listenerChain = tomcatWebApp.getListenerChain().trim();
392 AbstractName listenerName = earContext.getNaming().createChildName(moduleName, listenerChain, LifecycleListenerGBean.J2EE_TYPE);
393 webModuleData.setReferencePattern("LifecycleListenerChain", listenerName);
394 }
395
396 if (tomcatWebApp.isSetCluster()) {
397 String cluster = tomcatWebApp.getCluster().trim();
398 AbstractName clusterName = earContext.getNaming().createChildName(moduleName, cluster, CatalinaClusterGBean.J2EE_TYPE);
399 webModuleData.setReferencePattern("Cluster", clusterName);
400 }
401
402 if (tomcatWebApp.isSetManager()) {
403 String manager = tomcatWebApp.getManager().trim();
404 AbstractName managerName = earContext.getNaming().createChildName(moduleName, manager, ManagerGBean.J2EE_TYPE);
405 webModuleData.setReferencePattern("Manager", managerName);
406 }
407
408 Boolean distributable = webApp.getDistributableArray().length == 1 ? TRUE : FALSE;
409 if (TRUE == distributable) {
410 clusteringBuilders.build(tomcatWebApp, earContext, moduleContext);
411 if (null == webModuleData.getReferencePatterns(TomcatWebAppContext.GBEAN_REF_CLUSTERED_VALVE_RETRIEVER)) {
412 log.warn("No clustering builders configured: app will not be clustered");
413 }
414 }
415
416 //Handle the role permissions and webservices on the servlets.
417 ServletType[] servletTypes = webApp.getServletArray();
418 Map<String, AbstractName> webServices = new HashMap<String, AbstractName>();
419 Class baseServletClass;
420 try {
421 baseServletClass = webClassLoader.loadClass(Servlet.class.getName());
422 } catch (ClassNotFoundException e) {
423 throw new DeploymentException("Could not load javax.servlet.Servlet in web classloader", e); // TODO identify web app in message
424 }
425 for (ServletType servletType : servletTypes) {
426 //Handle the Role Ref Permissions
427 processRoleRefPermissions(servletType, securityRoles, rolePermissions);
428
429 if (servletType.isSetServletClass()) {
430 String servletName = servletType.getServletName().getStringValue().trim();
431 String servletClassName = servletType.getServletClass().getStringValue().trim();
432 Class servletClass;
433 try {
434 servletClass = webClassLoader.loadClass(servletClassName);
435 } catch (ClassNotFoundException e) {
436 throw new DeploymentException("Could not load servlet class " + servletClassName, e); // TODO identify web app in message
437 }
438 if (!baseServletClass.isAssignableFrom(servletClass)) {
439 //fake servletData
440 AbstractName servletAbstractName = moduleContext.getNaming().createChildName(moduleName, servletName, NameFactory.SERVLET);
441 GBeanData servletData = new GBeanData();
442 servletData.setAbstractName(servletAbstractName);
443 //let the web service builder deal with configuring the gbean with the web service stack
444 //Here we just extract the factory reference
445 boolean configured = false;
446 for (WebServiceBuilder serviceBuilder : webServiceBuilder) {
447 if (serviceBuilder.configurePOJO(servletData, servletName, module, servletClassName, moduleContext)) {
448 configured = true;
449 break;
450 }
451 }
452 if (!configured) {
453 throw new DeploymentException("POJO web service: " + servletName + " not configured by any web service builder");
454 }
455 ReferencePatterns patterns = servletData.getReferencePatterns("WebServiceContainerFactory");
456 AbstractName wsContainerFactoryName = patterns.getAbstractName();
457 webServices.put(servletName, wsContainerFactoryName);
458 //force all the factories to start before the web app that needs them.
459 webModuleData.addDependency(wsContainerFactoryName);
460 }
461
462 }
463 }
464
465 // JACC v1.0 secion B.19
466 addUnmappedJSPPermissions(securityRoles, rolePermissions);
467
468 webModuleData.setAttribute("webServices", webServices);
469
470 if (tomcatWebApp.isSetSecurityRealmName()) {
471 if (earContext.getSecurityConfiguration() == null) {
472 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)");
473 }
474
475 SecurityHolder securityHolder = new SecurityHolder();
476 securityHolder.setSecurityRealm(tomcatWebApp.getSecurityRealmName().trim());
477
478 webModuleData.setReferencePattern("RunAsSource", earContext.getJaccManagerName());
479
480 /**
481 * TODO - go back to commented version when possible.
482 */
483 String policyContextID = moduleName.toString().replaceAll("[, :]", "_");
484 securityHolder.setPolicyContextID(policyContextID);
485
486 ComponentPermissions componentPermissions = buildSpecSecurityConfig(webApp, securityRoles, rolePermissions);
487 earContext.addSecurityContext(policyContextID, componentPermissions);
488 //TODO WTF is this for?
489 securityHolder.setSecurity(true);
490
491 webModuleData.setAttribute("securityHolder", securityHolder);
492 }
493
494 //listeners added directly to the StandardContext will get loaded by the tomcat classloader, not the app classloader!
495 //TODO this may definitely not be the best place for this!
496 for (ModuleBuilderExtension mbe : moduleBuilderExtensions) {
497 mbe.addGBeans(earContext, module, cl, repository);
498 }
499 //not truly metadata complete until MBEs have run
500 if (!webApp.getMetadataComplete()) {
501 webApp.setMetadataComplete(true);
502 module.setOriginalSpecDD(module.getSpecDD().toString());
503 }
504 webModuleData.setAttribute("deploymentDescriptor", module.getOriginalSpecDD());
505 /**
506 * This next bit of code is kind of a kludge to get Tomcat to get a default
507 * web.xml if one does not exist. This is primarily for jaxws. This code is
508 * necessary because Tomcat either has a bug or there is a problem dynamically
509 * adding a wrapper to an already running context. Although the wrapper
510 * can be added, the url mappings do not get picked up at the proper level
511 * and therefore Tomcat cannot dispatch the request. Hence, creating and
512 * writing out a web.xml to the deployed location is the only way around this
513 * until Tomcat fixes that bug.
514 *
515 * For myfaces/jsf, the spec dd may have been updated with a listener. So, we need to write it out again whether or not
516 * there originally was one. This might not work on windows due to file locking problems.
517 */
518
519 if ((Boolean)module.getSharedContext().get(IS_JAVAEE)) {
520 WebAppType shortWebApp = (WebAppType) webApp.copy();
521 shortWebApp.setEjbLocalRefArray(new EjbLocalRefType[0]);
522 shortWebApp.setEjbRefArray(new EjbRefType[0]);
523 shortWebApp.setEnvEntryArray(new EnvEntryType[0]);
524 shortWebApp.setMessageDestinationArray(new MessageDestinationType[0]);
525 shortWebApp.setMessageDestinationRefArray(new MessageDestinationRefType[0]);
526 shortWebApp.setPersistenceContextRefArray(new PersistenceContextRefType[0]);
527 shortWebApp.setPersistenceUnitRefArray(new PersistenceUnitRefType[0]);
528 shortWebApp.setPostConstructArray(new LifecycleCallbackType[0]);
529 shortWebApp.setPreDestroyArray(new LifecycleCallbackType[0]);
530 shortWebApp.setResourceEnvRefArray(new ResourceEnvRefType[0]);
531 shortWebApp.setResourceRefArray(new ResourceRefType[0]);
532 shortWebApp.setServiceRefArray(new ServiceRefType[0]);
533 // TODO Tomcat will fail web services tck tests if the following security settings are set in shortWebApp
534 // need to figure out why...
535 //One clue is that without this stuff tomcat does not install an authenticator.... so there's no security
536 // shortWebApp.setSecurityConstraintArray(new SecurityConstraintType[0]);
537 // shortWebApp.setSecurityRoleArray(new SecurityRoleType[0]);
538 File webXml = new File(moduleContext.getBaseDir(), "/WEB-INF/web.xml");
539 File inPlaceDir = moduleContext.getInPlaceConfigurationDir();
540 if (inPlaceDir != null) {
541 webXml = new File(inPlaceDir, "/WEB-INF/web.xml");
542 }
543 // boolean webXmlExists = (inPlaceDir != null && new File(inPlaceDir,"/WEB-INF/web.xml").exists()) || webXml.exists();
544 // if (!webXmlExists) {
545 webXml.getParentFile().mkdirs();
546 try {
547 FileWriter outFile = new FileWriter(webXml);
548
549 XmlOptions opts = new XmlOptions();
550 opts.setSaveAggressiveNamespaces();
551 opts.setSaveSyntheticDocumentElement(WebAppDocument.type.getDocumentElementName());
552 opts.setUseDefaultNamespace();
553 opts.setSavePrettyPrint();
554
555 // WebAppDocument doc = WebAppDocument.Factory.newInstance();
556 // doc.setWebApp(webApp);
557
558 outFile.write(shortWebApp.xmlText(opts));
559 outFile.flush();
560 outFile.close();
561 } catch (Exception e) {
562 throw new DeploymentException(e);
563 }
564 // }
565 }
566
567 if (!module.isStandAlone()) {
568 ConfigurationData moduleConfigurationData = moduleContext.getConfigurationData();
569 earContext.addChildConfiguration(module.getTargetPath(), moduleConfigurationData);
570 }
571 } catch (DeploymentException de) {
572 throw de;
573 } catch (Exception e) {
574 throw new DeploymentException("Unable to initialize GBean for web app " + module.getName(), e);
575 }
576 }
577
578 public String getSchemaNamespace() {
579 return TOMCAT_NAMESPACE;
580 }
581
582
583 public static final GBeanInfo GBEAN_INFO;
584 public static final String GBEAN_REF_CLUSTERING_BUILDERS = "ClusteringBuilders";
585
586 static {
587 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(TomcatModuleBuilder.class, NameFactory.MODULE_BUILDER);
588 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
589 infoBuilder.addAttribute("tomcatContainerName", AbstractNameQuery.class, true, true);
590 infoBuilder.addReference("WebServiceBuilder", WebServiceBuilder.class, NameFactory.MODULE_BUILDER);
591 infoBuilder.addReference("SecurityBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
592 infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
593 infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER);
594 infoBuilder.addReference(GBEAN_REF_CLUSTERING_BUILDERS, NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
595 infoBuilder.addReference("ModuleBuilderExtensions", ModuleBuilderExtension.class, NameFactory.MODULE_BUILDER);
596 infoBuilder.addReference("ResourceEnvironmentSetter", ResourceEnvironmentSetter.class, NameFactory.MODULE_BUILDER);
597 infoBuilder.addAttribute("kernel", Kernel.class, false);
598 infoBuilder.addInterface(ModuleBuilder.class);
599
600 infoBuilder.setConstructor(new String[]{
601 "defaultEnvironment",
602 "tomcatContainerName",
603 "WebServiceBuilder",
604 "SecurityBuilders",
605 "ServiceBuilders",
606 "NamingBuilders",
607 GBEAN_REF_CLUSTERING_BUILDERS,
608 "ModuleBuilderExtensions",
609 "ResourceEnvironmentSetter",
610 "kernel"});
611 GBEAN_INFO = infoBuilder.getBeanInfo();
612 }
613
614 public static GBeanInfo getGBeanInfo() {
615 return GBEAN_INFO;
616 }
617
618 }