[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 (<depends>).</para>
<para>The layout of boot.xml is defined in</para>
<programlisting>
@@ -87,7 +89,7 @@
</listitem>
<listitem>
<code><inject></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><constructor></code>
@@ -97,6 +99,10 @@
<code><parameter></code>
<para>defines a parameter value for a constructor.</para>
</listitem>
+ <listitem>
+ <code><depends></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 @@
<property name="transactionTimeout">300</property>
<property name="objectStoreDir">${jboss.jca.home}/tmp/tx-object-store</property>
<property name="mbeanServer"><inject bean="JMX" property="mbeanServer"/></property>
- <property name="transactionStatusManagerInetAddress">localhost</property>
+ <property name="transactionStatusManagerInetAddress">${jboss.jca.host:localhost}</property>
<property name="transactionStatusManagerPort">4713</property>
- <property name="recoveryInetAddress">localhost</property>
+ <property name="recoveryInetAddress">${jboss.jca.host:localhost}</property>
<property name="recoveryPort">4712</property>
<property name="socketProcessIdPort">0</property>
+ <depends>NamingServer</depends>
</bean>
</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