This content has been marked as final.
Show 1 reply
-
1. Re: Howto install custom classloader
deady Nov 7, 2008 10:01 AM (in response to deady)For simplicity let's load class from file.
here's a trick:
1. create classloaderpackage test.jboss; import org.jboss.logging.Logger; import org.jboss.mx.loading.RepositoryClassLoader; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import java.net.URL; import java.io.FileInputStream; import java.io.IOException; /** * User: Deady * Date: 06.11.2008 * Time: 16:58:53 */ public class DBClassLoader extends RepositoryClassLoader { protected Logger log; private String name; /** * Create a new LoaderRepositoryClassLoader * * @param parent the parent classloader */ public DBClassLoader(String name, URL[] url, ClassLoader parent) { super(url, parent); this.name = name; this.log = org.jboss.logging.Logger.getLogger(getClass().getName()); } public ObjectName getObjectName() throws MalformedObjectNameException { return new ObjectName("dbclassloader"); } public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { log.info("loading class: "+name); return super.loadClass(name, resolve); } public URL getResourceLocally(String name) { log.info("getting resource locally: "+name); return getURL(); } public Class loadClassLocally(String name, boolean resolve) throws ClassNotFoundException { log.info("loading class locally: "+name); String file = "/home/Deady/testbean/classes/"+name.replace(".","/")+".class"; byte[] b = null; int readen = 0; try { FileInputStream in = new FileInputStream(file); b = new byte[in.available()]; readen = in.read(b); in.close(); } catch (IOException e) { e.printStackTrace(); } return defineClass(name, b, 0, readen); } public Package[] getPackages() { log.info("return packages: "+getPackage(name)); return new Package[]{getPackage(name)}; } }
2. create deployer MBean:package test.jboss; import org.jboss.deployment.DeploymentException; import org.jboss.deployment.DeploymentInfo; import org.jboss.deployment.SubDeployerSupport; import org.jboss.logging.Logger; import java.net.URL; /** * User: Deady * Date: 06.11.2008 * Time: 13:42:03 */ public class DBDeployerMBean extends SubDeployerSupport { protected Logger log; public DBDeployerMBean() { this.log = org.jboss.logging.Logger.getLogger(getClass().getName()); } public boolean accepts(DeploymentInfo di) { String urlStr = di.url.toString(); String extension = getExtension(); boolean res = urlStr.endsWith(extension); if (res) { log.info("accepted: "+di); } return res; } public void init(DeploymentInfo di) throws DeploymentException { log.info("initializing: "+di); try { di.createClassLoaders(); di.ucl.getLoaderRepository().addClassLoader(new DBClassLoader("foo", new URL[]{di.localUrl}, di.ucl)); } catch (Exception e) { e.printStackTrace(); } super.init(di); } protected void deployUrl(DeploymentInfo di, URL url, String name) throws DeploymentException { log.info("di: "+di+", url:"+url+", name: "+name); super.deployUrl(di, url, name); } public String getExtension() { return ".dbr"; } }
3. create sar descriptor:<?xml version="1.0" encoding="UTF-8"?> <!-- The JBoss service configuration file for the EJB deployer service. $Id: ejb-deployer.xml 62317 2007-04-13 10:39:22Z dimitris@jboss.org $ --> <server> <!-- ==================================================================== --> <!-- DB Deployer --> <!-- ==================================================================== --> <!-- EJB deployer, remove to disable EJB behavior--> <mbean code="test.jboss.DBDeployerMBean" name="jboss.ejb:service=DBDeployer" xmbean-dd=""> <!-- Inline XMBean Descriptor BEGIN --> <xmbean> <description>The DBDeployer responsible for dbr jar deployment</description> <class>test.jboss.DBDeployerMBean</class> <!-- ServiceMBean operations --> <operation> <description>Standard MBean lifecycle method</description> <name>create</name> </operation> <operation> <description>The start lifecycle operation</description> <name>start</name> </operation> <operation> <description>The stop lifecycle operation</description> <name>stop</name> </operation> <operation> <description>The destroy lifecycle operation</description> <name>destroy</name> </operation> <operation> <description>The detyped lifecycle operation (for internal use only)</description> <name>jbossInternalLifecycle</name> <parameter> <description>The lifecycle operation</description> <name>method</name> <type>java.lang.String</type> </parameter> <return-type>void</return-type> </operation> <!-- SubDeployerMBean operations --> <operation> <description>Accept a module for deployment</description> <name>accepts</name> <parameter> <name>info</name> <type>org.jboss.deployment.DeploymentInfo</type> </parameter> <return-type>boolean</return-type> </operation> <operation> <description>Initialize deployment step</description> <name>init</name> <parameter> <name>info</name> <type>org.jboss.deployment.DeploymentInfo</type> </parameter> </operation> <operation> <description>Create deployment step</description> <name>create</name> <parameter> <name>info</name> <type>org.jboss.deployment.DeploymentInfo</type> </parameter> </operation> <operation> <description>Start deployment step</description> <name>start</name> <parameter> <name>info</name> <type>org.jboss.deployment.DeploymentInfo</type> </parameter> </operation> <operation> <description>Stop deployment step</description> <name>stop</name> <parameter> <name>info</name> <type>org.jboss.deployment.DeploymentInfo</type> </parameter> </operation> <operation> <description>Destroy deployment step</description> <name>destroy</name> <parameter> <name>info</name> <type>org.jboss.deployment.DeploymentInfo</type> </parameter> </operation> </xmbean> </mbean> </server>
4. pack sar and copy it to server:
/jboss/server/deploy/dbdeployer.sar
+METAINF
++jboss-service.xml
+dbdeployer.jar
5. create and deploy test.ddr - this is simple jar file:
test.dbr
+META-INF
++INDEX.LIST
content of INDEX.LIST:ddd db.jar foo
6. create test bean:package test; import javax.ejb.Remote; /** * User: Deady * Date: 06.11.2008 * Time: 17:08:24 */ @Remote public interface TestClassLoader { public Object loadClass(String className); }
package test; import org.jboss.annotation.ejb.RemoteBinding; import javax.ejb.Stateless; /** * User: Deady * Date: 06.11.2008 * Time: 17:09:06 */ @Stateless(name="DBClassLoader") @RemoteBinding(jndiBinding="test/DBClassLoader/remote") public class TestClassLoaderImpl implements TestClassLoader{ public Object loadClass(String className) { try { Class cl = Thread.currentThread().getContextClassLoader().loadClass(className); System.out.println("loaded = " + cl); Object o = cl.newInstance(); return o; } catch (Exception e) { e.printStackTrace(); } return null; } }
7. create test class:package foo; import java.io.Serializable; /** * User: Deady * Date: 07.11.2008 * Time: 17:19:00 */ public class Test implements Serializable { public String hello() { return "hello world3"; } }
compile it and copy to path, from which DBClassLoader will read it ("/home/Deady/testbean/classes/" in my case)
8. test it works:package test; import foo.Test; import javax.naming.InitialContext; import javax.naming.Context; import java.util.Properties; /** * User: Deady * Date: 06.11.2008 * Time: 17:16:26 */ public class Client { public static void main(String[] args) throws Exception { Properties p = new Properties(); p.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); p.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); p.put(Context.PROVIDER_URL, "jnp://192.168.0.87:1099"); InitialContext ctx = new InitialContext(p); TestClassLoader l = (TestClassLoader) ctx.lookup("test/DBClassLoader/remote"); Object c = l.loadClass("foo.Test"); if (c==null) { System.out.println("null"); } else { if (c instanceof Test) { System.out.println(((Test)c).hello()); } else { System.out.println(c.getClass()); } } } }