FileDocCategorySizeDatePackage
EJB3StandaloneDeployer.javaAPI DocJBoss 4.2.117361Fri Jul 13 20:53:50 BST 2007org.jboss.ejb3.embedded

EJB3StandaloneDeployer.java

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.ejb3.embedded;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.zip.ZipFile;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;

import org.jboss.dependency.spi.ControllerContext;
import org.jboss.ejb3.DeploymentUnit;
import org.jboss.ejb3.interceptor.InterceptorInfoRepository;
import org.jboss.kernel.Kernel;
import org.jboss.logging.Logger;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VirtualFile;
import org.jboss.virtual.VirtualFileFilter;
import org.jboss.virtual.VisitorAttributes;
import org.jboss.virtual.plugins.context.jar.JarUtils;
import org.jboss.virtual.plugins.vfs.helpers.FilterVirtualFileVisitor;
import org.jboss.virtual.plugins.vfs.helpers.SuffixesExcludeFilter;

/**
 * When initialized properly, this class will search for annotated classes and archives in your
 * classpath and try to create EJB containers and EntityManagers automatically.
 * <p/>
 * All classes and jars must already be in your classpath for this deployer to work.
 *
 * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
 * @version $Revision: 60233 $
 */
public class EJB3StandaloneDeployer
{
   private static class DeployerUnit implements DeploymentUnit
   {
      private URL url;
      private ClassLoader resourceLoader;
      private ClassLoader loader;
      private Map defaultProps;
      private Hashtable jndiProperties;
      private InterceptorInfoRepository interceptorInfoRepository = new InterceptorInfoRepository();
      private VirtualFile vfsRoot;

      public DeployerUnit(ClassLoader loader, URL url, Map defaultProps, Hashtable jndiProperties)
      {
         this.loader = loader;
         this.url = url;
         URL[] urls = {url};
         URL[] empty = {};
         URLClassLoader parent = new URLClassLoader(empty)
         {
            @Override
            public URL getResource(String name)
            {
               return null;
            }
         };
         resourceLoader = new URLClassLoader(urls, parent);
         this.defaultProps = defaultProps;
         this.jndiProperties = jndiProperties;
         try
         {
            VFS vfs = VFS.getVFS(url);
            vfsRoot = vfs.getRoot();
         }
         catch (IOException e)
         {
            throw new RuntimeException();
         }
      }

      public VirtualFile getRootFile()
      {
         return vfsRoot;
      }
      
      public URL getRelativeURL(String jar)
      {
         URL url = null;
         try
         {
            url = new URL(jar);
         }
         catch (MalformedURLException e)
         {
            try
            {
               if (jar.startsWith(".."))
               {
                  if (getUrl() == null)
                     throw new RuntimeException("relative <jar-file> not allowed when standalone deployment unit is used");
                  String base = getUrl().toString();
                  jar = jar.replaceAll("\\.\\./", "+");
                  int idx = jar.lastIndexOf('+');
                  jar = jar.substring(idx + 1);
                  for (int i = 0; i < idx + 1; i++)
                  {
                     int slash = base.lastIndexOf('/');
                     base = base.substring(0, slash + 1);
                  }
                  url = new URL(base + jar.substring(idx));
               }
               else
               {
                  File fp = new File(jar);
                  url = fp.toURL();
               }
            }
            catch (MalformedURLException e1)
            {
               throw new RuntimeException("Unable to find relative url: " + jar, e1);
            }
         }
         return url;
      }
      

      public List<VirtualFile> getResources(VirtualFileFilter filter)
      {
         VisitorAttributes va = new VisitorAttributes();
         va.setLeavesOnly(true);
         SuffixesExcludeFilter noJars = new SuffixesExcludeFilter(JarUtils.getSuffixes());
         va.setRecurseFilter(noJars);
         FilterVirtualFileVisitor visitor = new FilterVirtualFileVisitor(filter, va);
         try
         {
            vfsRoot.visit(visitor);
         }
         catch (IOException e)
         {
            throw new RuntimeException(e);
         }
         return visitor.getMatched();

      }

      public Hashtable getJndiProperties()
      {
         return jndiProperties;
      }

      public URL getPersistenceXml()
      {
         return getResourceLoader().getResource("META-INF/persistence.xml");
      }

      public URL getEjbJarXml()
      {
         return getResourceLoader().getResource("META-INF/ejb-jar.xml");
      }

      public URL getJbossXml()
      {
         return getResourceLoader().getResource("META-INF/jboss.xml");
      }

      public List<Class> getClasses()
      {
         return null;
      }

      public ClassLoader getClassLoader()
      {
         return loader;
      }

      public ClassLoader getResourceLoader()
      {
         return resourceLoader;
      }

      public String getShortName()
      {
         String url = getUrl().toString();
         if (url.endsWith("/")) url = url.substring(0, url.length() - 1);

         int dotIdx = url.lastIndexOf('.');
         int slashIdx = url.lastIndexOf('/');
         String name = null;
         if (slashIdx > dotIdx)
         {
            name = url.substring(url.lastIndexOf('/') + 1);
         }
         else
         {
            name = url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.'));
         }
         return name;
      }

      public URL getUrl()
      {
         return url;
      }

      public String getDefaultEntityManagerName()
      {
         return getShortName();
      }

      public Map getDefaultPersistenceProperties()
      {
         return defaultProps;
      }

      public InterceptorInfoRepository getInterceptorInfoRepository()
      {
         return interceptorInfoRepository;
      }

      public VirtualFile getMetaDataFile(String path)
      {
         try
         {
            return vfsRoot.findChild(path);
         }
         catch (IOException e)
         {
            log.debug("Cannot get meta data file: " + path);
            return null;
         }
      }
   }

   protected static final Logger log = Logger.getLogger(EJB3StandaloneDeployer.class);

   protected Set<URL> archives = new HashSet<URL>();
   protected Set<URL> deployDirs = new HashSet<URL>();
   protected Set<String> archivesByResource = new HashSet<String>();
   protected Set<String> deployDirsByResource = new HashSet<String>();
   protected ClassLoader classLoader;
   private Map defaultPersistenceProperties;
   private Hashtable jndiProperties;

   private List<EJB3StandaloneDeployment> deployments = new ArrayList<EJB3StandaloneDeployment>();

   private Kernel kernel;
   private MBeanServer mbeanServer;


   public EJB3StandaloneDeployer()
   {
      classLoader = Thread.currentThread().getContextClassLoader();
   }

   public Kernel getKernel()
   {
      return kernel;
   }

   public void setKernel(Kernel kernel)
   {
      this.kernel = kernel;
   }

   /**
    * This is used by deployer for @Service beans that have @Management interfaces
    *
    * @return
    */
   public MBeanServer getMbeanServer()
   {
      return mbeanServer;
   }

   public void setMbeanServer(MBeanServer mbeanServer)
   {
      this.mbeanServer = mbeanServer;
   }

   /**
    * A set of URLs of jar archives to search for annotated EJB classes
    *
    * @return this will not return null.
    */
   public Set<URL> getArchives()
   {
      return archives;
   }

   public void setArchives(Set archives)
   {
      new Exception().printStackTrace();
      this.archives = archives;
   }


   /**
    * Set of directories where there are jar files and directories
    * The deployer will search through all archives and directories for
    * annotated classes
    *
    * @return this will not return null.
    */
   public Set<URL> getDeployDirs()
   {
      return deployDirs;
   }

   public void setDeployDirs(Set deployDirs)
   {
      this.deployDirs = deployDirs;
   }

   /**
    * All strings in this set will be used with ClassLoader.getResources()
    * All URLs returned will be used to search for annotated classes.
    *
    * @return
    */
   public Set<String> getArchivesByResource()
   {
      return archivesByResource;
   }

   public void setArchivesByResource(Set archivesByResource)
   {
      this.archivesByResource = archivesByResource;
   }

   /**
    * All strings in this set will be used with ClassLoader.getResources().
    * All URLs returned will be create a set of deploy directories that will
    * be used to find archives and directories that will be searched for annotated classes
    *
    * @return
    */
   public Set<String> getDeployDirsByResource()
   {
      return deployDirsByResource;
   }

   public void setDeployDirsByResource(Set deployDirsByResource)
   {
      this.deployDirsByResource = deployDirsByResource;
   }

   public ClassLoader getClassLoader()
   {
      return classLoader;
   }


   /**
    * You can set the classloader that will be used
    *
    * @param classLoader
    */
   public void setClassLoader(ClassLoader classLoader)
   {
      this.classLoader = classLoader;
   }

   public Map getDefaultPersistenceProperties()
   {
      return defaultPersistenceProperties;
   }


   /**
    * If you do not specifiy the default persistence properties, the resource
    * "default.persistence.properties" will be search for in your classpath
    *
    * @param defaultPersistenceProperties
    */
   public void setDefaultPersistenceProperties(Map defaultPersistenceProperties)
   {
      this.defaultPersistenceProperties = defaultPersistenceProperties;
   }

   public Hashtable getJndiProperties()
   {
      return jndiProperties;
   }

   public void setJndiProperties(Hashtable jndiProperties)
   {
      this.jndiProperties = jndiProperties;
   }

   /**
    * Returns a list of deployments found in this
    *
    * @return
    */
   public List<EJB3StandaloneDeployment> getDeployments()
   {
      return deployments;
   }

   public void setDeployments(List<EJB3StandaloneDeployment> deployments)
   {
      this.deployments = deployments;
   }

   public static URL getContainingUrlFromResource(URL url, String resource) throws Exception
   {
      if (url.getProtocol().equals("jar"))
      {
         URL jarURL = url;
         URLConnection urlConn = jarURL.openConnection();
         JarURLConnection jarConn = (JarURLConnection) urlConn;
         // Extract the archive to dest/jarName-contents/archive
         String parentArchiveName = jarConn.getJarFile().getName();
         File fp = new File(parentArchiveName);
         return fp.toURL();
      }

      // its a file
      String base = url.toString();
      int idx = base.lastIndexOf(resource);
      base = base.substring(0, idx);
      return new URL(base);
   }

   public static URL getDeployDirFromResource(URL url, String resource) throws Exception
   {
      if (url.getProtocol().equals("jar"))
      {
         URL jarURL = url;
         URLConnection urlConn = jarURL.openConnection();
         JarURLConnection jarConn = (JarURLConnection) urlConn;
         // Extract the archive to dest/jarName-contents/archive
         String parentArchiveName = jarConn.getJarFile().getName();
         File fp = new File(parentArchiveName);
         return fp.getParentFile().toURL();
      }

      // its a file
      String base = url.toString();
      int idx = base.lastIndexOf(resource);
      base = base.substring(0, idx);
      File fp = new File(base);
      return fp.getParentFile().toURL();
   }

   public void create() throws Exception
   {
      try
      {
         for (String resource : deployDirsByResource)
         {
            Enumeration<URL> urls = classLoader.getResources(resource);
            while (urls.hasMoreElements())
            {
               URL url = urls.nextElement();
               URL deployUrl = getDeployDirFromResource(url, resource);
               deployDirs.add(deployUrl);
            }
         }

         for (URL url : deployDirs)
         {
            File dir = new File(url.toURI());
            for (File fp : dir.listFiles())
            {
               if (fp.isDirectory())
               {
                  archives.add(fp.toURL());
                  continue;
               }
               try
               {
                  ZipFile zip = new ZipFile(fp);
                  zip.entries();
                  zip.close();
                  archives.add(fp.toURL());
               }
               catch (IOException e)
               {
               }
            }
         }

         for (String resource : archivesByResource)
         {
            Enumeration<URL> urls = classLoader.getResources(resource);
            while (urls.hasMoreElements())
            {
               URL url = urls.nextElement();
               URL archiveUrl = getContainingUrlFromResource(url, resource);
               archives.add(archiveUrl);
            }
         }

         if (defaultPersistenceProperties == null)
         {
            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("default.persistence.properties");
            if (is == null) throw new RuntimeException("cannot find default.persistence.properties");
            Properties defaults = new Properties();
            defaults.load(is);
            defaultPersistenceProperties = defaults;
         }

         for (URL archive : archives)
         {
            DeployerUnit du = new DeployerUnit(classLoader, archive, defaultPersistenceProperties, jndiProperties);
            EJB3StandaloneDeployment deployment = new EJB3StandaloneDeployment(du, kernel, mbeanServer);
            deployments.add(deployment);
            deployment.create();
         }
      }
      catch (Exception e)
      {
         e.printStackTrace();
         throw e;
      }
   }

   private void lookup(String name)
   {
      System.out.println("lookup " + name);
      try {
         InitialContext jndiContext = new InitialContext();
         NamingEnumeration names = jndiContext.list(name);
         if (names != null){
            while (names.hasMore()){
               System.out.println("  " + names.next());
            }
         }
      } catch (Exception e){
      }
   }

   public void start() throws Exception
   {
      try
      {
         loadMbeanServer();

         for (EJB3StandaloneDeployment deployment : deployments)
         {
            if (deployment.getMbeanServer() == null)
            {
               deployment.setMbeanServer(mbeanServer);
            }

            deployment.start();
            lookup("");
         }
      }
      catch (Exception e)
      {
         e.printStackTrace();
         throw e;
      }
   }

   private void loadMbeanServer()
   {
      if (mbeanServer == null)
      {
         ControllerContext context = kernel.getController().getInstalledContext("MBeanServer");

         if (context != null)
            mbeanServer = (MBeanServer) context.getTarget();
         else
         {
            ArrayList servers = MBeanServerFactory.findMBeanServer(null);
            if (servers.size() == 0)
               mbeanServer = MBeanServerFactory.createMBeanServer();
            else
               mbeanServer = (MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0);
         }
      }
   }

   public void stop() throws Exception
   {
      for (EJB3StandaloneDeployment deployment : deployments)
      {
         deployment.stop();
      }
   }

   public void destroy() throws Exception
   {
      for (EJB3StandaloneDeployment deployment : deployments)
      {
         deployment.destroy();
      }
   }
}