User: schulze
Date: 00/11/02 14:43:54
Modified: src/main/org/jboss/deployment Deployment.java
J2eeDeployer.java URLWizzard.java
Log:
The J2eeDeployer now handles .ear, .jar, and .war files from http and file urls and
unpacked ejb archives (directoroies) from file:/ locations.
He manages the local copies of the files and the classloader stuff for the
ContainerFactory and the Web container (Tomcat).
Revision Changes Path
1.3 +36 -72 jboss/src/main/org/jboss/deployment/Deployment.java
Index: Deployment.java
===================================================================
RCS file: /products/cvs/ejboss/jboss/src/main/org/jboss/deployment/Deployment.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Deployment.java 2000/10/27 19:10:27 1.2
+++ Deployment.java 2000/11/02 22:43:53 1.3
@@ -15,103 +15,67 @@
/** Represents a J2EE application or module (EJB.jar, Web.war or App.ear). <br>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Daniel Schulze</a>
-* @version $Revision: 1.2 $
+* @version $Revision: 1.3 $
*/
public class Deployment
implements java.io.Serializable
{
- // the applications name
+ /** the apploications name */
protected String name;
- // the url from which this app is downloaded and under which it is deployed
- //protected URL downloadUrl;
- // the local position of the apps root directory
+
+ /** the local position of the apps root directory */
protected URL localUrl;
+
+ /** the directory for common libraries */
+ protected URL commonLibs;
+
+ /** the content of the <code>commonLibs</code> directory as
+ URL Collection */
+ protected Vector commonUrls;
- // the Modules for jBoss and Tomcat
+ /** the EJB Modules */
protected Vector ejbModules;
- protected Vector webModules;
+ /** the WEB Modules */
+ protected Vector webModules;
- /** Creates a new Deployment object.
- */
+ /** Creates a new Deployment object. */
Deployment ()
{
ejbModules = new Vector ();
webModules = new Vector ();
-
+
+ commonUrls = new Vector ();
}
+ /** returns a new instance of the Module innerclass */
public Module newModule ()
{
return new Module ();
}
-
- /** the name of the application.
- * @param the download URL
- * @return the app context as filename
- */
- public static String getAppName (URL _url)
- {
- String s = _url.getFile ();
- // if it is a jar:<something>!/path/file url
- if (_url.getProtocol ().equals ("jar"))
- {
- int p = s.lastIndexOf ("!");
- if (p != -1)
- s = s.substring (0, p);
- }
-
- return s.substring (Math.max (0, Math.min (s.length (), s.lastIndexOf ("/") +
1)));
- }
- /** returns app name with relative path in case of url is jar url.
jar:<something>!/
- * @param the download URL
- * @return wether file:|http:<bla>/<RETURNVALUE> or
jar:<something>!/<RETURNVALUE>
- */
- public static String getFileName (URL _url)
- {
- String s = _url.getFile ();
- int p = s.lastIndexOf ("!");
- if (p != -1)
- // jar url...
- s = s.substring (Math.min (p + 2, s.length ()));
- else
- s = s.substring (Math.max (0, Math.min (s.length (), s.lastIndexOf
("/") + 1)));
-
- return s;
- }
-
- /** tries to compose a webcontext for WAR files from the given war file url */
- public static String getWebContext (URL _downloadUrl)
- {
- String s = getFileName (_downloadUrl);
-
- // truncate the file extension
- int p = s.lastIndexOf (".");
- if (p != -1)
- s = s.substring (0, p);
-
- return "/" + s.replace ('.', '/');
- }
-
- /** Represents a J2ee module.
- * the downloadURL (in case of ear something like:
jar:applicationURL!/packagename)
- * the localURL where the downloaded file is placed
- * the downloadURL for an alternative dd
- * in case of a web package the optional web root context
- */
+ /** Represents a J2ee module. */
class Module
implements java.io.Serializable
{
- // a short name for the module
+ /** a short name for the module */
String name;
- // the url from which it is downloaded
- // (in case of ear module like: jar:<app.downloadUrl>!/<module>
- //URL downloadUrl;
- // the local url under which it is deployed by the special deployer
- URL localUrl;
- // the web root context in case of war file
- String webContext;
+
+ /** a collection of urls that make this module. <br>
+ actually there is only one url for the modules jar file or
+ in case of web the modules root directory needed. But to be able
+ to allow alternative descriptors, the base directories of this alternative
+ descriptors can be put here before the real module url, so that these where
+ found first */
+ Vector localUrls;
+
+ /** the web root context in case of war file */
+ String webContext;
+
+ Module ()
+ {
+ localUrls = new Vector ();
+ }
}
}
1.5 +344 -241 jboss/src/main/org/jboss/deployment/J2eeDeployer.java
Index: J2eeDeployer.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/deployment/J2eeDeployer.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- J2eeDeployer.java 2000/10/27 19:10:27 1.4
+++ J2eeDeployer.java 2000/11/02 22:43:53 1.5
@@ -19,6 +19,10 @@
import java.util.Hashtable;
import java.util.Vector;
import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
import javax.management.MBeanServer;
import javax.management.MBeanException;
@@ -39,27 +43,25 @@
/** J2eeDeployer allows to deploy single EJB.jars as well as Web.wars
-* (if Tomcat runs within the same VM as jBoss) or even Application.ears. <br>
+* (if a Servlet Container is present) or even Application.ears. <br>
* The deployment is done by determining the file type of the given url.
-* The file must be a valid zip file and must contain either a META-INF/ejb-jar.xml
+* The file must be a valid zip file or a directory and must contain either a
META-INF/ejb-jar.xml
* or META-INF/application.xml or a WEB-INF/web.xml file.
* Depending on the file type, the whole file (EJBs, WARs)
* or only the relevant packages (EAR) becoming downloaded. <br>
* <i> replacing alternative DDs and validation is not yet implementet! </i>
* The uploaded files are getting passed through to the responsible deployer
* (ContainerFactory for jBoss and EmbededTomcatService for Tomcat).
-* The state of deployments is persistent and becomes recovered after shutdown
-* or crash.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Daniel Schulze</a>
-* @version $Revision: 1.4 $
+* @version $Revision: 1.5 $
*/
public class J2eeDeployer
extends ServiceMBeanSupport
implements J2eeDeployerMBean
{
// Constants -----------------------------------------------------
- public String DEPLOYMENT_DIR = "/home/deployment"; // default? MUST BE ABSOLUTE
PATH!!!
+ public File DEPLOYMENT_DIR = null;//"/home/deployment"; // default? MUST BE
ABSOLUTE PATH!!!
public String CONFIG = "deployment.cfg";
// Attributes ----------------------------------------------------
@@ -76,10 +78,7 @@
// The logger for this service
Log log = new Log(getName());
- // the deployments
- Hashtable deployments = new Hashtable ();
-
// Static --------------------------------------------------------
/** only for testing...*/
public static void main (String[] _args) throws Exception
@@ -91,7 +90,7 @@
/** */
public J2eeDeployer (String _deployDir, String jarDeployerName, String
warDeployerName)
{
- DEPLOYMENT_DIR = _deployDir;
+ DEPLOYMENT_DIR = new File (_deployDir);
this.jarDeployerName = jarDeployerName;
this.warDeployerName = warDeployerName;
@@ -131,32 +130,53 @@
log.log ("j2ee application: " + _url + " is deployed.");
}
- catch (IOException _ioe)
- {
- uninstallApplication (_url.substring(Math.max (0, _url.lastIndexOf("/"))));
- throw _ioe;
- }
- catch (J2eeDeploymentException _e)
+ catch (Exception _e)
{
- if (d != null) // start failed...
- stopApplication (d);
-
- uninstallApplication (_url.substring(Math.max (0, _url.lastIndexOf("/"))));
- throw _e;
+ if (_e instanceof J2eeDeploymentException)
+ {
+ if (d != null) // start failed...
+ stopApplication (d);
+
+ uninstallApplication (getAppName (url));
+ throw (J2eeDeploymentException)_e;
+ }
+ else if (_e instanceof IOException)
+ {
+ // some download failed
+ uninstallApplication (getAppName (url));
+ throw (IOException)_e;
+ }
+ else
+ {
+ // Runtime Exception - shouldnt happen
+ log.exception (_e);
+ uninstallApplication (getAppName (url));
+ throw new J2eeDeploymentException ("fatal error: "+_e.toString ());
+ }
}
}
/** Undeploys the given URL (if it is deployed).
- * Actually only the file name is of interest, so it dont has to be
+ * Actually only the file name is of interest, so it dont has to be
* an URL to be undeployed, the file name is ok as well.
- * @param _url the url to to undeploy
+ * @param _url the url to to undeploy
* @throws MalformedURLException in case of a malformed url
* @throws J2eeDeploymentException if something went wrong (but should have
removed all files)
* @throws IOException if file removement fails
*/
public void undeploy (String _app) throws IOException, J2eeDeploymentException
{
- String name = _app.substring(Math.max (0, _app.lastIndexOf("/")));
+ String name;
+ try
+ {
+ name = getAppName (new URL (_app));
+ }
+ catch (MalformedURLException _e)
+ {
+ // must be only the name
+ name = _app;
+ }
+
Deployment d = null;
File f = new File (DEPLOYMENT_DIR + File.separator + name);
if (f.exists())
@@ -165,16 +185,16 @@
{
d = loadConfig (name);
stopApplication (d);
- }
+ }
catch (IOException _ioe)
{ // thrown by the load config
throw _ioe;
}
catch (J2eeDeploymentException _e)
{
- throw _e;
+ throw _e;
}
- finally
+ finally
{
uninstallApplication (name);
}
@@ -185,7 +205,7 @@
}
/** Checks if the given URL is currently deployed or not.
- * Actually only the file name is of interest, so it dont has to be
+ * Actually only the file name is of interest, so it dont has to be
* an URL to be undeployed, the file name is ok as well.
* @param _url the url to to check
* @return true if _url is deployed
@@ -196,14 +216,24 @@
public boolean isDeployed (String _url) throws MalformedURLException,
J2eeDeploymentException
{
// get Application name
- String name = _url.substring(Math.max (0, _url.lastIndexOf("/")));
+ String name;
+ try
+ {
+ name = getAppName (new URL (_url));
+ }
+ catch (MalformedURLException _e)
+ {
+ // must be only the name
+ name = _url;
+ }
+
Deployment d = null;
File f = new File (DEPLOYMENT_DIR + File.separator + name);
if (f.exists())
{
try
{
- return checkApplication (loadConfig (name));
+ return checkApplication (loadConfig (name));
}
catch (IOException e)
{
@@ -235,67 +265,22 @@
throws Exception
{
- //set the deployment directory
- DEPLOYMENT_DIR = new File (DEPLOYMENT_DIR).getCanonicalPath ();
+ //check if the deployment dir was set meaningful
+ if (!DEPLOYMENT_DIR.exists ())
+ throw new IOException ("temporary directory
\""+DEPLOYMENT_DIR.getCanonicalPath ()+"\" does not exist!");
// Save JMX name of the deployers
jarDeployer = new ObjectName(jarDeployerName);
warDeployer= new ObjectName(warDeployerName);
-
}
- /** tries to redeploy all deployments before shutdown.*/
+ /** */
protected void startService()
throws Exception
{
if (!warDeployerAvailable ())
log.log ("No war deployer found - only EJB deployment available...");
-
- /*
- // this doesnt work properly ?!
- // when something was deployed on server stop and on server restart
- // it becomes restarted (the same files) the ContainerFactory has a
- // strange problem in handling its copys of the jar files in the tmp/deploy
dir...
-
- log.log ("trying to start all applications that were running before
service.stop ()...");
-
- File f = new File (DEPLOYMENT_DIR);
- File[] files = f.listFiles();
- int count = 0;
- for (int i = 0, l = files.length; i<l; ++i)
- {
- if (files[i].isDirectory ())
- {
- // lets give it a try...
- Deployment d = null;
- try
- {
- d = loadConfig (files[i].getName());
- }
- catch (IOException _io)
- {
- continue;
- }
-
- // ok, then lets start it
- log.log ("starting application: " + d.name);
- try
- {
- startApplication (d);
- log.log ("application: " + d.name + " is started.");
- ++count;
- }
- catch (J2eeDeploymentException _e)
- {
- stopApplication (d);
- uninstallApplication (files[i].getName());
-
- _e.printStackTrace();
- }
- }
- }
- log.log ("started "+count+" applications.");
- */
+
}
@@ -304,8 +289,7 @@
{
log.log ("undeploying all applications.");
- File f = new File (DEPLOYMENT_DIR);
- File[] files = f.listFiles();
+ File[] files = DEPLOYMENT_DIR.listFiles();
int count = 0;
for (int i = 0, l = files.length; i<l; ++i)
{
@@ -345,170 +329,244 @@
* by the given deployment of the given deployment. <br>
* This means download the needed packages do some validation...
* <i> Validation and do some other things is not yet implemented </i>
- * @param _d the deployment (= a J2ee application or module)
+ * @param _downloadUrl the url that points to the app to install
* @throws IOException if the download fails
* @throws J2eeDeploymentException if the given package is somehow inconsistent
*/
Deployment installApplication (URL _downloadUrl) throws IOException,
J2eeDeploymentException
{
- // determine the file type by trying to access one of the possible
- // deployment descriptors...
+ // because of the URLClassLoader problem (doesnt notice when jar content
changed)
+ // we first make a local copy of the file
+ boolean directory = false;
+ URL localCopy = null;
+
+ // determine if directory or not
+ // directories are only local supported
+ if (_downloadUrl.getProtocol().equals ("file") &&
+ new File (_downloadUrl.getFile ()).isDirectory ())
+ {
+ directory = true;
+ localCopy = URLWizzard.downloadAndPackTemporary (_downloadUrl,
DEPLOYMENT_DIR.toURL (), "copy", ".zip");
+ }
+ else
+ localCopy = URLWizzard.downloadTemporary (_downloadUrl,
DEPLOYMENT_DIR.toURL (), "copy", ".zip");
+
+ // determine the file type by trying to access one of its possible descriptors
Element root = null;
+ URLClassLoader cl = new URLClassLoader (new URL[] {localCopy});
String[] files = {"META-INF/ejb-jar.xml", "META-INF/application.xml",
"WEB-INF/web.xml"};
- boolean directory = false;
+
for (int i = 0; i < files.length && root == null; ++i)
{
- // try it as if it is a jar file
try {
- root = XmlFileLoader.getDocument (new URL ("jar:" +
_downloadUrl.toString () + "!/" + files[i])).getDocumentElement ();
+ root = XmlFileLoader.getDocument (cl.getResourceAsStream
(files[i])).getDocumentElement ();
} catch (Exception _e) {}
-
- // try it, as if it is a directory
- // but this cant be handled right now
- // try {
- // root = XmlFileLoader.getDocument (new URL (_downloadUrl.toString ()
+ "/" + files[i])).getDocumentElement ();
- // directory = true;
- // } catch (Exception _e) {}
}
+ // dont need it anymore...
+ cl = null;
+ URLWizzard.deleteTree(localCopy);
+
if (root == null)
+ {
// no descriptor was found...
- throw new J2eeDeploymentException ("No valid deployment descriptor was found
within this URL: "+
- _downloadUrl.toString ()+
- "\nMake sure it points to a valid j2ee package
(ejb.jar/web.war/app.ear)!");
+ throw new J2eeDeploymentException ("No valid deployment descriptor was
found within this URL: "+
+ _downloadUrl.toString ()+
+ "\nMake sure it points to a valid j2ee package
(ejb.jar/web.war/app.ear)!");
+ }
+ // valid descriptor found
// create a Deployment
Deployment d = new Deployment ();
- URL currentDownload = null; // to give more precize info in error case which
download failed
- try {
- d.name = Deployment.getAppName (_downloadUrl);
- String localUrl = "file:"+DEPLOYMENT_DIR+"/"+d.name;
+
+ d.name = getAppName (_downloadUrl);
+ d.localUrl = new File (DEPLOYMENT_DIR, d.name).toURL ();
+ log.log ("create application " + d.name);
+
+ // do the app type dependent stuff...
+ if ("ejb-jar".equals (root.getTagName ()))
+ {
+ // its a EJB.jar... just take the package
+ installEJB (d, _downloadUrl, null);
+ }
+ else if ("web-app".equals (root.getTagName ()))
+ {
+ // its a WAR.jar... just take the package
+ if (directory)
+ throw new J2eeDeploymentException ("Currently are only packed web.war
archives supported.");
- log.log ("create application " + d.name);
+ if (!warDeployerAvailable ())
+ throw new J2eeDeploymentException ("No WEB container available!");
+ String context = getWebContext (_downloadUrl);
+ installWAR (d, _downloadUrl, context, null);
+ }
+ else if ("application".equals (root.getTagName ()))
+ {
+ // its a EAR.jar... hmmm, its a little more
+ if (directory)
+ throw new J2eeDeploymentException ("Application.ear files are only in
packed archive format supported.");
- // do the app type dependent stuff...
- if ("ejb-jar".equals (root.getTagName ()))
+ // create a MetaData object...
+ J2eeApplicationMetaData app = null;
+ try
{
- // its a EJB.jar... just take the package
- Deployment.Module m = d.newModule ();
- // localUrl: file:<download_dir> / <appName> / <appName>
- m.name = Deployment.getFileName (_downloadUrl);
- m.localUrl = new URL (localUrl+"/"+m.name);// should never throw an
URLEx
-
- log.log ("downloading module " + m.name);
- currentDownload = _downloadUrl;
- URLWizzard.download (currentDownload, m.localUrl);
- d.ejbModules.add (m);
- }
- else if ("web-app".equals (root.getTagName ()))
+ app = new J2eeApplicationMetaData (root);
+ }
+ catch (DeploymentException _de)
{
- // its a WAR.jar... just take the package
- if (!warDeployerAvailable ())
- throw new J2eeDeploymentException ("No war container available!");
-
- Deployment.Module m = d.newModule ();
- m.name = Deployment.getFileName (_downloadUrl);
- m.localUrl = new URL (localUrl+"/"+m.name);// should never throw an
URLEx
- m.webContext = Deployment.getWebContext (_downloadUrl);
-
- log.log ("downloading and inflating module " + m.name);
- currentDownload = _downloadUrl;
- URLWizzard.downloadAndInflate (currentDownload, m.localUrl);
- d.webModules.add (m);
- }
- else if ("application".equals (root.getTagName ()))
+ throw new J2eeDeploymentException ("error in parsing application.xml:
"+_de.getMessage ());
+ }
+
+ // currently we only take care for the modules
+ // no security stuff, no alternative DDs
+ // no dependency and integrity checking... !!!
+ J2eeModuleMetaData mod;
+ Iterator it = app.getModules ();
+ for (int i = 0; it.hasNext (); ++i)
{
- // its a EAR.jar... hmmm, its a little more
- // create a MetaData object...
- J2eeApplicationMetaData app;
- app = new J2eeApplicationMetaData (root);
+ // iterate the ear modules
+ mod = (J2eeModuleMetaData) it.next ();
- // currently we only take care for the modules
- // no security stuff, no alternative DDs
- // no dependency and integrity checking... !!!
- J2eeModuleMetaData mod;
- Iterator it = app.getModules ();
- while (it.hasNext ())
- {
- mod = (J2eeModuleMetaData) it.next ();
- // iterate the ear modules
- if (mod.isEjb () || mod.isWeb ())
- {
-
- // common stuff
- Deployment.Module m = d.newModule ();
- URL downloadUrl;
- try
- {
- currentDownload = new URL ("jar:" + _downloadUrl.toString () +
"!"+
- (mod.getFileName ().startsWith ("/") ? "" : "/")+
- mod.getFileName ());// chould throw an URLEx
- m.name = Deployment.getFileName (currentDownload);
- m.localUrl = new URL (localUrl + "/" + m.name);// should not
throw an URLEx
- }
- catch (MalformedURLException _mue)
- {
- throw new J2eeDeploymentException ("syntax error in module
section in application DD (module uri: " + mod.getFileName()+")");
- }
-
- // web specific
- if (mod.isWeb ())
- {
- if (!warDeployerAvailable ())
- throw new J2eeDeploymentException ("Application containes
.war file. No war container available!");
-
- m.webContext = mod.getWebContext ();
- if (m.webContext == null)
- m.webContext = Deployment.getWebContext (currentDownload);
-
- log.log ("downloading and inflating module " + m.name);
- URLWizzard.downloadAndInflate (currentDownload, m.localUrl);
- d.webModules.add (m);
- }
- // ejb specific
- else
- {
- log.log ("downloading module " + m.name);
- URLWizzard.download (currentDownload, m.localUrl);
- d.ejbModules.add (m);
- }
-
- // here the code for checking and DD replacment...
- // ...
- }
+ if (mod.isEjb ())
+ {
+ URL src = new URL ("jar:"+_downloadUrl.toString ()+ "!"+
+ (mod.getFileName ().startsWith ("/") ? "" : "/")+
+ mod.getFileName ());
+ installEJB (d, src, null);
}
+ else if (mod.isWeb ())
+ {
+ if (!warDeployerAvailable ())
+ throw new J2eeDeploymentException ("Application containes .war
file. No war container available!");
+
+ String context = mod.getWebContext ();
+ if (context == null)
+ context = mod.getFileName ().substring (Math.max (0,
mod.getFileName ().lastIndexOf ("/")));
+
+ URL src = new URL ("jar:"+_downloadUrl.toString ()+ "!"+
+ (mod.getFileName ().startsWith ("/") ? "" : "/")+
+ mod.getFileName ());
+ installWAR (d, src, context, null);
+ }
// other packages we dont care about (currently)
+ }
+ }
+ saveConfig (d);
+
+ return d;
+ }
+
+ void installEJB (Deployment _d, URL _source, URL[] _altDD) throws IOException
+ {
+ Deployment.Module m = _d.newModule ();
+ m.name = getAppName (_source);
+ log.log ("intalling ejb package: " + m.name);
+
+ // the base dir for this EJB package
+ URL destDir = URLWizzard.createTempDir (_d.localUrl, "ejb");
+
+ // download the package...
+ URL localUrl = URLWizzard.download(_source, new URL (destDir, "ejb.jar"));
+
+ // download alternative Descriptors (ejb-jar.xml, jboss.xml, ...)
+ // DOESNT WORK YET!!!
+ if (_altDD != null && _altDD.length > 0)
+ {
+ URL metaDir = new URL (destDir.getFile () + "/META-INF");
+ for (int i = 0, l = _altDD.length; i < l; ++i)
+ {
+ URLWizzard.download (_altDD[i], new URL (metaDir,"bla"));
}
- // storing the deployment
- currentDownload = null;
- FileOutputStream fout = new FileOutputStream (localUrl.substring (5,
localUrl.length ()) + File.separator + CONFIG);
- ObjectOutputStream out = new ObjectOutputStream (fout);
- out.writeObject (d);
- out.flush ();
- out.close ();
-
- return d;
- }
- catch (IOException _ioe) //happens on downloading modules
+ // this in the classpath before the real jar file to find this descriptors
first
+ m.localUrls.add (destDir);
+ }
+
+ m.localUrls.add (localUrl);
+
+ // download libraries we depend on
+ Manifest mf = new JarFile (localUrl.getFile ()).getManifest ();
+ addCommonLibs (_d, mf, _source);
+
+ // add module to the deployment
+ _d.ejbModules.add (m);
+ }
+
+
+ void installWAR (Deployment _d, URL _source, String _context, URL[] _altDD)
throws IOException
+ {
+ Deployment.Module m = _d.newModule ();
+ m.name = getAppName (_source);
+ log.log ("intalling web package: " + m.name);
+
+ // the base dir for this WAR package
+ URL destDir = URLWizzard.createTempDir (_d.localUrl, "war");
+
+ // download the package...
+ URL localUrl = URLWizzard.downloadAndInflate (_source, new URL (destDir,
"expandedWar"));
+
+ // save the contextName
+ m.webContext = _context;
+
+ // download alternative Descriptors (web.xml, ...)
+ // DOESNT WORK YET!!!
+ if (_altDD != null && _altDD.length > 0)
{
- if (currentDownload == null)
- throw new IOException ("Error in saving config file "+CONFIG +":
"+_ioe.getMessage ());
- else
- throw new IOException ("Error in downloading
"+currentDownload.toString() +
- ": "+_ioe.getMessage ());
+ URL metaDir = new URL (destDir.getFile () + "/WEB-INF");
+ for (int i = 0, l = _altDD.length; i < l; ++i)
+ {
+ URLWizzard.download (_altDD[i], new URL (metaDir,"bla"));
+ }
+ m.localUrls.add (destDir);
}
- catch (DeploymentException _de) // happens on creating
J2eeApplicationMetaData
- {
- throw new J2eeDeploymentException ("Error in scanning .ear file deploymnet
descriptor: " + _de.getMessage ());
- }
- catch (Exception _e) // when something goes really wrong (runtime exception)
- {
- _e.printStackTrace ();
- throw new J2eeDeploymentException ("FATAL ERROR! "+_e.toString ());
- }
+
+ m.localUrls.add (localUrl);
+
+ // download libraries we depend on
+ FileInputStream in = new FileInputStream (localUrl.getFile
()+File.separator+"META-INF"+File.separator+"MANIFEST.MF");
+ Manifest mf = new Manifest (in);
+ in.close ();
+ addCommonLibs (_d, mf, _source);
+
+ // add module to the deployment
+ _d.webModules.add (m);
}
+ /** downloads all Class-Path: files of this manifest and adds the local urls
+ * to the deployments commonUrls.
+ * @param _d the deployment
+ * @param _mf the manifest
+ * @param _base the base url to which the manifest entries are relative
+ * @throws IOExcepiton in case of error while downloading
+ */
+ private void addCommonLibs (Deployment _d, Manifest _mf, URL _base) throws
IOException
+ {
+ if (_d.commonLibs == null)
+ _d.commonLibs = URLWizzard.createTempDir (_d.localUrl, "common");
+
+ String cp = _mf.getMainAttributes ().getValue(Attributes.Name.CLASS_PATH);
+
+ if (cp != null)
+ {
+ StringTokenizer cpTokens = new StringTokenizer (cp," ");
+ while (cpTokens.hasMoreTokens ())
+ {
+ String classPath = cpTokens.nextToken();
+ try
+ {
+ URL src = new URL(_base, classPath);
+ URL dest = new URL (_d.commonLibs, getAppName (src));
+ _d.commonUrls.add (URLWizzard.download (src, dest));
+ log.error("added " + classPath + " to common classpath");
+ }
+ catch (Exception e)
+ {
+ log.error("Could not add " + classPath + " to common classpath");
+ }
+ }
+ }
+ }
+
/** Deletes the file tree of the specified application. <br>
* @param _name the directory (DEPLOYMENT_DIR/<_name> to remove recursivly
* @throws IOException if something goes wrong
@@ -519,7 +577,7 @@
URL url = null;
try
{
- url = new URL ("file:"+DEPLOYMENT_DIR+"/"+_name);
+ url = new URL (DEPLOYMENT_DIR.toURL (), _name);
URLWizzard.deleteTree (url);
log.log ("file tree "+url.toString ()+" deleted.");
} catch (MalformedURLException _mfe) { // should never happen
@@ -536,6 +594,9 @@
*/
private void startApplication (Deployment _d) throws J2eeDeploymentException
{
+ // save the old classloader
+ ClassLoader oldCl = Thread.currentThread().getContextClassLoader ();
+
// set the context classloader for this application
createContextClassLoader(_d);
@@ -549,10 +610,12 @@
while (it.hasNext ())
{
m = (Deployment.Module)it.next ();
+
log.log ("starting module " + m.name);
+
// Call the ContainerFactory that is loaded in the JMX server
server.invoke(jarDeployer, "deploy",
- new Object[] { m.localUrl.toString () }, new String[] {
"java.lang.String" });
+ new Object[] { m.localUrls.firstElement().toString () }, new
String[] { "java.lang.String" });
}
@@ -561,10 +624,12 @@
while (it.hasNext ())
{
m = (Deployment.Module)it.next ();
+
log.log ("starting module " + m.name);
+
// Call the TomcatDeployer that is loaded in the JMX server
server.invoke(warDeployer, "deploy",
- new Object[] { m.webContext, m.localUrl.toString ()}, new String[] {
"java.lang.String", "java.lang.String" });
+ new Object[] { m.webContext, m.localUrls.firstElement().toString
()}, new String[] { "java.lang.String", "java.lang.String" });
}
}
catch (MBeanException _mbe) {
@@ -573,7 +638,9 @@
} catch (JMException _jme){
log.error ("starting failed!");
throw new J2eeDeploymentException ("fatal error while interacting with
deployer MBeans... " + _jme.getMessage ());
- }
+ } finally {
+ Thread.currentThread().setContextClassLoader (oldCl);
+ }
}
/** Stops a running deployment. <br>
@@ -584,6 +651,9 @@
*/
private void stopApplication (Deployment _d) throws J2eeDeploymentException
{
+ // save the old classloader, tomcat replaces my classloader somehow?!
+ ClassLoader oldCl = Thread.currentThread().getContextClassLoader ();
+
StringBuffer error = new StringBuffer ();
ObjectName[] container = new ObjectName[] {jarDeployer, warDeployer};
Iterator modules[] = new Iterator[] {_d.ejbModules.iterator
(),_d.webModules.iterator ()};
@@ -604,13 +674,13 @@
{
// Call the ContainerFactory/EmbededTomcat that is loaded in the JMX
server
Object result = server.invoke(container[i], "isDeployed",
- new Object[] { m.localUrl.toString () }, new String[] {
"java.lang.String" });
+ new Object[] { m.localUrls.firstElement ().toString () }, new
String[] { "java.lang.String" });
if (((Boolean)result).booleanValue ())
{
log.log ("stopping module " + m.name);
server.invoke(container[i], "undeploy",
- new Object[] { m.localUrl.toString () }, new String[] {
"java.lang.String" });
+ new Object[] { m.localUrls.firstElement ().toString () }, new
String[] { "java.lang.String" });
}
else
log.log ("module " + m.name+" is not running");
@@ -633,6 +703,9 @@
if (!error.toString ().equals (""))
// there was at least one error...
throw new J2eeDeploymentException ("error(s) on stopping application
"+_d.name+":\n"+error.toString ());
+
+ // restore the classloader
+ Thread.currentThread().setContextClassLoader (oldCl);
}
/** Checks the Deplyment if it is correctly deployed.
@@ -668,8 +741,8 @@
log.log ("checking module " + m.name);
// Call the ContainerFactory/EmbededTomcat that is loaded in the JMX
server
o = server.invoke(container[i], "isDeployed",
- new Object[] { m.localUrl.toString () }, new String[] {
"java.lang.String" });
-
+ new Object[] { m.localUrls.firstElement ().toString () }, new
String[] { "java.lang.String" });
+
}
catch (MBeanException _mbe)
{
@@ -679,7 +752,7 @@
{
log.error ("fatal error while checking module " + m.name + ": " +
_jme.getMessage ());
}
-
+
if (o == null) // had an exception
++others;
else if (count++ == 0) // first module -> set state
@@ -719,41 +792,71 @@
return d;
}
- /** tests if the web container deployer is available
+ /** Serializes Deployment as CONFIG file. <br>
+ * saves DEPLOYMENT_DIR / _d.name / CONFIG
+ * @param _app the name of the app
+ * @throws IOException if an error occures
*/
+ private void saveConfig (Deployment _d) throws IOException
+ {
+ ObjectOutputStream out = new ObjectOutputStream (
+ new FileOutputStream (DEPLOYMENT_DIR + File.separator + _d.name +
File.separator + CONFIG));
+ out.writeObject (_d);
+ out.flush ();
+ out.close ();
+ }
+
+ /** tests if the web container deployer is available */
private boolean warDeployerAvailable ()
{
return server.isRegistered (warDeployer);
}
+ /** returns the filename this url points to */
+ public String getAppName (URL _url)
+ {
+ String s = _url.toString ();
+
+ if (s.endsWith ("/"))
+ s = s.substring (0, s.length() - 1);
+
+ s = s.substring (s.lastIndexOf ("/") + 1);
+ return s;
+ }
+
+ /** composes a webContext name of the file this url points to */
+ public String getWebContext (URL _downloadUrl)
+ {
+ String s = getAppName (_downloadUrl);
+
+ // truncate the file extension
+ int p = s.lastIndexOf (".");
+ if (p != -1)
+ s = s.substring (0, p);
+
+ return "/" + s.replace ('.', '/');
+ }
+
+
/**
* creates an application class loader for this deployment
* this class loader will be shared between jboss and tomcat via the
contextclassloader
*/
private void createContextClassLoader(Deployment deployment) {
- // find all the urls to add
- ArrayList urls = new ArrayList();
+ // get urls we want all classloaders of this application to share
+ URL[] urls = new URL[deployment.commonUrls.size ()];
+ for (int i = 0, l = deployment.commonUrls.size (); i < l; ++i)
+ urls[i] = (URL)deployment.commonUrls.elementAt (i);
- // ejb applications
- Iterator iterator = deployment.ejbModules.iterator();
- while (iterator.hasNext()) {
- // add the local url to the classloader
- urls.add(((Deployment.Module)iterator.next()).localUrl);
- }
-
- // TODO? web applications
- // add WEB-INF/classes and WEB-INF/lib/* from webModules.localUrl
-
- // actually create the class loader.
- // Keep the current context class loader as a parent (jboss and tomcat
classes are in it)
- URL[] urlArray = (URL[])urls.toArray(new URL[urls.size()]);
+ // create classloader
ClassLoader parent = Thread.currentThread().getContextClassLoader();
-
- URLClassLoader appCl = new URLClassLoader(urlArray, parent);
+ URLClassLoader appCl = new URLClassLoader(urls, parent);
// set it as the context class loader for the deployment thread
Thread.currentThread().setContextClassLoader(appCl);
}
+
+
}
1.2 +177 -84 jboss/src/main/org/jboss/deployment/URLWizzard.java
Index: URLWizzard.java
===================================================================
RCS file: /products/cvs/ejboss/jboss/src/main/org/jboss/deployment/URLWizzard.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- URLWizzard.java 2000/10/03 00:08:16 1.1
+++ URLWizzard.java 2000/11/02 22:43:53 1.2
@@ -1,9 +1,9 @@
/*
- * jBoss, the OpenSource EJB server
- *
- * Distributable under GPL license.
- * See terms of license at gnu.org.
- */
+* jBoss, the OpenSource EJB server
+*
+* Distributable under GPL license.
+* See terms of license at gnu.org.
+*/
package org.jboss.deployment;
import java.net.URL;
@@ -11,6 +11,7 @@
import java.io.File;
import java.io.FileOutputStream;
+import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
@@ -22,107 +23,173 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+
/**
- * Encapsulates URL bases copy and jar file operations.
- * Very scratchy! Any improvements are welcome!
- *
- * @author Daniel Schulze <[EMAIL PROTECTED]>
- * @version $Revision: 1.1 $
- */
+* Encapsulates URL bases copy and jar file operations.
+* Very scratchy! Any improvements are welcome!
+*
+* @author Daniel Schulze <[EMAIL PROTECTED]>
+* @version $Revision: 1.2 $
+*/
public class URLWizzard
{
-
+
// Static --------------------------------------------------------
public static void main (String[] _args) throws Exception
{
- downloadAndInflate (new URL (_args[0]), new URL (_args[1]));
+ downloadAndPack (new URL (_args[0]), new URL (_args[1]));
}
/** copies the source to the destination url. As destination
- are currently only file:/... urls supported */
- public static void download (URL _src, URL _dest) throws IOException
+ are currently only file:/... urls supported */
+ public static URL download (URL _src, URL _dest) throws IOException
{
+ if (!_dest.getProtocol ().equals ("file"))
+ throw new IOException ("only file: protocoll is allowed as destination!");
+
InputStream in;
OutputStream out;
-/*
- URLConnection urlCon = _src.openConnection ();
- urlCon.setDoInput (true);
- in = urlCon.getInputStream ();
-*/
+
+ String s = _dest.getFile ();
+ File dir = new File (s.substring (0, s.lastIndexOf("/")));
+ if (!dir.exists ())
+ dir.mkdirs ();
+
in = _src.openStream ();
+ out = new FileOutputStream (s);
+
+ write (in, out);
+
+ out.close ();
+ in.close ();
+
+ return _dest;
+ }
+
+ /** copies the source to the destination. The destination is composed from the
+ _destDirectory, _prefix and _suffix */
+ public static URL downloadTemporary (URL _src, URL _destDirectory, String
_prefix, String _suffix) throws IOException
+ {
+ File f = new File (_destDirectory.getFile ());
+ if (!f.exists ())
+ f.mkdirs ();
+
+ f = File.createTempFile (_prefix, _suffix, f);
+
+ URL result = f.toURL ();
+
+ download (_src, result);
+
+ return result;
+ }
+
+ /** packs the source directory the _src url points to to a jar archiv at
+ the _dest position */
+ public static void downloadAndPack (URL _src, URL _dest) throws IOException
+ {
+ if (!_dest.getProtocol ().equals ("file"))
+ throw new IOException ("only file: protocoll is allowed as destination!");
+ if (!_src.getProtocol ().equals ("file"))
+ throw new IOException ("only file: protocoll is allowed as source!");
- boolean jar = false;
- String jarPath = "";
- String filePath;
- String fileName;
- String s = _dest.toString ();
+ InputStream in;
+ OutputStream out;
- if (_dest.getProtocol ().equals ("jar"))
- {
- // get the path in the jar
- int pos = s.indexOf ("!");
- jarPath = s.substring (pos + 1);
- s = s.substring (0, pos);
- }
+ String s = _dest.getFile ();
+ File dir = new File (s.substring (0, s.lastIndexOf("/")));
+ if (!dir.exists ())
+ dir.mkdirs ();
- // get the FileName
- int pos = s.lastIndexOf ("/");
- fileName = s.substring (pos + 1);
- s = s.substring (0, pos);
-
- // get the FilePath
- pos = Math.max (0, s.lastIndexOf (":"));
- filePath = s.substring (pos + 1);
- filePath = filePath.replace ('/', File.separatorChar);
+ JarOutputStream jout = new JarOutputStream (new FileOutputStream
(_dest.getFile()));
- if (jar)
- {
- // open jarFile
- throw new IOException ("write into a jar file NOT yet implemented!");
- }
- else
+ // put all into the jar...
+ add (jout, new File (_src.getFile()), "");
+ jout.close ();
+ }
+
+ /** used by downloadAndPack*. */
+ private static void add (JarOutputStream _jout, File _dir, String _prefix)
throws IOException
+ {
+ File[] content = _dir.listFiles ();
+ for (int i = 0, l = content.length; i < l; ++i)
{
- File dir = new File (filePath);
- if (!dir.exists ())
- dir.mkdirs ();
-
- out = new FileOutputStream (filePath + File.separator + fileName);
+ if (content[i].isDirectory ())
+ {
+ add (_jout, content[i], _prefix+(_prefix.equals ("") ? "" :
"/")+content[i].getName ());
+ }
+ else
+ {
+ _jout.putNextEntry (new ZipEntry(_prefix + "/" + content[i].getName
()));
+ FileInputStream in = new FileInputStream (content[i]);
+ write (in, _jout);
+ in.close ();
+ }
}
+ }
+
+
+ /** packs the source directory the _src url points to to a jar archiv at
+ the position composed from _destDir, _prefix and _suffix */
+ public static URL downloadAndPackTemporary (URL _src, URL _destDir, String
_prefix, String _suffix) throws IOException
+ {
+ if (!_destDir.getProtocol ().equals ("file"))
+ throw new IOException ("only file: protocoll is allowed as destination!");
+ if (!_src.getProtocol ().equals ("file"))
+ throw new IOException ("only file: protocoll is allowed as source!");
- write (in, out);
-
- out.close ();
- in.close ();
+ InputStream in;
+ OutputStream out;
+
+ File f = new File (_destDir.getFile ());
+ if (!f.exists ())
+ f.mkdirs ();
+
+ f = File.createTempFile (_prefix, _suffix, f);
+ JarOutputStream jout = new JarOutputStream (new FileOutputStream (f));
+
+ // put all into the jar...
+ add (jout, new File (_src.getFile()), "");
+ jout.close ();
+
+ return f.toURL ();
}
-
+
+
+
+
+
+
/** inflates the given zip file into the given directory */
- public static void downloadAndInflate (URL _src, URL _dest) throws IOException
+ public static URL downloadAndInflate (URL _src, URL _dest) throws IOException
{
InputStream in;
OutputStream out;
-
+
in = _src.openStream ();
-
+
boolean jar = false;
String jarPath = "";
String filePath;
String fileName;
String s = _dest.toString ();
-
+
if (!_dest.getProtocol ().equals ("file"))
- throw new IOException ("only file:/ is as destination allowed!");
-
- File base = new File (_dest.getFile ());
- if (base.exists ())
- deleteTree (_dest);
-
- base.mkdirs ();
-
+ throw new IOException ("only file: protocoll is allowed as destination!");
+
+ File base = new File (_dest.getFile ());
+ if (base.exists ())
+ deleteTree (_dest);
+
+ base.mkdirs ();
+
ZipInputStream zin = new ZipInputStream (in);
ZipEntry entry;
while ((entry = zin.getNextEntry ()) != null)
@@ -146,48 +213,74 @@
}
}
zin.close ();
+
+ return _dest;
}
+ /** creates a directory like the File.createTempFile method */
+ public static URL createTempDir (URL _baseDir, String _prefix) throws IOException
+ {
+ do
+ {
+ File f = new File (_baseDir.getFile (), _prefix + getId ());
+ if (!f.exists ())
+ {
+ f.mkdirs ();
+ return f.toURL ();
+ }
+ }
+ while (true); // the endless loop should never cause trouble
+ }
+ private static int id = 1000;
+
+ /** used by createTempDir */
+ private static String getId ()
+ {
+ return String.valueOf (++id);
+ }
+
+
/** deletes the given file:/... url recursively */
public static void deleteTree (URL _dir) throws IOException
{
- if (!_dir.getProtocol ().equals ("file"))
+ if (!_dir.getProtocol ().equals ("file"))
throw new IOException ("Protocol not supported");
-
+
File f = new File (_dir.getFile ());
if (!delete (f))
throw new IOException ("deleting " + _dir.toString () + "recursively
failed!");
}
-
+
/** deletes a file recursively */
private static boolean delete (File _f) throws IOException
{
- if (_f.exists ())
- {
- if (_f.isDirectory ())
- {
- File[] files = _f.listFiles ();
- for (int i = 0, l = files.length; i < l; ++i)
- if (!delete (files[i]))
- return false;
+ if (_f.exists ())
+ {
+ if (_f.isDirectory ())
+ {
+ File[] files = _f.listFiles ();
+ for (int i = 0, l = files.length; i < l; ++i)
+ if (!delete (files[i]))
+ return false;
}
return _f.delete ();
}
return true;
}
-
-
+
+
/** writes the content of the InputStream into the OutputStream */
private static void write (InputStream _in, OutputStream _out) throws IOException
{
int b;
while ((b = _in.read ()) != -1)
_out.write ((byte)b);
-
+
_out.flush ();
}
-
+
+
}