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 ();
      }
  -
  +   
  +   
   
   }
  
  
  

Reply via email to