Index: /Users/svn/JBossHead/jboss-head/ejb3/build.xml
===================================================================
--- /Users/svn/JBossHead/jboss-head/ejb3/build.xml (revision 76821)
+++ /Users/svn/JBossHead/jboss-head/ejb3/build.xml (working copy)
@@ -94,6 +94,7 @@
+
Index: /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/client/ClientContainer.java
===================================================================
--- /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/client/ClientContainer.java (revision 76821)
+++ /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/client/ClientContainer.java (working copy)
@@ -30,6 +30,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -53,7 +54,6 @@
import org.jboss.injection.InjectionContainer;
import org.jboss.injection.InjectionHandler;
import org.jboss.injection.Injector;
-import org.jboss.injection.JndiInjectHandler;
import org.jboss.injection.PersistenceUnitHandler;
import org.jboss.injection.WebServiceRefHandler;
import org.jboss.logging.Logger;
@@ -103,6 +103,9 @@
{
log.info("ClientContainer(version="+VERSION+")");
log.info("DependencyPolicy.CS: "+DependencyPolicy.class.getProtectionDomain().getCodeSource());
+ log.info("ClientContainer.CS: "+getClass().getProtectionDomain().getCodeSource());
+ ClassLoader mainClassLoader = mainClass.getClassLoader();
+ log.info("mainClass.ClassLoader: "+mainClassLoader);
clientJndiEnv.set(jndiEnv);
this.xml = xml;
this.mainClass = mainClass;
@@ -110,6 +113,8 @@
ClientJavaEEComponent client = new ClientJavaEEComponent(applicationClientName);
this.dependsPolicy = new NoopDependencyPolicy(client);
+ URL jndiPropertiesURL = mainClassLoader.getResource("jndi.properties");
+ log.info("mainClassLoader jndi.properties: "+jndiPropertiesURL);
Context ctx = InitialContextFactory.getInitialContext(jndiEnv);
enc = (Context) ctx.lookup(applicationClientName);
StringBuffer encInfo = new StringBuffer("Client ENC("+applicationClientName+"):\n");
@@ -289,9 +294,19 @@
{
Class> parameterTypes[] = { args.getClass() };
Method method = mainClass.getDeclaredMethod("main", parameterTypes);
- method.invoke(null, (Object) args);
+ try
+ {
+ log.info("Invoking main: "+method);
+ method.invoke(null, (Object) args);
+ log.info("Successfully invoked main");
+ }
+ catch(Throwable e)
+ {
+ e.printStackTrace();
+ log.error("Invocation of client main failed", e);
+ }
}
-
+
/**
* Call post construct methods.
* @throws IllegalAccessException
Index: /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/client/ClientLauncher.java
===================================================================
--- /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/client/ClientLauncher.java (revision 76821)
+++ /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/client/ClientLauncher.java (working copy)
@@ -22,8 +22,13 @@
package org.jboss.ejb3.client;
import java.io.IOException;
-import java.net.URL;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.rmi.server.RMIClassLoader;
+import java.rmi.server.RMIClassLoaderSpi;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Properties;
@@ -30,10 +35,32 @@
import javax.naming.InitialContext;
import javax.naming.NamingException;
+import org.jboss.beans.metadata.plugins.builder.BeanMetaDataBuilderFactory;
+import org.jboss.beans.metadata.spi.BeanMetaData;
+import org.jboss.beans.metadata.spi.BeanMetaDataFactory;
+import org.jboss.beans.metadata.spi.ValueMetaData;
+import org.jboss.beans.metadata.spi.builder.BeanMetaDataBuilder;
+import org.jboss.classloader.plugins.system.DefaultClassLoaderSystem;
+import org.jboss.classloader.spi.ClassLoaderDomain;
+import org.jboss.classloader.spi.ClassLoaderSystem;
+import org.jboss.classloader.spi.ParentPolicy;
+import org.jboss.classloading.spi.dependency.ClassLoading;
+import org.jboss.classloading.spi.vfs.dependency.VFSClassLoaderPolicyModule;
+import org.jboss.classloading.spi.vfs.metadata.VFSClassLoaderFactory;
+import org.jboss.classloading.spi.vfs.metadata.VFSClassLoaderFactory10;
import org.jboss.client.AppClientLauncher;
+import org.jboss.dependency.spi.ControllerMode;
+import org.jboss.dependency.spi.ControllerState;
+import org.jboss.kernel.Kernel;
+import org.jboss.kernel.plugins.bootstrap.AbstractBootstrap;
+import org.jboss.kernel.plugins.bootstrap.basic.BasicBootstrap;
+import org.jboss.kernel.plugins.deployment.AbstractKernelDeployment;
+import org.jboss.kernel.plugins.deployment.xml.BasicXMLDeployer;
+import org.jboss.kernel.spi.dependency.KernelController;
+import org.jboss.kernel.spi.dependency.KernelControllerContext;
+import org.jboss.kernel.spi.deployment.KernelDeployment;
import org.jboss.logging.Logger;
import org.jboss.metadata.client.jboss.JBossClientMetaData;
-import org.jboss.util.NotImplementedException;
import org.jboss.xb.binding.JBossXBException;
/**
@@ -51,7 +78,13 @@
implements AppClientLauncher
{
private static final Logger log = Logger.getLogger(ClientLauncher.class);
-
+ private static Throwable exception;
+ /** The kernel */
+ private static Kernel kernel;
+
+ /** The deployer */
+ private static BasicXMLDeployer deployer;
+
/**
* Convenience method for launching a client container.
*
@@ -62,28 +95,12 @@
* @throws Exception
*/
public static void launch(JBossClientMetaData xml, String mainClassName, String applicationClientName, String args[])
- throws Exception
+ throws Throwable
{
- launch(xml, mainClassName, applicationClientName, args, null);
+ List cp = Collections.emptyList();
+ launch(xml, cp, mainClassName, applicationClientName, args, null);
}
- public static void launch(JBossClientMetaData xml, String mainClassName,
- String applicationClientName, String args[], Properties jndiEnv)
- throws Exception
- {
- Class> mainClass = Class.forName(mainClassName);
- // Pass in the jndi env properties so InitialContext() works
- if(jndiEnv != null)
- {
- for(Object key : jndiEnv.keySet())
- {
- String name = (String) key;
- System.setProperty(name, jndiEnv.getProperty(name));
- }
- }
- ClientContainer container = new ClientContainer(xml, mainClass, applicationClientName, jndiEnv);
-
- container.invokeMain(args);
- }
+
/**
* Convenience method to load the XML descriptor.
@@ -94,13 +111,6 @@
*/
public static JBossClientMetaData loadXML(String applicationClientName) throws NamingException
{
- /*
- URL url = findResource("META-INF/application-client.xml");
- log.trace("application-client.xml found at " + url);
- URL jbossClientURL = findResource("META-INF/jboss-client.xml");
- log.trace("jboss-client.xml found at " + jbossClientURL);
- return loadXML(url, jbossClientURL);
- */
log.warn("FIXME: using an unsupported hack to get metadata");
InitialContext ctx = new InitialContext();
JBossClientMetaData metaData = (JBossClientMetaData) ctx.lookup(applicationClientName + "/metaData");
@@ -106,60 +116,251 @@
JBossClientMetaData metaData = (JBossClientMetaData) ctx.lookup(applicationClientName + "/metaData");
return metaData;
}
-
+ public static List loadClassPath(String applicationClientName)
+ throws NamingException
+ {
+ InitialContext ctx = new InitialContext();
+ List cp = (List) ctx.lookup(applicationClientName + "/classPathEntries");
+ return cp;
+ }
+
/**
- * Work in progress.
+ * The AppClientLauncher method for launching a client container.
*
- * @param args the arguments for the launcher
+ * @param mainClassName - the class whose main(String[]) will be invoked
+ * @param clientName - the client name that maps to the server side JNDI ENC
+ * @param args - the args to pass to main method
+ * @throws Throwable
*/
- public static void main(String[] args)
+ public void launch(String mainClassName, String clientName, String args[])
+ throws Throwable
+ {
+ launch(mainClassName, clientName, args, null);
+ }
+ public void launch(String mainClassName, String clientName, String args[],
+ Properties jndiEnv)
+ throws Throwable
+ {
+ // Set the RMIClassLoaderSpi implementation to JBossRMIClassLoader
+ System.setProperty("java.rmi.server.RMIClassLoaderSpi", JBossRMIClassLoader.class.getName());
+
+ JBossClientMetaData xml = loadXML(clientName);
+ List cp = loadClassPath(clientName);
+ launch(xml, cp, mainClassName, clientName, args, jndiEnv);
+ }
+
+ /**
+ * The client launcher entry point that create an mc to launch the client container.
+ * @param clientClass
+ * @param clientName
+ * @param cp
+ * @param args
+ * @throws Throwable
+ */
+ public static void launch(JBossClientMetaData xml, List classPath,
+ String mainClassName, String applicationClientName, String args[],
+ Properties jndiEnv)
+ throws Throwable
{
+ // Init the kernel and deployers
+ init();
+
+ // Pass in the jndi env properties so InitialContext() works
+ if(jndiEnv != null)
+ {
+ for(Object key : jndiEnv.keySet())
+ {
+ String name = (String) key;
+ System.setProperty(name, jndiEnv.getProperty(name));
+ }
+ }
+
+ ArrayList beanFactories = new ArrayList();
+ ArrayList beans = new ArrayList();
+
+ // Add the common launcher beans, ClassLoaderSystem
+ BeanMetaDataBuilder builder = BeanMetaDataBuilderFactory.createBuilder("ClassLoaderSystem", ClassLoaderSystem.class.getName());
+ builder.setFactoryClass(ClientLauncher.class.getName());
+ builder.setFactoryMethod("getClassLoaderSystem");
+ BeanMetaData classLoaderSystemBMD = builder.getBeanMetaData();
+ addBeanMetaData(beanFactories, beans, classLoaderSystemBMD);
+
+ // ClassLoading
+ builder = BeanMetaDataBuilderFactory.createBuilder("ClassLoading", ClassLoading.class.getName());
+ builder.addMethodInstallCallback("addModule", ControllerState.CONFIGURED);
+ builder.addMethodUninstallCallback("removeModule", ControllerState.CONFIGURED);
+ BeanMetaData classLoadingBMD = builder.getBeanMetaData();
+ addBeanMetaData(beanFactories, beans, classLoadingBMD);
+
try
{
- if(args.length < 1)
- throw new IllegalArgumentException("expected a jar filename as argument");
-
- Class> mainClass;
-
- String name = args[0];
- if(name.endsWith(".jar"))
+ builder = BeanMetaDataBuilderFactory.createBuilder("ClientContainer",
+ "org.jboss.ejb3.client.ClientContainer");
+ VFSClassLoaderFactory factory = new VFSClassLoaderFactory("ClientLauncherClassPath");
+ ArrayList roots = new ArrayList();
+ // Create the classpath
+ log.debug("Setting up classpath from: ");
+ for(String path : classPath)
{
- throw new NotImplementedException();
-// JarFile jarFile = new JarFile(jarName);
+ log.debug(path);
+ roots.add(path);
}
- else
+ factory.setRoots(roots);
+ beanFactories.add(factory);
+ // ClientContainer(xml, mainClass, applicationClientName, jndiEnv);
+ builder.addConstructorParameter(JBossClientMetaData.class.getName(), xml);
+ builder.addConstructorParameter(Class.class.getName(), mainClassName);
+ builder.addConstructorParameter(String.class.getName(), applicationClientName);
+ builder.addConstructorParameter(Properties.class.getName(), jndiEnv);
+ // Use vfs class loader as the ClientContainer class loader
+ String classLoaderName = factory.getContextName();
+ if(classLoaderName == null)
+ classLoaderName = factory.getName() + ":" + factory.getVersion();
+ ValueMetaData classLoader = builder.createInject(classLoaderName);
+ builder.setClassLoader(classLoader);
+ BeanMetaData clientContainerMD = builder.getBeanMetaData();
+
+ AbstractKernelDeployment deployment = new AbstractKernelDeployment();
+ deployment.setName(factory.getName() + ":" + factory.getVersion());
+ addBeanMetaData(beanFactories, beans, clientContainerMD);
+ deployment.setBeanFactories(beanFactories);
+ if(beans.size() > 0)
+ deployment.setBeans(beans);
+ deploy(deployment);
+
+ KernelController controller = kernel.getController();
+ // ClientContainer
+ KernelControllerContext context = (KernelControllerContext) controller.getContext("ClientContainer", ControllerState.INSTALLED);
+ if (context == null)
+ throw new Exception("ClientContainer bean was not created");
+ Object client = context.getTarget();
+ KernelControllerContext cclContext = (KernelControllerContext) controller.getContext(classLoaderName, ControllerState.INSTALLED);
+ if (cclContext == null)
+ throw new Exception(classLoaderName+" bean was not created");
+ ClassLoader ccLoader = (ClassLoader) cclContext.getTarget();
+ if (ccLoader == null )
+ throw new Exception(classLoaderName+" bean was not created");
+ if (client.getClass().getClassLoader() != ccLoader)
+ log.warn(client.getClass().getClassLoader()+" != "+ccLoader);
+ Class> clientContainerClass = ccLoader.loadClass("org.jboss.ejb3.client.ClientContainer");
+ if (clientContainerClass.getClassLoader() != ccLoader)
+ log.warn(clientContainerClass.getClassLoader()+" != "+ccLoader);
+
+ // Invoke main on the underlying client main class through the ClientContain
+ ClassLoader prevLoader = Thread.currentThread().getContextClassLoader();
+ try
{
- String mainClassName = name;
- mainClass = Class.forName(mainClassName);
+ Thread.currentThread().setContextClassLoader(ccLoader);
+ Class> parameterTypes[] = { args.getClass() };
+ Method invokeMain = clientContainerClass.getDeclaredMethod("invokeMain", parameterTypes);
+ invokeMain.invoke(client, (Object) args);
}
-
- URL appXmlURL = mainClass.getClassLoader().getResource("META-INF/application-client.xml");
- if(appXmlURL == null)
- throw new RuntimeException("Can't find META-INF/application-client.xml");
-
- // FIXME: client metadata
- JBossClientMetaData xml = null;
- //JBossClientMetaData xml = ApplicationClientDDObjectFactory.parse(appXmlURL);
- if(true)
- throw new RuntimeException("NYI");
-
- // FIXME: j2ee.clientName
-
- List newArgs = new ArrayList();
- for(int i = 1; i < args.length; i++)
+ finally
{
- newArgs.add(args[i]);
+ Thread.currentThread().setContextClassLoader(prevLoader);
}
- args = newArgs.toArray(args);
-
- // FIXME: when jar gets implemented this won't work anymore
- String mainClassName = name;
- launch(xml, mainClassName, "FIXME", args);
+
+ //
+ undeploy(deployment);
+ }
+ catch(Throwable e)
+ {
+ exception = e;
+ throw e;
+ }
+ }
+
+ /**
+ * Create a ClassLoaderSystem with the default ClassLoaderDomain set to use
+ * a AFTER ParentPolicy.
+ *
+ * @return ClassLoaderSystem instance
+ */
+ public static ClassLoaderSystem getClassLoaderSystem()
+ {
+ DefaultClassLoaderSystem system = new DefaultClassLoaderSystem();
+ ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+ defaultDomain.setParentPolicy(ParentPolicy.AFTER);
+ return system;
+ }
+
+ private static void addBeanMetaData(
+ ArrayList beanFactories,
+ ArrayList beans, BeanMetaData bmd)
+ {
+ // TODO Auto-generated method stub
+ if(bmd instanceof BeanMetaDataFactory)
+ {
+ BeanMetaDataFactory bmdf = (BeanMetaDataFactory) bmd;
+ beanFactories.add(bmdf);
+ }
+ else
+ {
+ // Have to use the deprecated beans
+ beans.add(bmd);
+ }
+ }
+
+ private static void init() throws Throwable
+ {
+ // Bootstrap the kernel
+ AbstractBootstrap bootstrap = new BasicBootstrap();
+ bootstrap.run();
+ kernel = bootstrap.getKernel();
+
+ // Create the deployer
+ deployer = createDeployer();
+
+ }
+
+ private static BasicXMLDeployer createDeployer()
+ {
+ return new BasicXMLDeployer(kernel, ControllerMode.AUTOMATIC);
+ }
+
+ /**
+ * Deploy a deployment
+ *
+ * @param deployment the deployment
+ * @throws Exception for any error
+ */
+ private static void deploy(KernelDeployment deployment) throws Exception
+ {
+ log.debug("Deploying " + deployment);
+ try
+ {
+ deployer.deploy(deployment);
+ log.debug("Deployed " + deployment);
}
catch (Exception e)
{
- e.printStackTrace();
- System.exit(1);
+ throw e;
+ }
+ catch (Error e)
+ {
+ throw e;
+ }
+ catch (Throwable t)
+ {
+ throw new RuntimeException("Error deploying deployment: " + deployment, t);
+ }
+ }
+ /**
+ * Undeploy a deployment
+ *
+ * @param deployment the deployment
+ */
+ private static void undeploy(KernelDeployment deployment)
+ {
+ log.debug("Undeploying " + deployment.getName());
+ try
+ {
+ deployer.undeploy(deployment);
+ log.trace("Undeployed " + deployment.getName());
+ }
+ catch (Throwable t)
+ {
+ log.warn("Error during undeployment: " + deployment.getName(), t);
}
}
@@ -164,24 +365,122 @@
}
/**
- * The AppClientLauncher method for launching a client container.
+ * Validate
*
- * @param mainClassName - the class whose main(String[]) will be invoked
- * @param clientName - the client name that maps to the server side JNDI ENC
- * @param args - the args to pass to main method
- * @throws Throwable
+ * @throws Exception for any error
*/
- public void launch(String mainClassName, String clientName, String args[])
- throws Throwable
+ private static void validate() throws Exception
{
- launch(mainClassName, clientName, args, null);
+ try
+ {
+ deployer.validate();
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw e;
+ }
+ catch (Error e)
+ {
+ throw e;
+ }
+ catch (Throwable t)
+ {
+ throw new RuntimeException(t);
+ }
}
- public void launch(String mainClassName, String clientName, String args[],
- Properties jndiEnv)
- throws Throwable
+
+ public static void main(String[] args)
+ {
+ String[] roots = {
+ "vfszip:/home/svn/JBossHead/jboss-head/build/output/jboss-5.0.0.CR2/server/cts/tmp/jsr88/assembly_classpath_appclient.ear/assembly_classpath_appclient_client.jar",
+ "vfszip:/Users/svn/JBossHead/jboss-head/build/output/jboss-5.0.0.CR2/server/cts/tmp/jsr88/assembly_classpath_appclient.ear/libs/direct_classpath_util.jar",
+ "vfszip:/Users/svn/JBossHead/jboss-head/build/output/jboss-5.0.0.CR2/server/cts/tmp/jsr88/assembly_classpath_appclient.ear/libs/indirect_classpath_util.jar"
+ };
+ VFSClassLoaderFactory10 factory = new VFSClassLoaderFactory10();
+ factory.setRoots(Arrays.asList(roots));
+ VFSClassLoaderPolicyModule module = new VFSClassLoaderPolicyModule(factory, "AppClientLoaderModule");
+
+ }
+
+ /**
+ * RMIClassLoaderSpi that uses the thread context class loader
+ *
+ * @author Adrian Brock
+ * @author Scott.Stark@jboss.org
+ * @version $Revision:$
+ */
+ public static class JBossRMIClassLoader
+ extends RMIClassLoaderSpi
{
- JBossClientMetaData xml = loadXML(clientName);
- launch(xml, mainClassName, clientName, args, jndiEnv);
+ // Attributes ----------------------------------------------------
+
+ /**
+ * The JVM implementation (we delegate most work to it)
+ */
+ RMIClassLoaderSpi delegate = RMIClassLoader.getDefaultProviderInstance();
+
+ // Constructors --------------------------------------------------
+
+ /**
+ * Required constructor
+ */
+ public JBossRMIClassLoader()
+ {
+ }
+
+ // RMIClassLoaderSpi Implementation ------------------------------
+
+ /*
+ * Ignore the JVM, use the thread context classloader for proxy caching
+ */
+ public Class> loadProxyClass(String codebase, String[] interfaces, ClassLoader ignored)
+ throws MalformedURLException, ClassNotFoundException
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ return delegate.loadProxyClass(codebase, interfaces, loader);
+ }
+
+ /*
+ * Just delegate
+ */
+ public Class> loadClass(String codebase, String name, ClassLoader ignored)
+ throws MalformedURLException, ClassNotFoundException
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ return delegate.loadClass(codebase, name, loader);
+ }
+
+ /*
+ * Just delegate
+ */
+ public ClassLoader getClassLoader(String codebase)
+ throws MalformedURLException
+ {
+ return delegate.getClassLoader(codebase);
+ }
+
+ /*
+ * Try to delegate an default to the java.rmi.server.codebase on any
+ * failure.
+ */
+ public String getClassAnnotation(Class> cl)
+ {
+ String annotation = null;
+ try
+ {
+ annotation = delegate.getClassAnnotation(cl);
+ }
+ catch(Throwable t)
+ {
+ // Try the java.rmi.server.codebase property
+ annotation = System.getProperty("java.rmi.server.codebase");
+ }
+ return annotation;
+ }
}
}
Index: /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/deployers/Ejb3ClientDeployer.java
===================================================================
--- /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/deployers/Ejb3ClientDeployer.java (revision 76821)
+++ /Users/svn/JBossHead/jboss-head/ejb3/src/main/org/jboss/ejb3/deployers/Ejb3ClientDeployer.java (working copy)
@@ -21,6 +21,7 @@
*/
package org.jboss.ejb3.deployers;
+import java.util.ArrayList;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
@@ -107,7 +108,14 @@
}
// Notify the client launcher of extra class path entries in an EAR (See EE 8.2)
- encCtx.bind("classPathEntries", getClassPathEntries(unit));
+ List classPath = unit.getClassPath();
+ ArrayList cpURIs = new ArrayList();
+ for(VirtualFile vf : classPath)
+ {
+ String uri = vf.toURI().toString();
+ cpURIs.add(uri);
+ }
+ encCtx.bind("classPathEntries", cpURIs);
// java:comp/UserTransaction -> UserTransaction
Util.createLinkRef(encCtx, "UserTransaction", "UserTransaction");