/* * JBoss, the OpenSource EJB server * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.deployment; import java.io.File; import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.StringTokenizer; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.jboss.logging.Logger; import org.jboss.metadata.XmlFileLoader; /** An implementation of Installer that only works with unpackaged J2EE modules as local directories. There is no copying of package contents. @author Scott.Stark@jboss.org */ public class LocalDirInstaller implements Installer { // the URL to install URL src; // the resulting Deployment Deployment d; // the log4j category for output Logger log; // flag to not run execute twice boolean done; /** Creates a new instance of ModuleInstaller */ public LocalDirInstaller() { } public Deployment execute(InstallerFactory factory, URL src) throws J2eeDeploymentException, IOException { this.log = factory.log; d = new Deployment(); d.name = Util.getName(src.toString()); d.sourceUrl=src; File localPkg = null; boolean trace = log.isTraceEnabled(); if( trace ) log.trace("execute, src="+src); if( src.getProtocol().startsWith("file") == false ) throw new J2eeDeploymentException("Only local file: URL are supported by LocalDirInstaller"); try { localPkg = new File(src.getFile()); // Determine the type of the deployment d.type = Util.hasDeploymentDescriptor(localPkg); if( d.type < 0 ) throw new J2eeDeploymentException("LocalPkg: "+localPkg+" has no valid deployment descriptors"); d.localUrl = localPkg.toURL(); if( trace ) log.trace("Deployment type is: "+d.type); switch(d.type) { // A stand-alone EJB module case Deployment.EJB_MODULE: { log.info("install EJB module "+d.name); // Check for libs declared in the EJB jar manifest URL[] libs = resolveLibraries(localPkg); URL localURL = localPkg.toURL(); d.addEjbModule(d.name, localURL, libs); } break; // A stand-alone WAR module case Deployment.WAR_MODULE: { /* Build a default webContext based on the deployment war name. We have to do this here because the warURL passed to the WAR deployer is the local copy war name. We could change the deployment interface to include the full deployment info as is done in 3.x, but this will work for now. We simply pass the original name of the war file as the context root with a leading null '\0' character. The WAR deployer has to understand this wacked */ String webContext = "" + '\0' + d.name; log.info("inflate and install WEB module "+d.name); // Check for libs declared int the WAR jar manifest URL[] libs = libs = resolveLibraries(localPkg); URL localURL = localPkg.toURL(); d.addWebModule(d.name, webContext, localURL, libs); } break; // A J2EE app with any number of ejb and war modules case Deployment.EAR_MODULE: { J2eeApplicationMetaData app = null; try { URL appXml = new URL(localPkg.toURL(), Installer.files[d.type]); Document appDoc = XmlFileLoader.getDocument(appXml, false); Element root = appDoc.getDocumentElement(); app = new J2eeApplicationMetaData(root); } catch (DeploymentException e) { throw new J2eeDeploymentException("Error in parsing application.xml", e); } // iterating the ejb and web modules and install them ArrayList ejbJars = new ArrayList(); Iterator it = app.getModules(); while( it.hasNext() ) { // iterate the ear modules J2eeModuleMetaData mod = (J2eeModuleMetaData) it.next(); if( mod.isEjb() ) { String name = mod.getFileName(); log.debug("Process EJB module "+name); try { File ejbPkg = new File(localPkg, name); if( ejbPkg.isDirectory() == false ) throw new J2eeDeploymentException("EJB module: "+ejbPkg+" is not a directory"); URL[] libs = resolveLibraries(ejbPkg); URL localURL = ejbPkg.toURL(); d.addEjbModule(name, localURL, libs); ejbJars.add(localURL); } catch (IOException _ioe) { throw _ioe; } catch (NullPointerException _npe) { log.info("module "+name+" not found in "+d.name); throw new J2eeDeploymentException("module "+name+" not found in "+d.name); } } else if( mod.isWeb() ) { String name = mod.getFileName(); String webContext = mod.getWebContext(); log.debug("Process WEB module "+name); try { File warPkg = new File(localPkg, name); if( warPkg.isDirectory() == false ) throw new J2eeDeploymentException("WAR module: "+warPkg+" is not a directory"); URL[] libs = resolveLibraries(warPkg); URL localURL = warPkg.toURL(); d.addWebModule(name, webContext, localURL, libs); } catch (IOException _ioe) { throw _ioe; } catch (NullPointerException _npe) { log.info("module "+name+" not found in "+d.name); throw new J2eeDeploymentException("module "+name+" not found in "+d.name); } } // other packages we dont care about (currently) } // put all ejb jars to the common classpath too if( ejbJars.size() > 0 ) log.debug("Adding all ejb jar files to the common classpath"); for(int e = 0; e < ejbJars.size(); e ++) { URL jar = (URL) ejbJars.get(e); d.commonUrls.add(jar); } } break; } //saveConfig(); } catch(Throwable t) { log.error("Deployment failed", t); } return d; } /** Resolves all Class-Path: entries from the Manifest * @param mf the Manifest to process * @param baseURL the URL to which the Class-Path entries will be relative @return URL[] the array of URLs for the valid Class-Path entries */ private URL[] resolveLibraries(File localFile) { URL[] libs = {}; // Locate a manifest Manifest mf = null; URL baseURL = null; try { baseURL = localFile.toURL(); File mfFile = new File(localFile, "META-INF" + File.separator + "MANIFEST.MF"); if( mfFile.exists() == false ) { mfFile = new File(localFile, "meta-inf" + File.separator + "manifest.mf"); } if( mfFile.exists() == true ) { FileInputStream fis = new FileInputStream(mfFile); mf = new Manifest(fis); } } catch(IOException e) { if( log.isTraceEnabled() ) log.trace("resolveLibraries, error reading manifest", e); return libs; } String classPath = null; if( mf != null ) { Attributes mainAttributes = mf.getMainAttributes(); classPath = mainAttributes.getValue(Attributes.Name.CLASS_PATH); } if (classPath != null) { ArrayList tmp = new ArrayList(); StringTokenizer st = new StringTokenizer(classPath); log.debug("resolveLibraries, Manifest Class-Path: "+classPath); while (st.hasMoreTokens()) { String tk = st.nextToken(); try { URL lib = new URL(baseURL, tk); tmp.add(lib); log.debug("added "+lib+" to common classpath"); } catch (IOException _ioe) { log.warn("Failed to add "+tk+" to common classpath: "+_ioe.getMessage()); } } libs = new URL[tmp.size()]; tmp.toArray(libs); } return libs; } }