0001: /**
0002: *
0003: * Licensed to the Apache Software Foundation (ASF) under one or more
0004: * contributor license agreements. See the NOTICE file distributed with
0005: * this work for additional information regarding copyright ownership.
0006: * The ASF licenses this file to You under the Apache License, Version 2.0
0007: * (the "License"); you may not use this file except in compliance with
0008: * the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing, software
0013: * distributed under the License is distributed on an "AS IS" BASIS,
0014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015: * See the License for the specific language governing permissions and
0016: * limitations under the License.
0017: */package org.apache.openejb.config;
0018:
0019: import java.io.File;
0020: import java.io.IOException;
0021: import java.io.InputStream;
0022: import java.net.MalformedURLException;
0023: import java.net.URL;
0024: import java.net.URLDecoder;
0025: import java.util.ArrayList;
0026: import java.util.Arrays;
0027: import java.util.Collections;
0028: import java.util.HashMap;
0029: import java.util.HashSet;
0030: import java.util.Iterator;
0031: import java.util.LinkedList;
0032: import java.util.List;
0033: import java.util.Map;
0034: import java.util.Set;
0035: import java.util.TreeMap;
0036: import java.util.jar.Attributes;
0037: import java.util.jar.JarEntry;
0038: import java.util.jar.JarFile;
0039: import java.util.jar.Manifest;
0040: import javax.ejb.MessageDriven;
0041: import javax.ejb.Stateful;
0042: import javax.ejb.Stateless;
0043: import javax.xml.bind.JAXBException;
0044:
0045: import org.apache.openejb.ClassLoaderUtil;
0046: import org.apache.openejb.OpenEJB;
0047: import org.apache.openejb.OpenEJBException;
0048: import org.apache.openejb.jee.Application;
0049: import org.apache.openejb.jee.ApplicationClient;
0050: import org.apache.openejb.jee.Connector;
0051: import org.apache.openejb.jee.EjbJar;
0052: import org.apache.openejb.jee.JavaWsdlMapping;
0053: import org.apache.openejb.jee.JaxbJavaee;
0054: import org.apache.openejb.jee.JspConfig;
0055: import org.apache.openejb.jee.Module;
0056: import org.apache.openejb.jee.Taglib;
0057: import org.apache.openejb.jee.TldTaglib;
0058: import org.apache.openejb.jee.WebApp;
0059: import org.apache.openejb.jee.WebserviceDescription;
0060: import org.apache.openejb.jee.Webservices;
0061: import org.apache.openejb.util.JarExtractor;
0062: import org.apache.openejb.util.LogCategory;
0063: import org.apache.openejb.util.Logger;
0064: import org.apache.openejb.util.URLs;
0065: import org.apache.openejb.util.UrlCache;
0066: import static org.apache.openejb.util.URLs.toFile;
0067: import org.apache.xbean.finder.ClassFinder;
0068: import org.apache.xbean.finder.ResourceFinder;
0069: import org.apache.xbean.finder.UrlSet;
0070: import org.xml.sax.SAXException;
0071:
0072: /**
0073: * @version $Revision: 637630 $ $Date: 2008-03-16 12:33:07 -0700 $
0074: */
0075: public class DeploymentLoader {
0076: public static final Logger logger = Logger.getInstance(
0077: LogCategory.OPENEJB_STARTUP_CONFIG,
0078: "org.apache.openejb.util.resources");
0079:
0080: public AppModule load(File jarFile) throws OpenEJBException {
0081: // verify we have a valid file
0082: String jarPath;
0083: try {
0084: jarPath = jarFile.getCanonicalPath();
0085: } catch (IOException e) {
0086: throw new OpenEJBException("Invalid application file path "
0087: + jarFile);
0088: }
0089:
0090: URL baseUrl = getFileUrl(jarFile);
0091:
0092: // create a class loader to use for detection of module type
0093: // do not use this class loader for any other purposes... it is
0094: // non-temp class loader and usage will mess up JPA
0095: ClassLoader doNotUseClassLoader = ClassLoaderUtil
0096: .createClassLoader(jarPath, new URL[] { baseUrl },
0097: OpenEJB.class.getClassLoader());
0098:
0099: try {
0100: // determine the module type
0101: Class moduleClass;
0102: File tmpFile = null;
0103: try {
0104: // TODO: ClassFinder is leaking file locks, so copy the jar to a temp dir
0105: // when we have a possible ejb-jar file (only ejb-jars result in a ClassFinder being used)
0106: URL tempURL = baseUrl;
0107: if (jarFile.isFile() && UrlCache.cacheDir != null
0108: && !jarFile.getName().endsWith(".ear")
0109: && !jarFile.getName().endsWith(".war")
0110: && !jarFile.getName().endsWith(".rar")) {
0111: try {
0112: tmpFile = File.createTempFile("AppModule-", "",
0113: UrlCache.cacheDir);
0114: JarExtractor
0115: .copy(URLs.toFile(baseUrl), tmpFile);
0116: tempURL = tmpFile.toURL();
0117: } catch (Exception e) {
0118: throw new OpenEJBException(e);
0119: }
0120: }
0121:
0122: moduleClass = discoverModuleType(
0123: tempURL,
0124: ClassLoaderUtil
0125: .createTempClassLoader(doNotUseClassLoader),
0126: true);
0127: } catch (Exception e) {
0128: throw new UnknownModuleTypeException(
0129: "Unable to determine module type for jar: "
0130: + baseUrl.toExternalForm(), e);
0131: } finally {
0132: // most likely won't work but give it a try
0133: if (tmpFile != null)
0134: tmpFile.delete();
0135: }
0136:
0137: if (AppModule.class.equals(moduleClass)) {
0138:
0139: return createAppModule(jarFile, jarPath);
0140:
0141: } else if (EjbModule.class.equals(moduleClass)) {
0142: ClassLoader classLoader = ClassLoaderUtil
0143: .createTempClassLoader(jarPath,
0144: new URL[] { baseUrl }, OpenEJB.class
0145: .getClassLoader());
0146: EjbModule ejbModule = createEjbModule(baseUrl, jarPath,
0147: classLoader, null);
0148:
0149: // wrap the EJB Module with an Application Module
0150: AppModule appModule = new AppModule(ejbModule
0151: .getClassLoader(), ejbModule.getJarLocation());
0152: appModule.getEjbModules().add(ejbModule);
0153:
0154: // Persistence Units
0155: addPersistenceUnits(appModule, baseUrl);
0156:
0157: return appModule;
0158: } else if (ConnectorModule.class.equals(moduleClass)) {
0159: String jarLocation = URLs.toFilePath(baseUrl);
0160: ConnectorModule connectorModule = createConnectorModule(
0161: jarLocation, jarLocation, OpenEJB.class
0162: .getClassLoader(), null);
0163:
0164: // Wrap the resource module with an Application Module
0165: AppModule appModule = new AppModule(connectorModule
0166: .getClassLoader(), jarLocation);
0167: appModule.getResourceModules().add(connectorModule);
0168:
0169: return appModule;
0170: } else if (WebModule.class.equals(moduleClass)) {
0171: String moduleId = toFile(baseUrl).getName();
0172: String warPath = URLs.toFilePath(baseUrl);
0173:
0174: AppModule appModule = new AppModule(OpenEJB.class
0175: .getClassLoader(), warPath);
0176: addWebModule(appModule, warPath, OpenEJB.class
0177: .getClassLoader(), null, moduleId);
0178: return appModule;
0179: } else {
0180: throw new UnsupportedModuleTypeException(
0181: "Unsupported module type: "
0182: + moduleClass.getSimpleName());
0183: }
0184: } finally {
0185: // if the application was unpacked appId used to create this class loader will be wrong
0186: // We can safely destroy this class loader in either case, as it was not use by any modules
0187: ClassLoaderUtil.destroyClassLoader(doNotUseClassLoader);
0188: }
0189: }
0190:
0191: protected static AppModule createAppModule(File jarFile,
0192: String jarPath) throws OpenEJBException {
0193: File appDir = unpack(jarFile);
0194: try {
0195: appDir = appDir.getCanonicalFile();
0196: } catch (IOException e) {
0197: throw new OpenEJBException("Invalid application directory "
0198: + appDir.getAbsolutePath());
0199: }
0200:
0201: URL appUrl = getFileUrl(appDir);
0202:
0203: String appId = appDir.getAbsolutePath();
0204: ClassLoader tmpClassLoader = ClassLoaderUtil
0205: .createTempClassLoader(appId, new URL[] { appUrl },
0206: OpenEJB.class.getClassLoader());
0207:
0208: ResourceFinder finder = new ResourceFinder("", tmpClassLoader,
0209: appUrl);
0210:
0211: Map<String, URL> appDescriptors;
0212: try {
0213: appDescriptors = finder.getResourcesMap("META-INF");
0214: } catch (IOException e) {
0215: throw new OpenEJBException(
0216: "Unable to determine descriptors in jar: "
0217: + appUrl.toExternalForm(), e);
0218: }
0219:
0220: try {
0221:
0222: //
0223: // Find all the modules using either the application xml or by searching for all .jar, .war and .rar files.
0224: //
0225:
0226: Map<String, URL> ejbModules = new HashMap<String, URL>();
0227: Map<String, URL> clientModules = new HashMap<String, URL>();
0228: Map<String, URL> resouceModules = new HashMap<String, URL>();
0229: Map<String, URL> webModules = new HashMap<String, URL>();
0230: Map<String, String> webContextRoots = new HashMap<String, String>();
0231:
0232: URL applicationXmlUrl = appDescriptors
0233: .get("application.xml");
0234:
0235: Application application;
0236: if (applicationXmlUrl != null) {
0237: application = unmarshal(Application.class,
0238: "application.xml", applicationXmlUrl);
0239: for (Module module : application.getModule()) {
0240: try {
0241: if (module.getEjb() != null) {
0242: URL url = finder.find(module.getEjb()
0243: .trim());
0244: ejbModules.put(module.getEjb(), url);
0245: } else if (module.getJava() != null) {
0246: URL url = finder.find(module.getJava()
0247: .trim());
0248: clientModules.put(module.getConnector(),
0249: url);
0250: } else if (module.getConnector() != null) {
0251: URL url = finder.find(module.getConnector()
0252: .trim());
0253: resouceModules.put(module.getConnector(),
0254: url);
0255: } else if (module.getWeb() != null) {
0256: URL url = finder.find(module.getWeb()
0257: .getWebUri().trim());
0258: webModules.put(module.getWeb().getWebUri(),
0259: url);
0260: webContextRoots.put(module.getWeb()
0261: .getWebUri(), module.getWeb()
0262: .getContextRoot());
0263: }
0264: } catch (IOException e) {
0265: throw new OpenEJBException(
0266: "Invalid path to module "
0267: + e.getMessage(), e);
0268: }
0269: }
0270: } else {
0271: application = new Application();
0272: HashMap<String, URL> files = new HashMap<String, URL>();
0273: scanDir(appDir, files, "");
0274: files.remove("META-INF/MANIFEST.MF");
0275: for (Map.Entry<String, URL> entry : files.entrySet()) {
0276: if (entry.getKey().startsWith("lib/"))
0277: continue;
0278: if (!entry.getKey().matches(
0279: ".*\\.(jar|war|rar|ear)"))
0280: continue;
0281:
0282: try {
0283: ClassLoader moduleClassLoader = ClassLoaderUtil
0284: .createTempClassLoader(appId,
0285: new URL[] { entry.getValue() },
0286: tmpClassLoader);
0287:
0288: Class moduleType = discoverModuleType(entry
0289: .getValue(), moduleClassLoader, true);
0290: if (EjbModule.class.equals(moduleType)) {
0291: ejbModules.put(entry.getKey(), entry
0292: .getValue());
0293: } else if (ClientModule.class
0294: .equals(moduleType)) {
0295: clientModules.put(entry.getKey(), entry
0296: .getValue());
0297: } else if (ConnectorModule.class
0298: .equals(moduleType)) {
0299: resouceModules.put(entry.getKey(), entry
0300: .getValue());
0301: } else if (WebModule.class.equals(moduleType)) {
0302: webModules.put(entry.getKey(), entry
0303: .getValue());
0304: }
0305: } catch (UnsupportedOperationException e) {
0306: // Ignore it as per the javaee spec EE.8.4.2 section 1.d.iiilogger.info("Ignoring unknown module type: "+entry.getKey());
0307: } catch (Exception e) {
0308: throw new OpenEJBException(
0309: "Unable to determine the module type of "
0310: + entry.getKey()
0311: + ": Exception: "
0312: + e.getMessage(), e);
0313: }
0314: }
0315: }
0316:
0317: //
0318: // Create a class loader for the application
0319: //
0320:
0321: // lib/*
0322: if (application.getLibraryDirectory() == null) {
0323: application.setLibraryDirectory("lib/");
0324: } else {
0325: String dir = application.getLibraryDirectory();
0326: if (!dir.endsWith("/"))
0327: application.setLibraryDirectory(dir + "/");
0328: }
0329: List<URL> extraLibs = new ArrayList<URL>();
0330: try {
0331: Map<String, URL> libs = finder
0332: .getResourcesMap(application
0333: .getLibraryDirectory());
0334: extraLibs.addAll(libs.values());
0335: } catch (IOException e) {
0336: logger.warning("Cannot load libs from '"
0337: + application.getLibraryDirectory() + "' : "
0338: + e.getMessage(), e);
0339: }
0340:
0341: // APP-INF/lib/*
0342: try {
0343: Map<String, URL> libs = finder
0344: .getResourcesMap("APP-INF/lib/");
0345: extraLibs.addAll(libs.values());
0346: } catch (IOException e) {
0347: logger.warning(
0348: "Cannot load libs from 'APP-INF/lib/' : "
0349: + e.getMessage(), e);
0350: }
0351:
0352: // META-INF/lib/*
0353: try {
0354: Map<String, URL> libs = finder
0355: .getResourcesMap("META-INF/lib/");
0356: extraLibs.addAll(libs.values());
0357: } catch (IOException e) {
0358: logger.warning(
0359: "Cannot load libs from 'META-INF/lib/' : "
0360: + e.getMessage(), e);
0361: }
0362:
0363: // All jars nested in the Resource Adapter
0364: HashMap<String, URL> rarLibs = new HashMap<String, URL>();
0365: for (Map.Entry<String, URL> entry : resouceModules
0366: .entrySet()) {
0367: try {
0368: // unpack the resource adapter archive
0369: File rarFile = toFile(entry.getValue());
0370: rarFile = unpack(rarFile);
0371: entry.setValue(rarFile.toURL());
0372:
0373: scanDir(appDir, rarLibs, "");
0374: } catch (MalformedURLException e) {
0375: throw new OpenEJBException("Malformed URL to app. "
0376: + e.getMessage(), e);
0377: }
0378: }
0379: for (Iterator<Map.Entry<String, URL>> iterator = rarLibs
0380: .entrySet().iterator(); iterator.hasNext();) {
0381: // remove all non jars from the rarLibs
0382: Map.Entry<String, URL> fileEntry = iterator.next();
0383: if (!fileEntry.getKey().endsWith(".jar"))
0384: continue;
0385: iterator.remove();
0386: }
0387:
0388: List<URL> classPath = new ArrayList<URL>();
0389: classPath.addAll(ejbModules.values());
0390: classPath.addAll(clientModules.values());
0391: classPath.addAll(rarLibs.values());
0392: classPath.addAll(extraLibs);
0393: URL[] urls = classPath.toArray(new URL[classPath.size()]);
0394: ClassLoader appClassLoader = ClassLoaderUtil
0395: .createTempClassLoader(appId, urls, OpenEJB.class
0396: .getClassLoader());
0397:
0398: //
0399: // Create the AppModule and all nested module objects
0400: //
0401:
0402: AppModule appModule = new AppModule(appClassLoader, appId);
0403: appModule.getAdditionalLibraries().addAll(extraLibs);
0404: appModule.getAltDDs().putAll(appDescriptors);
0405: appModule.getWatchedResources().add(appId);
0406: if (applicationXmlUrl != null) {
0407: appModule.getWatchedResources().add(
0408: URLs.toFilePath(applicationXmlUrl));
0409: }
0410:
0411: // EJB modules
0412: for (String moduleName : ejbModules.keySet()) {
0413: try {
0414: URL ejbUrl = ejbModules.get(moduleName);
0415: File ejbFile = toFile(ejbUrl);
0416: String absolutePath = ejbFile.getAbsolutePath();
0417:
0418: EjbModule ejbModule = createEjbModule(ejbUrl,
0419: absolutePath, appClassLoader, moduleName);
0420:
0421: appModule.getEjbModules().add(ejbModule);
0422: } catch (OpenEJBException e) {
0423: logger.error("Unable to load EJBs from EAR: "
0424: + appId + ", module: " + moduleName
0425: + ". Exception: " + e.getMessage(), e);
0426: }
0427: }
0428:
0429: // Application Client Modules
0430: for (String moduleName : clientModules.keySet()) {
0431: try {
0432: URL clientUrl = clientModules.get(moduleName);
0433: File clientFile = toFile(clientUrl);
0434: String absolutePath = clientFile.getAbsolutePath();
0435:
0436: ClientModule clientModule = createClientModule(
0437: clientUrl, absolutePath, appClassLoader,
0438: moduleName);
0439:
0440: appModule.getClientModules().add(clientModule);
0441: } catch (Exception e) {
0442: logger.error("Unable to load App Client from EAR: "
0443: + appId + ", module: " + moduleName
0444: + ". Exception: " + e.getMessage(), e);
0445: }
0446: }
0447:
0448: // Resource modules
0449: for (String moduleName : resouceModules.keySet()) {
0450: try {
0451: URL rarUrl = resouceModules.get(moduleName);
0452: ConnectorModule connectorModule = createConnectorModule(
0453: appId, URLs.toFilePath(rarUrl),
0454: appClassLoader, moduleName);
0455:
0456: appModule.getResourceModules().add(connectorModule);
0457: } catch (OpenEJBException e) {
0458: logger.error("Unable to load RAR: " + appId
0459: + ", module: " + moduleName
0460: + ". Exception: " + e.getMessage(), e);
0461: }
0462: }
0463:
0464: // Web modules
0465: for (String moduleName : webModules.keySet()) {
0466: try {
0467: URL warUrl = webModules.get(moduleName);
0468: addWebModule(appModule, URLs.toFilePath(warUrl),
0469: appClassLoader, webContextRoots
0470: .get(moduleName), moduleName);
0471: } catch (OpenEJBException e) {
0472: logger.error("Unable to load WAR: " + appId
0473: + ", module: " + moduleName
0474: + ". Exception: " + e.getMessage(), e);
0475: }
0476: }
0477:
0478: // Persistence Units
0479: addPersistenceUnits(appModule, urls);
0480:
0481: return appModule;
0482:
0483: } catch (OpenEJBException e) {
0484: logger.error("Unable to load EAR: " + jarPath, e);
0485: throw e;
0486: }
0487: }
0488:
0489: protected static ClientModule createClientModule(URL clientUrl,
0490: String absolutePath, ClassLoader appClassLoader,
0491: String moduleName) throws IOException, OpenEJBException {
0492: ResourceFinder clientFinder = new ResourceFinder(clientUrl);
0493:
0494: URL manifestUrl = clientFinder.find("META-INF/MANIFEST.MF");
0495: InputStream is = manifestUrl.openStream();
0496: Manifest manifest = new Manifest(is);
0497: String mainClass = manifest.getMainAttributes().getValue(
0498: Attributes.Name.MAIN_CLASS);
0499:
0500: if (mainClass == null)
0501: throw new IllegalStateException(
0502: "No Main-Class defined in META-INF/MANIFEST.MF file");
0503: Map<String, URL> descriptors = getDescriptors(clientUrl);
0504:
0505: ApplicationClient applicationClient = null;
0506: URL clientXmlUrl = descriptors.get("application-client.xml");
0507: if (clientXmlUrl != null) {
0508: applicationClient = ReadDescriptors
0509: .readApplicationClient(clientXmlUrl);
0510: }
0511:
0512: ClientModule clientModule = new ClientModule(applicationClient,
0513: appClassLoader, absolutePath, mainClass, moduleName);
0514:
0515: clientModule.getAltDDs().putAll(descriptors);
0516: clientModule.getWatchedResources().add(absolutePath);
0517: if (clientXmlUrl != null
0518: && "file".equals(clientXmlUrl.getProtocol())) {
0519: clientModule.getWatchedResources().add(
0520: URLs.toFilePath(clientXmlUrl));
0521: }
0522: return clientModule;
0523: }
0524:
0525: protected static EjbModule createEjbModule(URL baseUrl,
0526: String jarPath, ClassLoader classLoader, String moduleId)
0527: throws OpenEJBException {
0528: // read the ejb-jar.xml file
0529: Map<String, URL> descriptors = getDescriptors(baseUrl);
0530:
0531: EjbJar ejbJar = null;
0532: URL ejbJarXmlUrl = descriptors.get("ejb-jar.xml");
0533: if (ejbJarXmlUrl != null) {
0534: ejbJar = ReadDescriptors.readEjbJar(ejbJarXmlUrl);
0535: }
0536:
0537: // create the EJB Module
0538: EjbModule ejbModule = new EjbModule(classLoader, moduleId,
0539: jarPath, ejbJar, null);
0540: ejbModule.getAltDDs().putAll(descriptors);
0541: ejbModule.getWatchedResources().add(jarPath);
0542: if (ejbJarXmlUrl != null
0543: && "file".equals(ejbJarXmlUrl.getProtocol())) {
0544: ejbModule.getWatchedResources().add(
0545: URLs.toFilePath(ejbJarXmlUrl));
0546: }
0547:
0548: // load webservices descriptor
0549: addWebservices(ejbModule);
0550: return ejbModule;
0551: }
0552:
0553: protected static void addWebModule(AppModule appModule,
0554: String warPath, ClassLoader parentClassLoader,
0555: String contextRoot, String moduleName)
0556: throws OpenEJBException {
0557: WebModule webModule = createWebModule(appModule
0558: .getJarLocation(), warPath, parentClassLoader,
0559: contextRoot, moduleName);
0560: appModule.getWebModules().add(webModule);
0561:
0562: ClassLoader webClassLoader = webModule.getClassLoader();
0563:
0564: // get urls in web application
0565: List<URL> urls = null;
0566: try {
0567: UrlSet urlSet = new UrlSet(webClassLoader);
0568: urlSet = urlSet.exclude(webClassLoader.getParent());
0569: urls = urlSet.getUrls();
0570: } catch (IOException e) {
0571: logger
0572: .warning("Unable to determine URLs in classloader",
0573: e);
0574: }
0575:
0576: // clean jar URLs
0577: for (int i = 0; i < urls.size(); i++) {
0578: URL url = urls.get(i);
0579: if (url.getProtocol().equals("jar")) {
0580: try {
0581: url = new URL(url.getFile()
0582: .replaceFirst("!.*$", ""));
0583: urls.set(i, url);
0584: } catch (MalformedURLException ignored) {
0585: }
0586: }
0587: }
0588:
0589: // check each url to determine if it is an ejb jar
0590: for (URL ejbUrl : urls) {
0591: try {
0592: Class moduleType = DeploymentLoader.discoverModuleType(
0593: ejbUrl, webClassLoader, true);
0594: if (EjbModule.class.isAssignableFrom(moduleType)) {
0595: File ejbFile = toFile(ejbUrl);
0596: String absolutePath = ejbFile.getAbsolutePath();
0597:
0598: EjbModule ejbModule = createEjbModule(ejbUrl,
0599: absolutePath, webClassLoader, null);
0600:
0601: appModule.getEjbModules().add(ejbModule);
0602: }
0603: } catch (IOException e) {
0604: } catch (UnknownModuleTypeException ignore) {
0605: }
0606: }
0607:
0608: // Persistence Units
0609: addPersistenceUnits(appModule);
0610:
0611: }
0612:
0613: protected static WebModule createWebModule(String appId,
0614: String warPath, ClassLoader parentClassLoader,
0615: String contextRoot, String moduleName)
0616: throws OpenEJBException {
0617: File warFile = new File(warPath);
0618: warFile = unpack(warFile);
0619:
0620: // read web.xml file
0621: Map<String, URL> descriptors;
0622: try {
0623: descriptors = getWebDescriptors(warFile);
0624: } catch (IOException e) {
0625: throw new OpenEJBException(
0626: "Unable to determine descriptors in jar.", e);
0627: }
0628:
0629: WebApp webApp = null;
0630: URL webXmlUrl = descriptors.get("web.xml");
0631: if (webXmlUrl != null) {
0632: webApp = ReadDescriptors.readWebApp(webXmlUrl);
0633: }
0634:
0635: // if this is a standalone module (no-context root), and webApp.getId is set then that is the module name
0636: if (contextRoot == null && webApp != null
0637: && webApp.getId() != null) {
0638: moduleName = webApp.getId();
0639: }
0640:
0641: // determine war class path
0642: List<URL> webClassPath = new ArrayList<URL>();
0643: File webInfDir = new File(warFile, "WEB-INF");
0644: try {
0645: webClassPath.add(new File(webInfDir, "classes").toURL());
0646: } catch (MalformedURLException e) {
0647: logger.warning("War path bad: "
0648: + new File(webInfDir, "classes"), e);
0649: }
0650:
0651: File libDir = new File(webInfDir, "lib");
0652: if (libDir.exists()) {
0653: for (File file : libDir.listFiles()) {
0654: if (file.getName().endsWith(".jar")
0655: || file.getName().endsWith(".zip")) {
0656: try {
0657: webClassPath.add(file.toURL());
0658: } catch (MalformedURLException e) {
0659: logger.warning("War path bad: " + file, e);
0660: }
0661: }
0662: }
0663: }
0664:
0665: // create the class loader
0666: URL[] webUrls = webClassPath.toArray(new URL[webClassPath
0667: .size()]);
0668: ClassLoader warClassLoader = ClassLoaderUtil
0669: .createTempClassLoader(appId, webUrls,
0670: parentClassLoader);
0671:
0672: // create web module
0673: WebModule webModule = new WebModule(webApp, contextRoot,
0674: warClassLoader, warFile.getAbsolutePath(), moduleName);
0675: webModule.getAltDDs().putAll(descriptors);
0676: webModule.getWatchedResources().add(warPath);
0677: webModule.getWatchedResources().add(warFile.getAbsolutePath());
0678: if (webXmlUrl != null && "file".equals(webXmlUrl.getProtocol())) {
0679: webModule.getWatchedResources().add(
0680: URLs.toFilePath(webXmlUrl));
0681: }
0682:
0683: // find all tag libs
0684: addTagLibraries(webModule);
0685:
0686: // load webservices descriptor
0687: addWebservices(webModule);
0688:
0689: return webModule;
0690: }
0691:
0692: private static void addWebservices(WsModule wsModule)
0693: throws OpenEJBException {
0694: // get location of webservices.xml file
0695: Object webservicesObject = wsModule.getAltDDs().get(
0696: "webservices.xml");
0697: if (webservicesObject == null
0698: || !(webservicesObject instanceof URL)) {
0699: return;
0700: }
0701: URL webservicesUrl = (URL) webservicesObject;
0702:
0703: // determine the base url for this module (either file: or jar:)
0704: URL moduleUrl;
0705: try {
0706: File jarFile = new File(wsModule.getJarLocation());
0707: moduleUrl = jarFile.toURL();
0708: if (jarFile.isFile()) {
0709: moduleUrl = new URL("jar", "", -1, moduleUrl + "!/");
0710: }
0711: } catch (MalformedURLException e) {
0712: logger.warning("Invalid module location "
0713: + wsModule.getJarLocation());
0714: return;
0715: }
0716:
0717: // parse the webservices.xml file
0718: Map<URL, JavaWsdlMapping> jaxrpcMappingCache = new HashMap<URL, JavaWsdlMapping>();
0719: Webservices webservices = ReadDescriptors
0720: .readWebservices(webservicesUrl);
0721: wsModule.setWebservices(webservices);
0722: if ("file".equals(webservicesUrl.getProtocol())) {
0723: wsModule.getWatchedResources().add(
0724: URLs.toFilePath(webservicesUrl));
0725: }
0726:
0727: // parse any jaxrpc-mapping-files mentioned in the webservices.xml file
0728: for (WebserviceDescription webserviceDescription : webservices
0729: .getWebserviceDescription()) {
0730: String jaxrpcMappingFile = webserviceDescription
0731: .getJaxrpcMappingFile();
0732: if (jaxrpcMappingFile != null) {
0733: URL jaxrpcMappingUrl;
0734: try {
0735: jaxrpcMappingUrl = new URL(moduleUrl,
0736: jaxrpcMappingFile);
0737: JavaWsdlMapping jaxrpcMapping = jaxrpcMappingCache
0738: .get(jaxrpcMappingUrl);
0739: if (jaxrpcMapping == null) {
0740: jaxrpcMapping = ReadDescriptors
0741: .readJaxrpcMapping(jaxrpcMappingUrl);
0742: jaxrpcMappingCache.put(jaxrpcMappingUrl,
0743: jaxrpcMapping);
0744: }
0745: webserviceDescription
0746: .setJaxrpcMapping(jaxrpcMapping);
0747: if ("file".equals(jaxrpcMappingUrl.getProtocol())) {
0748: wsModule.getWatchedResources().add(
0749: URLs.toFilePath(jaxrpcMappingUrl));
0750: }
0751: } catch (MalformedURLException e) {
0752: logger
0753: .warning("Invalid jaxrpc-mapping-file location "
0754: + jaxrpcMappingFile);
0755: }
0756: }
0757: }
0758:
0759: }
0760:
0761: private static void addTagLibraries(WebModule webModule)
0762: throws OpenEJBException {
0763: Set<URL> tldLocations = new HashSet<URL>();
0764:
0765: // web.xml contains tag lib locations in nested jsp config elements
0766: File warFile = new File(webModule.getJarLocation());
0767: WebApp webApp = webModule.getWebApp();
0768: if (webApp != null) {
0769: for (JspConfig jspConfig : webApp.getJspConfig()) {
0770: for (Taglib taglib : jspConfig.getTaglib()) {
0771: String location = taglib.getTaglibLocation();
0772: if (!location.startsWith("/")) {
0773: // this reproduces a tomcat bug
0774: location = "/WEB-INF/" + location;
0775: }
0776: try {
0777: File file = new File(warFile, location)
0778: .getCanonicalFile().getAbsoluteFile();
0779: if (location.endsWith(".jar")) {
0780: URL url = file.toURL();
0781: tldLocations.add(url);
0782: } else {
0783: Set<URL> urls = scanJarForTagLibs(file);
0784: tldLocations.addAll(urls);
0785: }
0786: } catch (IOException e) {
0787: logger.warning("JSP tag library location bad: "
0788: + location, e);
0789: }
0790: }
0791: }
0792: }
0793:
0794: // WEB-INF/**/*.tld except in WEB-INF/classes and WEB-INF/lib
0795: Set<URL> urls = scanWarForTagLibs(warFile);
0796: tldLocations.addAll(urls);
0797:
0798: // Search all libs
0799: ClassLoader parentClassLoader = webModule.getClassLoader()
0800: .getParent();
0801: urls = scanClassLoaderForTagLibs(parentClassLoader);
0802: tldLocations.addAll(urls);
0803:
0804: // load the tld files
0805: for (URL location : tldLocations) {
0806: TldTaglib taglib = ReadDescriptors.readTldTaglib(location);
0807: webModule.getTaglibs().add(taglib);
0808: if ("file".equals(location.getProtocol())) {
0809: webModule.getWatchedResources().add(
0810: URLs.toFilePath(location));
0811: }
0812: }
0813: }
0814:
0815: private static Set<URL> scanClassLoaderForTagLibs(
0816: ClassLoader parentClassLoader) throws OpenEJBException {
0817: Set<URL> urls = new HashSet<URL>();
0818: if (parentClassLoader == null)
0819: return urls;
0820:
0821: UrlSet urlSet;
0822: try {
0823: urlSet = new UrlSet(parentClassLoader);
0824: urlSet = urlSet.excludeJavaEndorsedDirs();
0825: urlSet = urlSet.excludeJavaExtDirs();
0826: urlSet = urlSet.excludeJavaHome();
0827: urlSet = urlSet.exclude(ClassLoader.getSystemClassLoader());
0828: } catch (IOException e) {
0829: logger
0830: .warning(
0831: "Error scanning class loader for JSP tag libraries",
0832: e);
0833: return urls;
0834: }
0835:
0836: for (URL url : urlSet.getUrls()) {
0837: if (url.getProtocol().equals("jar")) {
0838: try {
0839: String path = url.getPath();
0840: if (path.endsWith("!/")) {
0841: path = path.substring(0, path.length() - 2);
0842: }
0843: url = new URL(path);
0844: } catch (MalformedURLException e) {
0845: logger.warning("JSP tag library location bad: "
0846: + url.toExternalForm(), e);
0847: continue;
0848: }
0849: }
0850:
0851: if (!url.getProtocol().equals("file")) {
0852: continue;
0853: }
0854:
0855: File file = toFile(url);
0856: try {
0857: file = file.getCanonicalFile().getAbsoluteFile();
0858: } catch (IOException e) {
0859: logger.warning("JSP tag library location bad: "
0860: + file.getAbsolutePath(), e);
0861: continue;
0862: }
0863:
0864: urls.addAll(scanJarForTagLibs(file));
0865: }
0866: return urls;
0867: }
0868:
0869: private static Set<URL> scanWarForTagLibs(File war) {
0870: Set<URL> urls = new HashSet<URL>();
0871:
0872: File webInfDir = new File(war, "WEB-INF");
0873: if (!webInfDir.isDirectory())
0874: return urls;
0875:
0876: // skip the lib and classes dir in WEB-INF
0877: LinkedList<File> files = new LinkedList<File>();
0878: for (File file : webInfDir.listFiles()) {
0879: if ("lib".equals(file.getName())
0880: || "classes".equals(file.getName())) {
0881: continue;
0882: }
0883: files.add(file);
0884: }
0885:
0886: if (files.isEmpty())
0887: return urls;
0888:
0889: // recursively scan the directories
0890: while (!files.isEmpty()) {
0891: File file = files.removeFirst();
0892: if (file.isDirectory()) {
0893: files.addAll(Arrays.asList(file.listFiles()));
0894: } else if (file.getName().endsWith(".tld")) {
0895: try {
0896: file = file.getCanonicalFile().getAbsoluteFile();
0897: urls.add(file.toURL());
0898: } catch (IOException e) {
0899: logger.warning("JSP tag library location bad: "
0900: + file.getAbsolutePath(), e);
0901: }
0902: }
0903: }
0904:
0905: return urls;
0906: }
0907:
0908: private static Set<URL> scanJarForTagLibs(File file) {
0909: Set<URL> urls = new HashSet<URL>();
0910:
0911: if (!file.isFile())
0912: return urls;
0913:
0914: JarFile jarFile = null;
0915: try {
0916: jarFile = new JarFile(file);
0917:
0918: URL jarFileUrl = new URL("jar", "", -1, file.toURL()
0919: .toExternalForm()
0920: + "!/");
0921: for (JarEntry entry : Collections.list(jarFile.entries())) {
0922: String name = entry.getName();
0923: if (!name.startsWith("META-INF/")
0924: || !name.endsWith(".tld")) {
0925: continue;
0926: }
0927: URL url = new URL(jarFileUrl, name);
0928: urls.add(url);
0929: }
0930: } catch (IOException e) {
0931: logger.warning("Error scanning jar for JSP tag libraries: "
0932: + file.getAbsolutePath(), e);
0933: } finally {
0934: if (jarFile != null) {
0935: try {
0936: jarFile.close();
0937: } catch (IOException e) {
0938: // exception ignored
0939: }
0940: }
0941: }
0942:
0943: return urls;
0944: }
0945:
0946: protected static ConnectorModule createConnectorModule(
0947: String appId, String rarPath,
0948: ClassLoader parentClassLoader, String moduleId)
0949: throws OpenEJBException {
0950: URL baseUrl;// unpack the rar file
0951: File rarFile = new File(rarPath);
0952: rarFile = unpack(rarFile);
0953: baseUrl = getFileUrl(rarFile);
0954:
0955: // read the ra.xml file
0956: Map<String, URL> descriptors = getDescriptors(baseUrl);
0957: Connector connector = null;
0958: URL rarXmlUrl = descriptors.get("ra.xml");
0959: if (rarXmlUrl != null) {
0960: connector = ReadDescriptors.readConnector(rarXmlUrl);
0961: }
0962:
0963: // find the nested jar files
0964: HashMap<String, URL> rarLibs = new HashMap<String, URL>();
0965: scanDir(rarFile, rarLibs, "");
0966: for (Iterator<Map.Entry<String, URL>> iterator = rarLibs
0967: .entrySet().iterator(); iterator.hasNext();) {
0968: // remove all non jars from the rarLibs
0969: Map.Entry<String, URL> fileEntry = iterator.next();
0970: if (!fileEntry.getKey().endsWith(".jar")) {
0971: iterator.remove();
0972: }
0973: }
0974:
0975: // create the class loader
0976: List<URL> classPath = new ArrayList<URL>();
0977: classPath.addAll(rarLibs.values());
0978: URL[] urls = classPath.toArray(new URL[classPath.size()]);
0979: ClassLoader appClassLoader = ClassLoaderUtil
0980: .createTempClassLoader(appId, urls, parentClassLoader);
0981:
0982: // create the Resource Module
0983: ConnectorModule connectorModule = new ConnectorModule(
0984: connector, appClassLoader, rarPath, moduleId);
0985: connectorModule.getAltDDs().putAll(descriptors);
0986: connectorModule.getLibraries().addAll(classPath);
0987: connectorModule.getWatchedResources().add(rarPath);
0988: connectorModule.getWatchedResources().add(
0989: rarFile.getAbsolutePath());
0990: if (rarXmlUrl != null && "file".equals(rarXmlUrl.getProtocol())) {
0991: connectorModule.getWatchedResources().add(
0992: URLs.toFilePath(rarXmlUrl));
0993: }
0994:
0995: return connectorModule;
0996: }
0997:
0998: @SuppressWarnings({"unchecked"})
0999: protected static void addPersistenceUnits(AppModule appModule,
1000: URL... urls) {
1001: try {
1002: // any class loader will do here since we are not calling class loading methods of resource finder
1003: ResourceFinder finder = new ResourceFinder("", ClassLoader
1004: .getSystemClassLoader(), urls);
1005: List<URL> persistenceUrls = (List<URL>) appModule
1006: .getAltDDs().get("persistence.xml");
1007: if (persistenceUrls == null) {
1008: persistenceUrls = new ArrayList<URL>();
1009: appModule.getAltDDs().put("persistence.xml",
1010: persistenceUrls);
1011: }
1012: persistenceUrls.addAll(finder
1013: .findAll("META-INF/persistence.xml"));
1014: } catch (IOException e) {
1015: logger.warning(
1016: "Cannot load persistence-units from 'META-INF/persistence.xml' : "
1017: + e.getMessage(), e);
1018: }
1019: }
1020:
1021: private static Map<String, URL> getDescriptors(URL moduleUrl)
1022: throws OpenEJBException {
1023: try {
1024: ResourceFinder finder = new ResourceFinder(moduleUrl);
1025:
1026: return finder.getResourcesMap("META-INF/");
1027:
1028: } catch (IOException e) {
1029: throw new OpenEJBException(
1030: "Unable to determine descriptors in jar.", e);
1031: }
1032: }
1033:
1034: private static Map<String, URL> getWebDescriptors(File warFile)
1035: throws IOException {
1036: Map<String, URL> descriptors = new TreeMap<String, URL>();
1037:
1038: // xbean resource finder has a bug when you use any uri but "META-INF"
1039: // and the jar file does not contain a directory entry for the uri
1040:
1041: if (warFile.isFile()) {
1042: URL jarURL = new URL("jar", "", -1, warFile.toURL() + "!/");
1043: try {
1044: JarFile jarFile = new JarFile(warFile);
1045: for (JarEntry entry : Collections.list(jarFile
1046: .entries())) {
1047: String entryName = entry.getName();
1048: if (!entry.isDirectory()
1049: && entryName.startsWith("WEB-INF/")
1050: && entryName.indexOf('/', "WEB-INF/"
1051: .length()) > 0) {
1052: descriptors.put(entryName, new URL(jarURL,
1053: entry.getName()));
1054: }
1055: }
1056: } catch (IOException e) {
1057: // most likely an invalid jar file
1058: }
1059: } else if (warFile.isDirectory()) {
1060: File webInfDir = new File(warFile, "WEB-INF");
1061: if (webInfDir.isDirectory()) {
1062: for (File file : webInfDir.listFiles()) {
1063: if (!file.isDirectory()) {
1064: descriptors.put(file.getName(), file.toURL());
1065: }
1066: }
1067: }
1068: }
1069:
1070: return descriptors;
1071: }
1072:
1073: protected static File getFile(URL warUrl) {
1074: if ("jar".equals(warUrl.getProtocol())) {
1075: String pathname = warUrl.getPath();
1076:
1077: // we only support file based jar urls
1078: if (!pathname.startsWith("file:")) {
1079: return null;
1080: }
1081:
1082: // strip off "file:"
1083: pathname = pathname.substring("file:".length());
1084:
1085: // file path has trailing !/ that must be stripped off
1086: pathname = pathname.substring(0, pathname.lastIndexOf('!'));
1087:
1088: pathname = URLDecoder.decode(pathname);
1089: return new File(pathname);
1090: } else if ("file".equals(warUrl.getProtocol())) {
1091: String pathname = warUrl.getPath();
1092: return new File(URLDecoder.decode(pathname));
1093: } else {
1094: return null;
1095: }
1096: }
1097:
1098: @SuppressWarnings({"unchecked"})
1099: public static <T> T unmarshal(Class<T> type, String descriptor,
1100: URL url) throws OpenEJBException {
1101: try {
1102: return (T) JaxbJavaee.unmarshal(type, url.openStream());
1103: } catch (SAXException e) {
1104: throw new OpenEJBException("Cannot parse the " + descriptor
1105: + " file: " + url.toExternalForm(), e);
1106: } catch (JAXBException e) {
1107: throw new OpenEJBException("Cannot unmarshall the "
1108: + descriptor + " file: " + url.toExternalForm(), e);
1109: } catch (IOException e) {
1110: throw new OpenEJBException("Cannot read the " + descriptor
1111: + " file: " + url.toExternalForm(), e);
1112: } catch (Exception e) {
1113: throw new OpenEJBException(
1114: "Encountered unknown error parsing the "
1115: + descriptor + " file: "
1116: + url.toExternalForm(), e);
1117: }
1118: }
1119:
1120: public static void scanDir(File dir, Map<String, URL> files,
1121: String path) {
1122: for (File file : dir.listFiles()) {
1123: if (file.isDirectory()) {
1124: scanDir(file, files, path + file.getName() + "/");
1125: } else {
1126: String name = file.getName();
1127: try {
1128: files.put(path + name, file.toURL());
1129: } catch (MalformedURLException e) {
1130: logger.warning("EAR path bad: " + path + name, e);
1131: }
1132: }
1133: }
1134: }
1135:
1136: public static Class<? extends DeploymentModule> discoverModuleType(
1137: URL baseUrl, ClassLoader classLoader,
1138: boolean searchForDescriptorlessApplications)
1139: throws IOException, UnknownModuleTypeException {
1140: ResourceFinder finder = new ResourceFinder("", classLoader,
1141: baseUrl);
1142:
1143: Map<String, URL> descriptors = finder
1144: .getResourcesMap("META-INF");
1145:
1146: String path = baseUrl.getPath();
1147: if (path.endsWith("/"))
1148: path = path.substring(0, path.length() - 1);
1149:
1150: if (descriptors.containsKey("application.xml")
1151: || path.endsWith(".ear")) {
1152: return AppModule.class;
1153: }
1154:
1155: if (descriptors.containsKey("ejb-jar.xml")) {
1156: return EjbModule.class;
1157: }
1158:
1159: if (descriptors.containsKey("application-client.xml")) {
1160: return ClientModule.class;
1161: }
1162:
1163: if (descriptors.containsKey("ra.xml") || path.endsWith(".rar")) {
1164: return ConnectorModule.class;
1165: }
1166:
1167: Map<String, URL> webDescriptors = getWebDescriptors(getFile(baseUrl));
1168: if (webDescriptors.containsKey("web.xml")
1169: || path.endsWith(".war")) {
1170: return WebModule.class;
1171: }
1172:
1173: URL manifestUrl = descriptors.get("MANIFEST.MF");
1174: if (manifestUrl != null) {
1175: InputStream is = manifestUrl.openStream();
1176: Manifest manifest = new Manifest(is);
1177: String mainClass = manifest.getMainAttributes().getValue(
1178: Attributes.Name.MAIN_CLASS);
1179: if (mainClass != null) {
1180: return ClientModule.class;
1181: }
1182: }
1183:
1184: if (searchForDescriptorlessApplications) {
1185: ClassFinder classFinder = new ClassFinder(classLoader,
1186: baseUrl);
1187:
1188: if (classFinder.isAnnotationPresent(Stateless.class)
1189: || classFinder.isAnnotationPresent(Stateful.class)
1190: || classFinder
1191: .isAnnotationPresent(MessageDriven.class)) {
1192: return EjbModule.class;
1193: }
1194: }
1195:
1196: throw new UnknownModuleTypeException(
1197: "Unknown module type: url=" + baseUrl.toExternalForm());
1198: }
1199:
1200: private static File unpack(File jarFile) throws OpenEJBException {
1201: if (jarFile.isDirectory()) {
1202: return jarFile;
1203: }
1204:
1205: String name = jarFile.getName();
1206: if (name.endsWith(".jar") || name.endsWith(".ear")
1207: || name.endsWith(".zip") || name.endsWith(".war")
1208: || name.endsWith(".rar")) {
1209: name = name.replaceFirst("....$", "");
1210: } else {
1211: name += ".unpacked";
1212: }
1213:
1214: try {
1215: return JarExtractor.extract(jarFile, name);
1216: } catch (IOException e) {
1217: throw new OpenEJBException("Unable to extract jar. "
1218: + e.getMessage(), e);
1219: }
1220: }
1221:
1222: protected static URL getFileUrl(File jarFile)
1223: throws OpenEJBException {
1224: URL baseUrl;
1225: try {
1226: baseUrl = jarFile.toURL();
1227: } catch (MalformedURLException e) {
1228: throw new OpenEJBException("Malformed URL to app. "
1229: + e.getMessage(), e);
1230: }
1231: return baseUrl;
1232: }
1233: }
|