0001: /**
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */package org.apache.geronimo.web25.deployment;
0017:
0018: import java.io.File;
0019: import java.io.IOException;
0020: import java.net.URI;
0021: import java.net.URISyntaxException;
0022: import java.net.URL;
0023: import java.security.Permission;
0024: import java.security.PermissionCollection;
0025: import java.security.Permissions;
0026: import java.util.ArrayList;
0027: import java.util.Collection;
0028: import java.util.Collections;
0029: import java.util.Enumeration;
0030: import java.util.HashMap;
0031: import java.util.HashSet;
0032: import java.util.LinkedList;
0033: import java.util.List;
0034: import java.util.Map;
0035: import java.util.Set;
0036: import java.util.LinkedHashSet;
0037: import java.util.jar.JarEntry;
0038: import java.util.jar.JarFile;
0039: import java.util.zip.ZipEntry;
0040:
0041: import javax.security.jacc.WebResourcePermission;
0042: import javax.security.jacc.WebRoleRefPermission;
0043: import javax.security.jacc.WebUserDataPermission;
0044: import javax.xml.namespace.QName;
0045:
0046: import org.apache.commons.logging.Log;
0047: import org.apache.commons.logging.LogFactory;
0048: import org.apache.geronimo.common.DeploymentException;
0049: import org.apache.geronimo.deployment.ModuleIDBuilder;
0050: import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
0051: import org.apache.geronimo.deployment.ClassPathList;
0052: import org.apache.geronimo.deployment.ModuleList;
0053: import org.apache.geronimo.deployment.util.DeploymentUtil;
0054: import org.apache.geronimo.deployment.xbeans.ServiceDocument;
0055: import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
0056: import org.apache.geronimo.gbean.AbstractName;
0057: import org.apache.geronimo.gbean.AbstractNameQuery;
0058: import org.apache.geronimo.gbean.GBeanData;
0059: import org.apache.geronimo.j2ee.annotation.Holder;
0060: import org.apache.geronimo.j2ee.deployment.EARContext;
0061: import org.apache.geronimo.j2ee.deployment.Module;
0062: import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
0063: import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
0064: import org.apache.geronimo.j2ee.deployment.NamingBuilder;
0065: import org.apache.geronimo.j2ee.deployment.WebModule;
0066: import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
0067: import org.apache.geronimo.j2ee.deployment.annotation.SecurityAnnotationHelper;
0068: import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
0069: import org.apache.geronimo.kernel.Kernel;
0070: import org.apache.geronimo.kernel.Naming;
0071: import org.apache.geronimo.kernel.config.Configuration;
0072: import org.apache.geronimo.kernel.config.ConfigurationModuleType;
0073: import org.apache.geronimo.kernel.config.ConfigurationStore;
0074: import org.apache.geronimo.kernel.repository.Artifact;
0075: import org.apache.geronimo.kernel.repository.Environment;
0076: import org.apache.geronimo.kernel.repository.ImportType;
0077: import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
0078: import org.apache.geronimo.schema.SchemaConversionUtils;
0079: import org.apache.geronimo.security.jacc.ComponentPermissions;
0080: import org.apache.geronimo.security.util.HTTPMethods;
0081: import org.apache.geronimo.security.util.URLPattern;
0082: import org.apache.geronimo.xbeans.geronimo.j2ee.GerSecurityDocument;
0083: import org.apache.geronimo.xbeans.javaee.FilterMappingType;
0084: import org.apache.geronimo.xbeans.javaee.FilterType;
0085: import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType;
0086: import org.apache.geronimo.xbeans.javaee.ListenerType;
0087: import org.apache.geronimo.xbeans.javaee.RoleNameType;
0088: import org.apache.geronimo.xbeans.javaee.SecurityConstraintType;
0089: import org.apache.geronimo.xbeans.javaee.SecurityRoleRefType;
0090: import org.apache.geronimo.xbeans.javaee.SecurityRoleType;
0091: import org.apache.geronimo.xbeans.javaee.ServletMappingType;
0092: import org.apache.geronimo.xbeans.javaee.ServletType;
0093: import org.apache.geronimo.xbeans.javaee.UrlPatternType;
0094: import org.apache.geronimo.xbeans.javaee.WebAppDocument;
0095: import org.apache.geronimo.xbeans.javaee.WebAppType;
0096: import org.apache.geronimo.xbeans.javaee.WebResourceCollectionType;
0097: import org.apache.xbean.finder.ClassFinder;
0098: import org.apache.xmlbeans.XmlCursor;
0099: import org.apache.xmlbeans.XmlDocumentProperties;
0100: import org.apache.xmlbeans.XmlException;
0101: import org.apache.xmlbeans.XmlObject;
0102:
0103: /**
0104: * @version $Rev: 609569 $ $Date: 2008-01-07 03:03:18 -0800 (Mon, 07 Jan 2008) $
0105: */
0106: public abstract class AbstractWebModuleBuilder implements ModuleBuilder {
0107: private static final Log log = LogFactory
0108: .getLog(AbstractWebModuleBuilder.class);
0109:
0110: private static final QName TAGLIB = new QName(
0111: SchemaConversionUtils.JAVAEE_NAMESPACE, "taglib");
0112:
0113: private static final String LINE_SEP = System
0114: .getProperty("line.separator");
0115:
0116: protected static final AbstractNameQuery MANAGED_CONNECTION_FACTORY_PATTERN;
0117: private static final AbstractNameQuery ADMIN_OBJECT_PATTERN;
0118: protected static final AbstractNameQuery STATELESS_SESSION_BEAN_PATTERN;
0119: protected static final AbstractNameQuery STATEFUL_SESSION_BEAN_PATTERN;
0120: protected static final AbstractNameQuery ENTITY_BEAN_PATTERN;
0121: protected final Kernel kernel;
0122: protected final NamespaceDrivenBuilderCollection securityBuilders;
0123: protected final NamespaceDrivenBuilderCollection serviceBuilders;
0124: protected final ResourceEnvironmentSetter resourceEnvironmentSetter;
0125: protected final Collection<WebServiceBuilder> webServiceBuilder;
0126:
0127: protected final NamingBuilder namingBuilders;
0128: protected final Collection<ModuleBuilderExtension> moduleBuilderExtensions;
0129:
0130: private static final QName SECURITY_QNAME = GerSecurityDocument.type
0131: .getDocumentElementName();
0132: private static final QName SERVICE_QNAME = ServiceDocument.type
0133: .getDocumentElementName();
0134:
0135: /**
0136: * Manifest classpath entries in a war configuration must be resolved relative to the war configuration, not the
0137: * enclosing ear configuration. Resolving relative to he war configuration using this offset produces the same
0138: * effect as URI.create(module.targetPath()).resolve(mcpEntry) executed in the ear configuration.
0139: */
0140: private static final URI RELATIVE_MODULE_BASE_URI = URI
0141: .create("../");
0142:
0143: protected AbstractWebModuleBuilder(Kernel kernel,
0144: Collection securityBuilders, Collection serviceBuilders,
0145: NamingBuilder namingBuilders,
0146: ResourceEnvironmentSetter resourceEnvironmentSetter,
0147: Collection<WebServiceBuilder> webServiceBuilder,
0148: Collection<ModuleBuilderExtension> moduleBuilderExtensions) {
0149: this .kernel = kernel;
0150: this .securityBuilders = new NamespaceDrivenBuilderCollection(
0151: securityBuilders, SECURITY_QNAME);
0152: this .serviceBuilders = new NamespaceDrivenBuilderCollection(
0153: serviceBuilders, SERVICE_QNAME);
0154: this .namingBuilders = namingBuilders;
0155: this .resourceEnvironmentSetter = resourceEnvironmentSetter;
0156: this .webServiceBuilder = webServiceBuilder;
0157: this .moduleBuilderExtensions = moduleBuilderExtensions == null ? new ArrayList<ModuleBuilderExtension>()
0158: : moduleBuilderExtensions;
0159: }
0160:
0161: static {
0162: MANAGED_CONNECTION_FACTORY_PATTERN = new AbstractNameQuery(
0163: null, Collections.singletonMap(NameFactory.J2EE_TYPE,
0164: NameFactory.JCA_MANAGED_CONNECTION_FACTORY));
0165: ADMIN_OBJECT_PATTERN = new AbstractNameQuery(null, Collections
0166: .singletonMap(NameFactory.J2EE_TYPE,
0167: NameFactory.JCA_ADMIN_OBJECT));
0168: STATELESS_SESSION_BEAN_PATTERN = new AbstractNameQuery(null,
0169: Collections.singletonMap(NameFactory.J2EE_TYPE,
0170: NameFactory.STATELESS_SESSION_BEAN));
0171: STATEFUL_SESSION_BEAN_PATTERN = new AbstractNameQuery(null,
0172: Collections.singletonMap(NameFactory.J2EE_TYPE,
0173: NameFactory.STATEFUL_SESSION_BEAN));
0174: ENTITY_BEAN_PATTERN = new AbstractNameQuery(null, Collections
0175: .singletonMap(NameFactory.J2EE_TYPE,
0176: NameFactory.ENTITY_BEAN));
0177:
0178: }
0179:
0180: public NamingBuilder getNamingBuilders() {
0181: return namingBuilders;
0182: }
0183:
0184: protected void addGBeanDependencies(EARContext earContext,
0185: GBeanData webModuleData) {
0186: Configuration earConfiguration = earContext.getConfiguration();
0187: addDependencies(earContext.findGBeanDatas(earConfiguration,
0188: MANAGED_CONNECTION_FACTORY_PATTERN), webModuleData);
0189: addDependencies(earContext.findGBeanDatas(earConfiguration,
0190: ADMIN_OBJECT_PATTERN), webModuleData);
0191: addDependencies(earContext.findGBeanDatas(earConfiguration,
0192: STATELESS_SESSION_BEAN_PATTERN), webModuleData);
0193: addDependencies(earContext.findGBeanDatas(earConfiguration,
0194: STATEFUL_SESSION_BEAN_PATTERN), webModuleData);
0195: addDependencies(earContext.findGBeanDatas(earConfiguration,
0196: ENTITY_BEAN_PATTERN), webModuleData);
0197: }
0198:
0199: private void addDependencies(LinkedHashSet<GBeanData> dependencies,
0200: GBeanData webModuleData) {
0201: for (GBeanData dependency : dependencies) {
0202: AbstractName dependencyName = dependency.getAbstractName();
0203: webModuleData.addDependency(dependencyName);
0204: }
0205: }
0206:
0207: public Module createModule(File plan, JarFile moduleFile,
0208: Naming naming, ModuleIDBuilder idBuilder)
0209: throws DeploymentException {
0210: return createModule(plan, moduleFile, ".", null, true, null,
0211: null, naming, idBuilder);
0212: }
0213:
0214: public Module createModule(Object plan, JarFile moduleFile,
0215: String targetPath, URL specDDUrl, Environment environment,
0216: Object moduleContextInfo, AbstractName earName,
0217: Naming naming, ModuleIDBuilder idBuilder)
0218: throws DeploymentException {
0219: return createModule(plan, moduleFile, targetPath, specDDUrl,
0220: false, (String) moduleContextInfo, earName, naming,
0221: idBuilder);
0222: }
0223:
0224: protected abstract Module createModule(Object plan,
0225: JarFile moduleFile, String targetPath, URL specDDUrl,
0226: boolean standAlone, String contextRoot,
0227: AbstractName earName, Naming naming,
0228: ModuleIDBuilder idBuilder) throws DeploymentException;
0229:
0230: /**
0231: * Some servlets will have multiple url patterns. However, webservice servlets
0232: * will only have one, which is what this method is intended for.
0233: *
0234: * @param webApp spec deployment descriptor
0235: * @param contextRoot context root for web app from application.xml or geronimo plan
0236: * @return map of servlet names to path mapped to them. Possibly inaccurate except for web services.
0237: */
0238: protected Map<String, String> buildServletNameToPathMap(
0239: WebAppType webApp, String contextRoot) {
0240: if (contextRoot == null) {
0241: contextRoot = "";
0242: } else if (!contextRoot.startsWith("/")) {
0243: contextRoot = "/" + contextRoot;
0244: }
0245: Map<String, String> map = new HashMap<String, String>();
0246: ServletMappingType[] servletMappings = webApp
0247: .getServletMappingArray();
0248: for (ServletMappingType servletMapping : servletMappings) {
0249: String servletName = servletMapping.getServletName()
0250: .getStringValue().trim();
0251: UrlPatternType[] urlPatterns = servletMapping
0252: .getUrlPatternArray();
0253:
0254: for (int i = 0; urlPatterns != null
0255: && (i < urlPatterns.length); i++) {
0256: map.put(servletName, contextRoot
0257: + urlPatterns[i].getStringValue().trim());
0258: }
0259: }
0260: return map;
0261: }
0262:
0263: protected String determineDefaultContextRoot(WebAppType webApp,
0264: boolean isStandAlone, JarFile moduleFile, String targetPath) {
0265:
0266: if (webApp != null && webApp.getId() != null) {
0267: return webApp.getId();
0268: }
0269:
0270: if (isStandAlone) {
0271: // default configId is based on the moduleFile name
0272: return "/"
0273: + trimPath(new File(moduleFile.getName()).getName());
0274: }
0275:
0276: // default configId is based on the module uri from the application.xml
0277: return trimPath(targetPath);
0278: }
0279:
0280: private String trimPath(String path) {
0281:
0282: if (path == null) {
0283: return null;
0284: }
0285:
0286: if (path.endsWith(".war")) {
0287: path = path.substring(0, path.length() - 4);
0288: }
0289: if (path.endsWith("/")) {
0290: path = path.substring(0, path.length() - 1);
0291: }
0292:
0293: return path;
0294: }
0295:
0296: public void installModule(JarFile earFile, EARContext earContext,
0297: Module module, Collection configurationStores,
0298: ConfigurationStore targetConfigurationStore,
0299: Collection repositories) throws DeploymentException {
0300: EARContext moduleContext;
0301: if (module.isStandAlone()) {
0302: moduleContext = earContext;
0303: } else {
0304: Environment environment = module.getEnvironment();
0305: Artifact earConfigId = earContext.getConfigID();
0306: Artifact configId = new Artifact(earConfigId.getGroupId(),
0307: earConfigId.getArtifactId() + "_"
0308: + module.getTargetPath(), earConfigId
0309: .getVersion(), "car");
0310: environment.setConfigId(configId);
0311: environment.addDependency(earConfigId, ImportType.ALL);
0312: File configurationDir = new File(earContext.getBaseDir(),
0313: module.getTargetPath());
0314: configurationDir.mkdirs();
0315:
0316: // construct the web app deployment context... this is the same class used by the ear context
0317: try {
0318: File inPlaceConfigurationDir = null;
0319: if (null != earContext.getInPlaceConfigurationDir()) {
0320: inPlaceConfigurationDir = new File(earContext
0321: .getInPlaceConfigurationDir(), module
0322: .getTargetPath());
0323: }
0324: moduleContext = new EARContext(configurationDir,
0325: inPlaceConfigurationDir, environment,
0326: ConfigurationModuleType.WAR, module
0327: .getModuleName(), earContext);
0328: } catch (DeploymentException e) {
0329: cleanupConfigurationDir(configurationDir);
0330: throw e;
0331: }
0332: }
0333: module.setEarContext(moduleContext);
0334: module.setRootEarContext(earContext);
0335:
0336: try {
0337: ClassPathList manifestcp = new ClassPathList();
0338: // add the warfile's content to the configuration
0339: JarFile warFile = module.getModuleFile();
0340: Enumeration<JarEntry> entries = warFile.entries();
0341: List<ZipEntry> libs = new ArrayList<ZipEntry>();
0342: while (entries.hasMoreElements()) {
0343: ZipEntry entry = entries.nextElement();
0344: URI targetPath = new URI(null, entry.getName(), null);
0345: if (entry.getName().equals("WEB-INF/web.xml")) {
0346: moduleContext.addFile(targetPath, module
0347: .getOriginalSpecDD());
0348: } else if (entry.getName().startsWith("WEB-INF/lib")
0349: && entry.getName().endsWith(".jar")) {
0350: // keep a collection of all libs in the war
0351: // libs must be installed after WEB-INF/classes which must be installed after this copy phase
0352: libs.add(entry);
0353: } else {
0354: moduleContext.addFile(targetPath, warFile, entry);
0355: }
0356: }
0357:
0358: // always add WEB-INF/classes to the classpath regardless of whether
0359: // any classes exist. This must be searched BEFORE the WEB-INF/lib jar files,
0360: // per the servlet specifications.
0361: moduleContext.getConfiguration().addToClassPath(
0362: "WEB-INF/classes/");
0363: manifestcp.add("WEB-INF/classes/");
0364:
0365: // install the libs
0366: for (ZipEntry entry : libs) {
0367: URI targetPath = new URI(null, entry.getName(), null);
0368: moduleContext.addInclude(targetPath, warFile, entry);
0369: manifestcp.add(entry.getName());
0370: }
0371:
0372: // add the manifest classpath entries declared in the war to the class loader
0373: // we have to explicitly add these since we are unpacking the web module
0374: // and the url class loader will not pick up a manifest from an unpacked dir
0375: moduleContext.addManifestClassPath(warFile,
0376: RELATIVE_MODULE_BASE_URI);
0377: moduleContext.getGeneralData().put(ClassPathList.class,
0378: manifestcp);
0379:
0380: } catch (IOException e) {
0381: throw new DeploymentException("Problem deploying war", e);
0382: } catch (URISyntaxException e) {
0383: throw new DeploymentException(
0384: "Could not construct URI for location of war entry",
0385: e);
0386: } finally {
0387: if (!module.isStandAlone()) {
0388: try {
0389: moduleContext.flush();
0390: } catch (IOException e) {
0391: throw new DeploymentException(
0392: "Problem closing war context", e);
0393: }
0394: }
0395: }
0396: for (ModuleBuilderExtension mbe : moduleBuilderExtensions) {
0397: mbe.installModule(earFile, earContext, module,
0398: configurationStores, targetConfigurationStore,
0399: repositories);
0400: }
0401: }
0402:
0403: protected void basicInitContext(EARContext earContext,
0404: Module module, XmlObject gerWebApp,
0405: boolean hasSecurityRealmName) throws DeploymentException {
0406: //complete manifest classpath
0407: EARContext moduleContext = module.getEarContext();
0408: ClassPathList manifestcp = (ClassPathList) moduleContext
0409: .getGeneralData().get(ClassPathList.class);
0410: ModuleList moduleLocations = (ModuleList) module
0411: .getRootEarContext().getGeneralData().get(
0412: ModuleList.class);
0413: URI baseUri = URI.create(module.getTargetPath());
0414: URI resolutionUri = invertURI(baseUri);
0415: earContext.getCompleteManifestClassPath(module.getModuleFile(),
0416: baseUri, resolutionUri, manifestcp, moduleLocations);
0417:
0418: WebAppType webApp = (WebAppType) module.getSpecDD();
0419: if ((webApp.getSecurityConstraintArray().length > 0 || webApp
0420: .getSecurityRoleArray().length > 0)
0421: && !hasSecurityRealmName) {
0422: throw new DeploymentException(
0423: "web.xml for web app "
0424: + module.getName()
0425: + " includes security elements but Geronimo deployment plan is not provided or does not contain <security-realm-name> element necessary to configure security accordingly.");
0426: }
0427: XmlObject[] securityElements = XmlBeansUtil
0428: .selectSubstitutionGroupElements(SECURITY_QNAME,
0429: gerWebApp);
0430: if (securityElements.length > 0 && !hasSecurityRealmName) {
0431: throw new DeploymentException(
0432: "You have supplied a security configuration for web app "
0433: + module.getName()
0434: + " but no security-realm-name to allow login");
0435: }
0436: getNamingBuilders().buildEnvironment(webApp,
0437: module.getVendorDD(), module.getEnvironment());
0438: //this is silly
0439: getNamingBuilders().initContext(webApp, gerWebApp, module);
0440:
0441: Map servletNameToPathMap = buildServletNameToPathMap(
0442: (WebAppType) module.getSpecDD(), ((WebModule) module)
0443: .getContextRoot());
0444:
0445: Map sharedContext = module.getSharedContext();
0446: for (Object aWebServiceBuilder : webServiceBuilder) {
0447: WebServiceBuilder serviceBuilder = (WebServiceBuilder) aWebServiceBuilder;
0448: serviceBuilder.findWebServices(module, false,
0449: servletNameToPathMap, module.getEnvironment(),
0450: sharedContext);
0451: }
0452: securityBuilders.build(gerWebApp, earContext, module
0453: .getEarContext());
0454: serviceBuilders.build(gerWebApp, earContext, module
0455: .getEarContext());
0456: }
0457:
0458: static URI invertURI(URI baseUri) {
0459: URI resolutionUri = URI.create(".");
0460: for (URI test = baseUri; !test.equals(RELATIVE_MODULE_BASE_URI); test = test
0461: .resolve(RELATIVE_MODULE_BASE_URI)) {
0462: resolutionUri = resolutionUri
0463: .resolve(RELATIVE_MODULE_BASE_URI);
0464: }
0465: return resolutionUri;
0466: }
0467:
0468: protected WebAppDocument convertToServletSchema(XmlObject xmlObject)
0469: throws XmlException {
0470:
0471: String schemaLocationURL = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd";
0472: String version = "2.5";
0473: XmlCursor cursor = xmlObject.newCursor();
0474: try {
0475: cursor.toStartDoc();
0476: cursor.toFirstChild();
0477: if ("http://java.sun.com/xml/ns/j2ee".equals(cursor
0478: .getName().getNamespaceURI())) {
0479: SchemaConversionUtils.convertSchemaVersion(cursor,
0480: SchemaConversionUtils.JAVAEE_NAMESPACE,
0481: schemaLocationURL, version);
0482: XmlObject result = xmlObject
0483: .changeType(WebAppDocument.type);
0484: XmlBeansUtil.validateDD(result);
0485: return (WebAppDocument) result;
0486: }
0487:
0488: if ("http://java.sun.com/xml/ns/javaee".equals(cursor
0489: .getName().getNamespaceURI())) {
0490: SchemaConversionUtils.convertSchemaVersion(cursor,
0491: SchemaConversionUtils.JAVAEE_NAMESPACE,
0492: schemaLocationURL, version);
0493: XmlObject result = xmlObject
0494: .changeType(WebAppDocument.type);
0495: XmlBeansUtil.validateDD(result);
0496: return (WebAppDocument) result;
0497: }
0498:
0499: //otherwise assume DTD
0500: XmlDocumentProperties xmlDocumentProperties = cursor
0501: .documentProperties();
0502: String publicId = xmlDocumentProperties
0503: .getDoctypePublicId();
0504: boolean is22 = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
0505: .equals(publicId);
0506: if ("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
0507: .equals(publicId)
0508: || is22) {
0509: XmlCursor moveable = xmlObject.newCursor();
0510: try {
0511: moveable.toStartDoc();
0512: moveable.toFirstChild();
0513:
0514: SchemaConversionUtils.convertToSchema(cursor,
0515: SchemaConversionUtils.JAVAEE_NAMESPACE,
0516: schemaLocationURL, version);
0517: cursor.toStartDoc();
0518: cursor.toChild(
0519: SchemaConversionUtils.JAVAEE_NAMESPACE,
0520: "web-app");
0521: cursor.toFirstChild();
0522: SchemaConversionUtils.convertToDescriptionGroup(
0523: SchemaConversionUtils.JAVAEE_NAMESPACE,
0524: cursor, moveable);
0525: SchemaConversionUtils
0526: .convertToJNDIEnvironmentRefsGroup(
0527: SchemaConversionUtils.JAVAEE_NAMESPACE,
0528: cursor, moveable);
0529: cursor.push();
0530: if (cursor.toNextSibling(TAGLIB)) {
0531: cursor.toPrevSibling();
0532: moveable.toCursor(cursor);
0533: cursor.beginElement("jsp-config",
0534: SchemaConversionUtils.JAVAEE_NAMESPACE);
0535: while (moveable.toNextSibling(TAGLIB)) {
0536: moveable.moveXml(cursor);
0537: }
0538: }
0539: cursor.pop();
0540: do {
0541: String name = cursor.getName().getLocalPart();
0542: if ("filter".equals(name)
0543: || "servlet".equals(name)
0544: || "context-param".equals(name)) {
0545: cursor.push();
0546: cursor.toFirstChild();
0547: SchemaConversionUtils
0548: .convertToDescriptionGroup(
0549: SchemaConversionUtils.JAVAEE_NAMESPACE,
0550: cursor, moveable);
0551: while (cursor
0552: .toNextSibling(
0553: SchemaConversionUtils.JAVAEE_NAMESPACE,
0554: "init-param")) {
0555: cursor.push();
0556: cursor.toFirstChild();
0557: SchemaConversionUtils
0558: .convertToDescriptionGroup(
0559: SchemaConversionUtils.JAVAEE_NAMESPACE,
0560: cursor, moveable);
0561: cursor.pop();
0562: }
0563: cursor.pop();
0564: cursor.push();
0565: if (cursor
0566: .toChild(
0567: SchemaConversionUtils.JAVAEE_NAMESPACE,
0568: "jsp-file")) {
0569: String jspFile = cursor.getTextValue();
0570: if (!jspFile.startsWith("/")) {
0571: if (is22) {
0572: cursor.setTextValue("/"
0573: + jspFile);
0574: } else {
0575: throw new XmlException(
0576: "jsp-file does not start with / and this is not a 2.2 web app: "
0577: + jspFile);
0578: }
0579: }
0580: }
0581: cursor.pop();
0582: }
0583: } while (cursor.toNextSibling());
0584: } finally {
0585: moveable.dispose();
0586: }
0587: }
0588: } finally {
0589: cursor.dispose();
0590: }
0591: XmlObject result = xmlObject.changeType(WebAppDocument.type);
0592: if (result != null) {
0593: XmlBeansUtil.validateDD(result);
0594: return (WebAppDocument) result;
0595: }
0596: XmlBeansUtil.validateDD(xmlObject);
0597: return (WebAppDocument) xmlObject;
0598: }
0599:
0600: protected void addUnmappedJSPPermissions(Set<String> securityRoles,
0601: Map<String, PermissionCollection> rolePermissions) {
0602: for (String roleName : securityRoles) {
0603: addPermissionToRole(roleName, new WebRoleRefPermission("",
0604: roleName), rolePermissions);
0605: }
0606: }
0607:
0608: protected ComponentPermissions buildSpecSecurityConfig(
0609: WebAppType webApp, Set<String> securityRoles,
0610: Map<String, PermissionCollection> rolePermissions) {
0611: Map<String, URLPattern> uncheckedPatterns = new HashMap<String, URLPattern>();
0612: Map<UncheckedItem, HTTPMethods> uncheckedResourcePatterns = new HashMap<UncheckedItem, HTTPMethods>();
0613: Map<UncheckedItem, HTTPMethods> uncheckedUserPatterns = new HashMap<UncheckedItem, HTTPMethods>();
0614: Map<String, URLPattern> excludedPatterns = new HashMap<String, URLPattern>();
0615: Map<String, URLPattern> rolesPatterns = new HashMap<String, URLPattern>();
0616: Set<URLPattern> allSet = new HashSet<URLPattern>(); // == allMap.values()
0617: Map<String, URLPattern> allMap = new HashMap<String, URLPattern>(); //uncheckedPatterns union excludedPatterns union rolesPatterns.
0618:
0619: SecurityConstraintType[] securityConstraintArray = webApp
0620: .getSecurityConstraintArray();
0621: for (SecurityConstraintType securityConstraintType : securityConstraintArray) {
0622: Map<String, URLPattern> currentPatterns;
0623: if (securityConstraintType.isSetAuthConstraint()) {
0624: if (securityConstraintType.getAuthConstraint()
0625: .getRoleNameArray().length == 0) {
0626: currentPatterns = excludedPatterns;
0627: } else {
0628: currentPatterns = rolesPatterns;
0629: }
0630: } else {
0631: currentPatterns = uncheckedPatterns;
0632: }
0633:
0634: String transport = "";
0635: if (securityConstraintType.isSetUserDataConstraint()) {
0636: transport = securityConstraintType
0637: .getUserDataConstraint()
0638: .getTransportGuarantee().getStringValue()
0639: .trim().toUpperCase();
0640: }
0641:
0642: WebResourceCollectionType[] webResourceCollectionTypeArray = securityConstraintType
0643: .getWebResourceCollectionArray();
0644: for (WebResourceCollectionType webResourceCollectionType : webResourceCollectionTypeArray) {
0645: UrlPatternType[] urlPatternTypeArray = webResourceCollectionType
0646: .getUrlPatternArray();
0647: for (UrlPatternType urlPatternType : urlPatternTypeArray) {
0648: String url = urlPatternType.getStringValue().trim();
0649: URLPattern pattern = currentPatterns.get(url);
0650: if (pattern == null) {
0651: pattern = new URLPattern(url);
0652: currentPatterns.put(url, pattern);
0653: }
0654:
0655: URLPattern allPattern = allMap.get(url);
0656: if (allPattern == null) {
0657: allPattern = new URLPattern(url);
0658: allSet.add(allPattern);
0659: allMap.put(url, allPattern);
0660: }
0661:
0662: String[] httpMethodTypeArray = webResourceCollectionType
0663: .getHttpMethodArray();
0664: if (httpMethodTypeArray.length == 0) {
0665: pattern.addMethod("");
0666: allPattern.addMethod("");
0667: } else {
0668: for (String aHttpMethodTypeArray : httpMethodTypeArray) {
0669: String method = (aHttpMethodTypeArray == null ? null
0670: : aHttpMethodTypeArray.trim());
0671: if (method != null) {
0672: pattern.addMethod(method);
0673: allPattern.addMethod(method);
0674: }
0675: }
0676: }
0677: if (currentPatterns == rolesPatterns) {
0678: RoleNameType[] roleNameTypeArray = securityConstraintType
0679: .getAuthConstraint().getRoleNameArray();
0680: for (RoleNameType roleNameType : roleNameTypeArray) {
0681: String role = roleNameType.getStringValue()
0682: .trim();
0683: if (role.equals("*")) {
0684: pattern.addAllRoles(securityRoles);
0685: } else {
0686: pattern.addRole(role);
0687: }
0688: }
0689: }
0690:
0691: pattern.setTransport(transport);
0692: }
0693: }
0694: }
0695:
0696: PermissionCollection excludedPermissions = new Permissions();
0697: PermissionCollection uncheckedPermissions = new Permissions();
0698:
0699: for (URLPattern pattern : excludedPatterns.values()) {
0700: String name = pattern.getQualifiedPattern(allSet);
0701: String actions = pattern.getMethods();
0702:
0703: excludedPermissions.add(new WebResourcePermission(name,
0704: actions));
0705: excludedPermissions.add(new WebUserDataPermission(name,
0706: actions));
0707: }
0708:
0709: for (URLPattern pattern : rolesPatterns.values()) {
0710: String name = pattern.getQualifiedPattern(allSet);
0711: String actions = pattern.getMethods();
0712: WebResourcePermission permission = new WebResourcePermission(
0713: name, actions);
0714:
0715: for (String roleName : pattern.getRoles()) {
0716: addPermissionToRole(roleName, permission,
0717: rolePermissions);
0718: }
0719: HTTPMethods methods = pattern.getHTTPMethods();
0720: int transportType = pattern.getTransport();
0721:
0722: addOrUpdatePattern(uncheckedUserPatterns, name, methods,
0723: transportType);
0724: }
0725:
0726: for (URLPattern pattern : uncheckedPatterns.values()) {
0727: String name = pattern.getQualifiedPattern(allSet);
0728: HTTPMethods methods = pattern.getHTTPMethods();
0729:
0730: addOrUpdatePattern(uncheckedResourcePatterns, name,
0731: methods, URLPattern.NA);
0732:
0733: int transportType = pattern.getTransport();
0734: addOrUpdatePattern(uncheckedUserPatterns, name, methods,
0735: transportType);
0736: }
0737:
0738: /**
0739: * A <code>WebResourcePermission</code> and a <code>WebUserDataPermission</code> must be instantiated for
0740: * each <tt>url-pattern</tt> in the deployment descriptor and the default pattern "/", that is not combined
0741: * by the <tt>web-resource-collection</tt> elements of the deployment descriptor with ever HTTP method
0742: * value. The permission objects must be contructed using the qualified pattern as their name and with
0743: * actions defined by the subset of the HTTP methods that do not occur in combination with the pattern.
0744: * The resulting permissions that must be added to the unchecked policy statements by calling the
0745: * <code>addToUncheckedPolcy</code> method on the <code>PolicyConfiguration</code> object.
0746: */
0747: for (URLPattern pattern : allSet) {
0748: String name = pattern.getQualifiedPattern(allSet);
0749: HTTPMethods methods = pattern.getComplementedHTTPMethods();
0750:
0751: if (methods.isNone()) {
0752: continue;
0753: }
0754:
0755: addOrUpdatePattern(uncheckedResourcePatterns, name,
0756: methods, URLPattern.NA);
0757: addOrUpdatePattern(uncheckedUserPatterns, name, methods,
0758: URLPattern.NA);
0759: }
0760:
0761: URLPattern pattern = new URLPattern("/");
0762: if (!allSet.contains(pattern)) {
0763: String name = pattern.getQualifiedPattern(allSet);
0764: HTTPMethods methods = pattern.getComplementedHTTPMethods();
0765:
0766: addOrUpdatePattern(uncheckedResourcePatterns, name,
0767: methods, URLPattern.NA);
0768: addOrUpdatePattern(uncheckedUserPatterns, name, methods,
0769: URLPattern.NA);
0770: }
0771:
0772: //Create the uncheckedPermissions for WebResourcePermissions
0773: for (UncheckedItem item : uncheckedResourcePatterns.keySet()) {
0774: HTTPMethods methods = uncheckedResourcePatterns.get(item);
0775: String actions = URLPattern.getMethodsWithTransport(
0776: methods, item.getTransportType());
0777:
0778: uncheckedPermissions.add(new WebResourcePermission(item
0779: .getName(), actions));
0780: }
0781: //Create the uncheckedPermissions for WebUserDataPermissions
0782: for (UncheckedItem item : uncheckedUserPatterns.keySet()) {
0783: HTTPMethods methods = uncheckedUserPatterns.get(item);
0784: String actions = URLPattern.getMethodsWithTransport(
0785: methods, item.getTransportType());
0786:
0787: uncheckedPermissions.add(new WebUserDataPermission(item
0788: .getName(), actions));
0789: }
0790:
0791: return new ComponentPermissions(excludedPermissions,
0792: uncheckedPermissions, rolePermissions);
0793:
0794: }
0795:
0796: protected void addPermissionToRole(String roleName,
0797: Permission permission,
0798: Map<String, PermissionCollection> rolePermissions) {
0799: PermissionCollection permissionsForRole = rolePermissions
0800: .get(roleName);
0801: if (permissionsForRole == null) {
0802: permissionsForRole = new Permissions();
0803: rolePermissions.put(roleName, permissionsForRole);
0804: }
0805: permissionsForRole.add(permission);
0806: }
0807:
0808: private void addOrUpdatePattern(
0809: Map<UncheckedItem, HTTPMethods> patternMap, String name,
0810: HTTPMethods actions, int transportType) {
0811: UncheckedItem item = new UncheckedItem(name, transportType);
0812: HTTPMethods existingActions = patternMap.get(item);
0813: if (existingActions != null) {
0814: patternMap.put(item, existingActions.add(actions));
0815: return;
0816: }
0817:
0818: patternMap.put(item, new HTTPMethods(actions, false));
0819: }
0820:
0821: protected static Set<String> collectRoleNames(WebAppType webApp) {
0822: Set<String> roleNames = new HashSet<String>();
0823:
0824: SecurityRoleType[] securityRoles = webApp
0825: .getSecurityRoleArray();
0826: for (SecurityRoleType securityRole : securityRoles) {
0827: roleNames.add(securityRole.getRoleName().getStringValue()
0828: .trim());
0829: }
0830:
0831: return roleNames;
0832: }
0833:
0834: protected static void check(WebAppType webApp)
0835: throws DeploymentException {
0836: checkURLPattern(webApp);
0837: checkMultiplicities(webApp);
0838: }
0839:
0840: private static void checkURLPattern(WebAppType webApp)
0841: throws DeploymentException {
0842:
0843: FilterMappingType[] filterMappings = webApp
0844: .getFilterMappingArray();
0845: for (FilterMappingType filterMapping : filterMappings) {
0846: UrlPatternType[] urlPatterns = filterMapping
0847: .getUrlPatternArray();
0848: for (int j = 0; (urlPatterns != null)
0849: && (j < urlPatterns.length); j++) {
0850: checkString(urlPatterns[j].getStringValue().trim());
0851: }
0852: }
0853:
0854: ServletMappingType[] servletMappings = webApp
0855: .getServletMappingArray();
0856: for (ServletMappingType servletMapping : servletMappings) {
0857: UrlPatternType[] urlPatterns = servletMapping
0858: .getUrlPatternArray();
0859: for (int j = 0; (urlPatterns != null)
0860: && (j < urlPatterns.length); j++) {
0861: checkString(urlPatterns[j].getStringValue().trim());
0862: }
0863: }
0864:
0865: SecurityConstraintType[] constraints = webApp
0866: .getSecurityConstraintArray();
0867: for (SecurityConstraintType constraint : constraints) {
0868: WebResourceCollectionType[] collections = constraint
0869: .getWebResourceCollectionArray();
0870: for (WebResourceCollectionType collection : collections) {
0871: UrlPatternType[] patterns = collection
0872: .getUrlPatternArray();
0873: for (UrlPatternType pattern : patterns) {
0874: checkString(pattern.getStringValue().trim());
0875: }
0876: }
0877: }
0878: }
0879:
0880: protected static void checkString(String pattern)
0881: throws DeploymentException {
0882: //j2ee_1_4.xsd explicitly requires preserving all whitespace. Do not trim.
0883: if (pattern.indexOf(0x0D) >= 0)
0884: throw new DeploymentException(
0885: "<url-pattern> must not contain CR(#xD)");
0886: if (pattern.indexOf(0x0A) >= 0)
0887: throw new DeploymentException(
0888: "<url-pattern> must not contain LF(#xA)");
0889: }
0890:
0891: private static void checkMultiplicities(WebAppType webApp)
0892: throws DeploymentException {
0893: if (webApp.getSessionConfigArray().length > 1)
0894: throw new DeploymentException(
0895: "Multiple <session-config> elements found");
0896: if (webApp.getJspConfigArray().length > 1)
0897: throw new DeploymentException(
0898: "Multiple <jsp-config> elements found");
0899: if (webApp.getLoginConfigArray().length > 1)
0900: throw new DeploymentException(
0901: "Multiple <login-config> elements found");
0902: }
0903:
0904: private boolean cleanupConfigurationDir(File configurationDir) {
0905: LinkedList<String> cannotBeDeletedList = new LinkedList<String>();
0906:
0907: if (!DeploymentUtil.recursiveDelete(configurationDir,
0908: cannotBeDeletedList)) {
0909: // Output a message to help user track down file problem
0910: log
0911: .warn("Unable to delete "
0912: + cannotBeDeletedList.size()
0913: + " files while recursively deleting directory "
0914: + configurationDir.getAbsolutePath()
0915: + LINE_SEP
0916: + "The first file that could not be deleted was:"
0917: + LINE_SEP
0918: + " "
0919: + (!cannotBeDeletedList.isEmpty() ? cannotBeDeletedList
0920: .getFirst()
0921: : ""));
0922: return false;
0923: }
0924: return true;
0925: }
0926:
0927: protected void processRoleRefPermissions(ServletType servletType,
0928: Set<String> securityRoles,
0929: Map<String, PermissionCollection> rolePermissions) {
0930: String servletName = servletType.getServletName()
0931: .getStringValue().trim();
0932: //WebRoleRefPermissions
0933: SecurityRoleRefType[] securityRoleRefTypeArray = servletType
0934: .getSecurityRoleRefArray();
0935: Set<String> unmappedRoles = new HashSet<String>(securityRoles);
0936: for (SecurityRoleRefType securityRoleRefType : securityRoleRefTypeArray) {
0937: String roleName = securityRoleRefType.getRoleName()
0938: .getStringValue().trim();
0939: String roleLink = securityRoleRefType.getRoleLink()
0940: .getStringValue().trim();
0941: //jacc 3.1.3.2
0942: /* The name of the WebRoleRefPermission must be the servlet-name in whose
0943: * context the security-role-ref is defined. The actions of the WebRoleRefPermission
0944: * must be the value of the role-name (that is the reference), appearing in the security-role-ref.
0945: * The deployment tools must call the addToRole method on the PolicyConfiguration object to add the
0946: * WebRoleRefPermission object resulting from the translation to the role
0947: * identified in the role-link appearing in the security-role-ref.
0948: */
0949: addPermissionToRole(roleLink, new WebRoleRefPermission(
0950: servletName, roleName), rolePermissions);
0951: unmappedRoles.remove(roleName);
0952: }
0953: for (String roleName : unmappedRoles) {
0954: addPermissionToRole(roleName, new WebRoleRefPermission(
0955: servletName, roleName), rolePermissions);
0956: }
0957: }
0958:
0959: protected ClassFinder createWebAppClassFinder(WebAppType webApp,
0960: WebModule webModule) throws DeploymentException {
0961: // Get the classloader from the module's EARContext
0962: ClassLoader classLoader = webModule.getEarContext()
0963: .getClassLoader();
0964: return createWebAppClassFinder(webApp, classLoader);
0965: }
0966:
0967: public static ClassFinder createWebAppClassFinder(
0968: WebAppType webApp, ClassLoader classLoader)
0969: throws DeploymentException {
0970: //------------------------------------------------------------------------------------
0971: // Find the list of classes from the web.xml we want to search for annotations in
0972: //------------------------------------------------------------------------------------
0973: List<Class> classes = new ArrayList<Class>();
0974:
0975: // Get all the servlets from the deployment descriptor
0976: ServletType[] servlets = webApp.getServletArray();
0977: for (ServletType servlet : servlets) {
0978: FullyQualifiedClassType cls = servlet.getServletClass();
0979: if (cls != null) { // Don't try this for JSPs
0980: Class<?> clas;
0981: try {
0982: clas = classLoader.loadClass(cls.getStringValue());
0983: } catch (ClassNotFoundException e) {
0984: throw new DeploymentException(
0985: "AbstractWebModuleBuilder: Could not load servlet class: "
0986: + cls.getStringValue(), e);
0987: }
0988: addClass(classes, clas);
0989: }
0990: }
0991:
0992: // Get all the listeners from the deployment descriptor
0993: ListenerType[] listeners = webApp.getListenerArray();
0994: for (ListenerType listener : listeners) {
0995: FullyQualifiedClassType cls = listener.getListenerClass();
0996: Class<?> clas;
0997: try {
0998: clas = classLoader.loadClass(cls.getStringValue());
0999: } catch (ClassNotFoundException e) {
1000: throw new DeploymentException(
1001: "AbstractWebModuleBuilder: Could not load listener class: "
1002: + cls.getStringValue(), e);
1003: }
1004: addClass(classes, clas);
1005: }
1006:
1007: // Get all the filters from the deployment descriptor
1008: FilterType[] filters = webApp.getFilterArray();
1009: for (FilterType filter : filters) {
1010: FullyQualifiedClassType cls = filter.getFilterClass();
1011: Class<?> clas;
1012: try {
1013: clas = classLoader.loadClass(cls.getStringValue());
1014: } catch (ClassNotFoundException e) {
1015: throw new DeploymentException(
1016: "AbstractWebModuleBuilder: Could not load filter class: "
1017: + cls.getStringValue(), e);
1018: }
1019: addClass(classes, clas);
1020: }
1021:
1022: // see https://issues.apache.org/jira/browse/GERONIMO-3421 .
1023: // if the user has botched her classloader config (perhaps by
1024: // not including a jar that her app needs) then ClassFinder
1025: // will throw NoClassDefFoundError. we want to indicate that
1026: // it's the user's error and provide a little context to help
1027: // her fix it.
1028: try {
1029: return new ClassFinder(classes);
1030: } catch (NoClassDefFoundError e) {
1031: throw new DeploymentException("Classloader for "
1032: + webApp.getId() + "can't find " + e.getMessage(),
1033: e);
1034: }
1035: }
1036:
1037: private static void addClass(List<Class> classes, Class<?> clas) {
1038: while (clas != Object.class) {
1039: classes.add(clas);
1040: clas = clas.getSuperclass();
1041: }
1042: }
1043:
1044: protected void configureBasicWebModuleAttributes(WebAppType webApp,
1045: XmlObject vendorPlan, EARContext moduleContext,
1046: EARContext earContext, WebModule webModule,
1047: GBeanData webModuleData) throws DeploymentException {
1048: Map<NamingBuilder.Key, Object> buildingContext = new HashMap<NamingBuilder.Key, Object>();
1049: buildingContext.put(NamingBuilder.GBEAN_NAME_KEY, moduleContext
1050: .getModuleName());
1051:
1052: if (!webApp.getMetadataComplete()) {
1053: // Create a classfinder and populate it for the naming builder(s). The absence of a
1054: // classFinder in the module will convey whether metadata-complete is set (or not)
1055: webModule.setClassFinder(createWebAppClassFinder(webApp,
1056: webModule));
1057: SecurityAnnotationHelper.processAnnotations(webApp,
1058: webModule.getClassFinder());
1059: }
1060: //N.B. we use the ear context which has all the gbeans we could possibly be looking up from this ear.
1061: //nope, persistence units can be in the war.
1062: //This means that you cannot use the default environment of the web builder to add configs that will be searched.
1063: getNamingBuilders().buildNaming(webApp, vendorPlan, webModule,
1064: buildingContext);
1065:
1066: Map compContext = NamingBuilder.JNDI_KEY.get(buildingContext);
1067: Holder holder = NamingBuilder.INJECTION_KEY
1068: .get(buildingContext);
1069:
1070: webModule.getSharedContext().put(WebModule.WEB_APP_DATA,
1071: webModuleData);
1072: webModule.getSharedContext().put(NamingBuilder.JNDI_KEY,
1073: compContext);
1074: webModule.getSharedContext().put(NamingBuilder.INJECTION_KEY,
1075: holder);
1076: if (moduleContext.getServerName() != null) {
1077: webModuleData.setReferencePattern("J2EEServer",
1078: moduleContext.getServerName());
1079: }
1080: if (!webModule.isStandAlone()) {
1081: webModuleData.setReferencePattern("J2EEApplication",
1082: earContext.getModuleName());
1083: }
1084:
1085: webModuleData.setAttribute("holder", holder);
1086:
1087: //Add dependencies on managed connection factories and ejbs in this app
1088: //This is overkill, but allows for people not using java:comp context (even though we don't support it)
1089: //and sidesteps the problem of circular references between ejbs.
1090: if (earContext != moduleContext) {
1091: addGBeanDependencies(earContext, webModuleData);
1092: }
1093:
1094: webModuleData.setAttribute("componentContext", compContext);
1095: webModuleData.setReferencePattern("TransactionManager",
1096: moduleContext.getTransactionManagerName());
1097: webModuleData.setReferencePattern(
1098: "TrackedConnectionAssociator", moduleContext
1099: .getConnectionTrackerName());
1100: }
1101:
1102: class UncheckedItem {
1103: final static int NA = 0x00;
1104: final static int INTEGRAL = 0x01;
1105: final static int CONFIDENTIAL = 0x02;
1106:
1107: private int transportType = NA;
1108: private String name;
1109:
1110: public UncheckedItem(String name, int transportType) {
1111: setName(name);
1112: setTransportType(transportType);
1113: }
1114:
1115: public boolean equals(Object o) {
1116: UncheckedItem item = (UncheckedItem) o;
1117: return item.transportType == transportType
1118: && item.name.equals(this .name);
1119: }
1120:
1121: public int hashCode() {
1122: return name.hashCode() + transportType;
1123: }
1124:
1125: public String getName() {
1126: return name;
1127: }
1128:
1129: public void setName(String name) {
1130: this .name = name;
1131: }
1132:
1133: public int getTransportType() {
1134: return transportType;
1135: }
1136:
1137: public void setTransportType(int transportType) {
1138: this.transportType = transportType;
1139: }
1140: }
1141: }
|