[jboss-cvs] JBossAS SVN: r92066 - in projects/jboss-jca/trunk: sjc/src/main/java/org/jboss/jca/sjc and 1 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Aug 6 10:44:40 EDT 2009


Author: jesper.pedersen
Date: 2009-08-06 10:44:40 -0400 (Thu, 06 Aug 2009)
New Revision: 92066

Modified:
   projects/jboss-jca/trunk/doc/developerguide/en/modules/standalone.xml
   projects/jboss-jca/trunk/sjc/src/main/java/org/jboss/jca/sjc/Main.java
   projects/jboss-jca/trunk/sjc/src/main/resources/boot.xml
   projects/jboss-jca/trunk/sjc/src/main/resources/boot.xsd
Log:
[JBJCA-143] SJC: Support parallel deployments

Modified: projects/jboss-jca/trunk/doc/developerguide/en/modules/standalone.xml
===================================================================
--- projects/jboss-jca/trunk/doc/developerguide/en/modules/standalone.xml	2009-08-06 14:33:02 UTC (rev 92065)
+++ projects/jboss-jca/trunk/doc/developerguide/en/modules/standalone.xml	2009-08-06 14:44:40 UTC (rev 92066)
@@ -67,7 +67,9 @@
       <programlisting>
 $JBOSS_JCA_HOME/config/boot.xml
       </programlisting>
-      <para>file, where all the beans are initialized in the order they appear.</para>
+      <para>file, where all the beans are initialized in the order they appear when
+        the single threaded kernel is used. Otherwise the dependency resolution based
+        solution is used (&lt;depends&gt;).</para>
 
       <para>The layout of boot.xml is defined in</para>
       <programlisting>
@@ -87,7 +89,7 @@
         </listitem>
         <listitem>
           <code>&lt;inject&gt;</code>
-          <para>injects a bean or a property from a bean.</para>
+          <para>injects a bean or a property from a bean (defines an implicit dependency on the bean).</para>
         </listitem>
         <listitem>
           <code>&lt;constructor&gt;</code>
@@ -97,6 +99,10 @@
           <code>&lt;parameter&gt;</code>
           <para>defines a parameter value for a constructor.</para>
         </listitem>
+        <listitem>
+          <code>&lt;depends&gt;</code>
+          <para>defines an explicit dependency to another bean.</para>
+        </listitem>
       </itemizedlist>
 
       <para>In order to define locations relative to the install root of the JBoss JCA
@@ -119,11 +125,12 @@
    &lt;property name="transactionTimeout"&gt;300&lt;/property&gt;
    &lt;property name="objectStoreDir"&gt;${jboss.jca.home}/tmp/tx-object-store&lt;/property&gt;
    &lt;property name="mbeanServer"&gt;&lt;inject bean="JMX" property="mbeanServer"/&gt;&lt;/property&gt;
-   &lt;property name="transactionStatusManagerInetAddress"&gt;localhost&lt;/property&gt;
+   &lt;property name="transactionStatusManagerInetAddress"&gt;${jboss.jca.host:localhost}&lt;/property&gt;
    &lt;property name="transactionStatusManagerPort"&gt;4713&lt;/property&gt;
-   &lt;property name="recoveryInetAddress"&gt;localhost&lt;/property&gt;
+   &lt;property name="recoveryInetAddress"&gt;${jboss.jca.host:localhost}&lt;/property&gt;
    &lt;property name="recoveryPort"&gt;4712&lt;/property&gt;
    &lt;property name="socketProcessIdPort"&gt;0&lt;/property&gt;    
+   &lt;depends&gt;NamingServer&lt;/depends&gt;
  &lt;/bean&gt;
       </programlisting>
 
@@ -137,7 +144,7 @@
       <itemizedlist>
         <listitem>
           <code>public void create()</code>
-          <para>Called after a bean has been constructed using its default constructor.</para>
+          <para>Called after a bean has been constructed.</para>
         </listitem>
         <listitem>
           <code>public void start()</code>
@@ -172,6 +179,44 @@
       </itemizedlist>
     </section>
 
+    <section id="jcasjc_paralleldeployment">
+      <title>Parallel deployment and dependency resolution</title>
+
+      <para>JBoss JCA/SJC features a mode where multiple threads are used during 
+        the booting sequence. This mode is enabled by using the</para>
+
+      <programlisting>
+./run.sh -mt
+      </programlisting>
+
+      <para>startup parameter.</para>
+
+      <para>When multiple threads are used in the kernel a dependency mechanism between beans is
+        needed. The kernel keeps track of each bean deployment and assigns a status</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><code>NOT_STARTED</code></para>
+          <para>The bean hasn't started.</para>
+        </listitem>
+        <listitem>
+          <para><code>STARTING</code></para>
+          <para>The bean is starting.</para>
+        </listitem>
+        <listitem>
+          <para><code>STARTED</code></para>
+          <para>The bean has fully started.</para>
+        </listitem>
+        <listitem>
+          <para><code>STOPPING</code></para>
+          <para>The bean is stopping.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Caveats: The kernel currently doesn't detect cyclic dependencies between deployment units.</para>
+
+    </section>
+
     <section id="jcasjc_classloading">
       <title>Classloading</title>
 
@@ -202,7 +247,7 @@
       <para>JBoss JCA/SJC features a very simple deployers mechanism.</para>
 
       <para>Each deployer is defined as a bean in the boot.xml file and they
-        must implemenet the</para>
+        must implement the</para>
       <programlisting>
 org.jboss.jca.sjc.deployers.Deployer
       </programlisting>
@@ -215,9 +260,9 @@
  * @param f The file
  * @param parent The parent classloader
  * @return The deployment; or null if no deployment was made
- * @exception Exception Thrown if an error occurs
+ * @exception DeployException Thrown if an error occurs
  */
-public Deployment deploy(File f, ClassLoader parent) throws Exception;
+public Deployment deploy(File f, ClassLoader parent) throws DeployException;
       </programlisting>
       <para>method which is invoked once with each of the files in the
         $JBOSS_JCA_HOME/deploy/ directory.</para>

Modified: projects/jboss-jca/trunk/sjc/src/main/java/org/jboss/jca/sjc/Main.java
===================================================================
--- projects/jboss-jca/trunk/sjc/src/main/java/org/jboss/jca/sjc/Main.java	2009-08-06 14:33:02 UTC (rev 92065)
+++ projects/jboss-jca/trunk/sjc/src/main/java/org/jboss/jca/sjc/Main.java	2009-08-06 14:44:40 UTC (rev 92066)
@@ -24,14 +24,16 @@
 
 import org.jboss.jca.sjc.boot.BeanType;
 import org.jboss.jca.sjc.boot.ConstructorType;
+import org.jboss.jca.sjc.boot.DependsType;
 import org.jboss.jca.sjc.boot.InjectType;
 import org.jboss.jca.sjc.boot.PropertyType;
-import org.jboss.jca.sjc.deployers.DeployException;
 import org.jboss.jca.sjc.deployers.Deployer;
 
 import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.net.MalformedURLException;
@@ -40,12 +42,17 @@
 import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
 
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBElement;
@@ -57,19 +64,52 @@
  */
 public class Main
 {
+   /** Parallel startup */
+   private static boolean parallel = false;
+
    /** Startup list */
    private static List<String> startup = new LinkedList<String>();
 
    /** Services */
-   private static Map<String, Object> services = new HashMap<String, Object>();
+   private static ConcurrentMap<String, Object> services = new ConcurrentHashMap<String, Object>();
 
+   /** Services status */
+   private static ConcurrentMap<String, Status> servicesStatus = new ConcurrentHashMap<String, Status>();
+
+   /** Services latch */
+   private static CountDownLatch servicesLatch;
+
+   /** Executor service */
+   private static ExecutorService executorService;
+
    /** Container classloader */
    private static URLClassLoader containerClassLoader;
 
+   /** The deploy directory */
+   private static File deployDirectory;
+
    /** Logging */
    private static Object logging;
 
    /**
+    * Status
+    */
+   enum Status
+   {
+      /** Services not started */
+      NOT_STARTED,
+
+      /** Services starting */
+      STARTING,
+
+      /** Services started */
+      STARTED,
+         
+      /** Services stopped */
+      STOPPING
+   }
+
+   /**
     * Default constructor
     */
    private Main()
@@ -79,8 +119,9 @@
    /**
     * Boot
     * @param args The arguments
+    * @param tg The thread group used
     */
-   private static void boot(String[] args)
+   private static void boot(final String[] args, final ThreadGroup tg)
    {
       try
       {
@@ -106,12 +147,22 @@
                {
                   SecurityActions.setSystemProperty("jboss.jca.bindaddress", args[++i]);
                }
+               else if ("-mt".equals(args[i]))
+               {
+                  parallel = true;
+               }
             }
          }
 
+         if (parallel)
+         {
+            ThreadFactory tf = new SJCThreadFactory(tg);
+            executorService = Executors.newCachedThreadPool(tf);
+         }
+
          File libDirectory = new File(root, "/lib/");
          File configDirectory = new File(root, "/config/");
-         File deployDirectory = new File(root, "/deploy/");
+         deployDirectory = new File(root, "/deploy/");
 
          ClassLoader parent = SecurityActions.getThreadContextClassLoader();
 
@@ -138,19 +189,47 @@
 
          if (boot != null)
          {
+            if (parallel)
+               servicesLatch = new CountDownLatch(boot.getBean().size());
+
             for (BeanType bt : boot.getBean())
             {
-               if (services.get(bt.getName()) == null)
+               if (!parallel)
                {
-                  Object bean = createBean(bt, containerClassLoader, deployDirectory);
-                  startup.add(bt.getName());
-                  services.put(bt.getName(), bean);
+                  try
+                  {
+                     if (services.get(bt.getName()) == null)
+                     {
+                        setServiceStatus(bt.getName(), Status.STARTING);
+
+                        Object bean = createBean(bt, containerClassLoader, deployDirectory);
+                        startup.add(bt.getName());
+                        services.put(bt.getName(), bean);
+
+                        setServiceStatus(bt.getName(), Status.STARTED);
+                     }
+                     else
+                     {
+                        warn("Warning: A service with name " + bt.getName() + " already exists");
+                     }
+                  }
+                  catch (Throwable t)
+                  {
+                     error("Installing bean " + bt.getName(), t);
+                  }
                }
                else
                {
-                  warn("Warning: A service with name " + bt.getName() + " already exists");
+                  Runnable r = new ServiceRunnable(bt);
+                  executorService.execute(r);
                }
             }
+
+            if (parallel)
+            {
+               servicesLatch.await();
+               executorService.shutdown();
+            }
          }
       }
       catch (Throwable t)
@@ -160,6 +239,177 @@
    }
 
    /**
+    * Set service status
+    * @param name The service name
+    * @param status The service status
+    */
+   static void setServiceStatus(String name, Status status)
+   {
+      servicesStatus.put(name, status);
+   }
+
+   /**
+    * Service runnable
+    */
+   static class ServiceRunnable implements Runnable
+   {
+      /** The bean */
+      private BeanType bt;
+
+      /**
+       * Constructor
+       * @param bt The bean
+       */
+      public ServiceRunnable(BeanType bt)
+      {
+         this.bt = bt;
+      }
+
+      /**
+       * Run
+       */
+      public void run()
+      {
+         SecurityActions.setThreadContextClassLoader(containerClassLoader);
+
+         try
+         {
+            if (services.get(bt.getName()) == null)
+            {
+               setServiceStatus(bt.getName(), Status.NOT_STARTED);
+
+               Set<String> dependencies = getDependencies(bt);
+               int notStarted = getNotStarted(dependencies);
+
+               while (notStarted > 0)
+               {
+                  try
+                  {
+                     Thread.sleep(10);
+                     notStarted = getNotStarted(dependencies);
+                  }
+                  catch (InterruptedException ie)
+                  {
+                     Thread.interrupted();
+                  }
+               }
+
+               setServiceStatus(bt.getName(), Status.STARTING);
+
+               Object bean = createBean(bt, containerClassLoader, deployDirectory);
+               startup.add(bt.getName());
+               services.put(bt.getName(), bean);
+
+               setServiceStatus(bt.getName(), Status.STARTED);
+            }
+            else
+            {
+               warn("Warning: A service with name " + bt.getName() + " already exists");
+            }
+         }
+         catch (Throwable t)
+         {
+            error("Installing bean " + bt.getName(), t);
+         }
+
+         servicesLatch.countDown();
+      }
+
+      /**
+       * Get the depedencies for a bean
+       * @paran bt The bean type
+       * @return The set of dependencies; <code>null</code> if no dependencies
+       */
+      private Set<String> getDependencies(BeanType bt)
+      {
+         Set<String> result = null;
+
+         List<DependsType> dts = bt.getDepends();
+         if (dts != null)
+         {
+            result = new HashSet<String>();
+            for (DependsType dt : dts)
+            {
+               result.add(dt.getValue());
+            }
+         }
+
+         List<PropertyType> pts = bt.getProperty();
+         if (pts != null)
+         {
+            if (result == null)
+               result = new HashSet<String>();
+
+            for (PropertyType pt : pts)
+            {
+               Object e = pt.getContent().get(0);
+
+               if (e != null && e instanceof JAXBElement)
+               {
+                  Object element = ((JAXBElement)e).getValue();
+                  if (element instanceof InjectType)
+                  {
+                     InjectType it = (InjectType)element;
+                     result.add(it.getBean());
+                  }
+               }
+            }
+         }
+
+         return result;
+      }
+
+      /**
+       * Get the number of services that are not started yet
+       * @paran dependencies The dependencies for a service
+       * @return The number of not started services
+       */
+      private int getNotStarted(Set<String> dependencies)
+      {
+         if (dependencies == null || dependencies.size() == 0)
+            return 0;
+
+         int count = 0;
+         for (String dependency : dependencies)
+         {
+            Status dependencyStatus = servicesStatus.get(dependency);
+            if (dependencyStatus == null || dependencyStatus != Status.STARTED)
+               count += 1;
+         }
+
+         return count;
+      }
+   }
+
+   /**
+    * A thread factory for JCA/SJC
+    */
+   static class SJCThreadFactory implements ThreadFactory
+   {
+      /** The thread group */
+      private ThreadGroup tg;
+
+      /**
+       * Constructor
+       * @param tg The thread group
+       */
+      public SJCThreadFactory(ThreadGroup tg)
+      {
+         this.tg = tg;
+      }
+
+      /**
+       * Create a new thread
+       * @param r The runnable
+       * @return The thread
+       */
+      public Thread newThread(Runnable r)
+      {
+         return new Thread(tg, r);
+      }
+   }
+
+   /**
     * Shutdown
     */
    private static void shutdown()
@@ -171,6 +421,8 @@
 
       for (String name : shutdown)
       {
+         setServiceStatus(name, Status.STOPPING);
+
          Object service = services.get(name);
 
          try
@@ -192,6 +444,8 @@
          {
             // No destroy method
          }
+
+         setServiceStatus(name, Status.NOT_STARTED);
       }
 
       info("Shutdown complete");
@@ -698,7 +952,7 @@
          
          Method mGetLogger = clz.getMethod("getLogger", String.class);
 
-         logging = mGetLogger.invoke((Object)null, new Object[] {"Main"});
+         logging = mGetLogger.invoke((Object)null, new Object[] {"org.jboss.jca.sjc.Main"});
       }
       catch (Exception e)
       {
@@ -783,8 +1037,54 @@
       }
    }
 
+   /**
+    * Logging: Is DEBUG enabled
+    * @return True if debug is enabled; otherwise false
+    */
+   private static boolean isDebugEnabled()
+   {
+      if (logging != null)
+      {
+         try
+         {
+            Class clz = logging.getClass();
+            Method mIsDebugEnabled = clz.getMethod("isDebugEnabled", (Class[])null);
+            return ((Boolean)mIsDebugEnabled.invoke(logging, (Object[])null)).booleanValue();
+         }
+         catch (Exception e)
+         {
+            // Nothing we can do
+         }
+      }
+      return true;
+   }
 
    /**
+    * Logging: DEBUG
+    * @param s The string
+    */
+   private static void debug(String s)
+   {
+      if (logging != null)
+      {
+         try
+         {
+            Class clz = logging.getClass();
+            Method mDebug = clz.getMethod("debug", Object.class);
+            mDebug.invoke(logging, new Object[] {s});
+         }
+         catch (Exception e)
+         {
+            // Nothing we can do
+         }
+      }
+      else
+      {
+         System.out.println(s);
+      }
+   }
+
+   /**
     * Main
     * @param args The arguments
     */
@@ -795,13 +1095,15 @@
       {
          final CountDownLatch latch = new CountDownLatch(1);
 
+         final ThreadGroup threads = new ThreadGroup("jboss");
+
          Runnable worker = new Runnable()
          {
             public void run()
             {
                try
                {
-                  Main.boot(args);
+                  Main.boot(args, threads);
                   latch.countDown();
                }
                catch (Exception e)
@@ -811,7 +1113,6 @@
             }
          };
          
-         ThreadGroup threads = new ThreadGroup("jboss");
          Thread bootThread = new Thread(threads, worker, "main");
          bootThread.start();
 
@@ -840,8 +1141,22 @@
             }
          });
 
+         if (isDebugEnabled())
+         {
+            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
+            debug("Heap memory: " + memoryBean.getHeapMemoryUsage().toString());
+            debug("NonHeap memory: " + memoryBean.getNonHeapMemoryUsage().toString());
+         }
+
          long l2 = System.currentTimeMillis();
-         info("Server started in " + (l2 - l1) + "ms");
+         if (!parallel)
+         {
+            info("Server started in " + (l2 - l1) + "ms");
+         }
+         else
+         {
+            info("Server (MT mode) started in " + (l2 - l1) + "ms");
+         }
       }
       catch (Exception e)
       {

Modified: projects/jboss-jca/trunk/sjc/src/main/resources/boot.xml
===================================================================
--- projects/jboss-jca/trunk/sjc/src/main/resources/boot.xml	2009-08-06 14:33:02 UTC (rev 92065)
+++ projects/jboss-jca/trunk/sjc/src/main/resources/boot.xml	2009-08-06 14:44:40 UTC (rev 92066)
@@ -59,6 +59,7 @@
     <property name="recoveryInetAddress">localhost</property>
     <property name="recoveryPort">4712</property>
     <property name="socketProcessIdPort">0</property>    
+    <depends>NamingServer</depends>
   </bean>
 
   <!-- Work Manager thread pool -->
@@ -94,6 +95,8 @@
 
   <!-- RA deployer -->
   <bean name="RADeployer" interface="org.jboss.jca.sjc.deployers.Deployer" class="org.jboss.jca.sjc.deployers.ra.RADeployer">
+    <depends>ConnectionManager</depends>
+    <depends>WorkManager</depends>
   </bean>
 
 </deployment>

Modified: projects/jboss-jca/trunk/sjc/src/main/resources/boot.xsd
===================================================================
--- projects/jboss-jca/trunk/sjc/src/main/resources/boot.xsd	2009-08-06 14:33:02 UTC (rev 92065)
+++ projects/jboss-jca/trunk/sjc/src/main/resources/boot.xsd	2009-08-06 14:44:40 UTC (rev 92066)
@@ -8,6 +8,7 @@
      <xsd:sequence>
        <xsd:element name="constructor" type="constructorType" maxOccurs="1" minOccurs="0"/>
        <xsd:element name="property" type="propertyType" maxOccurs="unbounded" minOccurs="0"/>
+       <xsd:element name="depends" type="dependsType" maxOccurs="unbounded" minOccurs="0"/>
      </xsd:sequence>
      <xsd:attribute name="name" type="xsd:token" use="required"/>
      <xsd:attribute name="interface" type="xsd:token"/>
@@ -46,6 +47,13 @@
      </xsd:simpleContent>
    </xsd:complexType>
 
+   <xsd:complexType name="dependsType">
+     <xsd:simpleContent>
+       <xsd:extension base="xsd:token">
+       </xsd:extension>
+     </xsd:simpleContent>
+   </xsd:complexType>
+
    <xsd:element name="deployment">
      <xsd:complexType>
        <xsd:sequence>




More information about the jboss-cvs-commits mailing list