Hi Guys,
I've managed to do some work on the no-interface view work. I've managed to
read the localbean ejb-jar.xml config and @LocalBean annotation, and
propagate this through to CoreDeploymentInfo. I've got to a point where I
can lookup an EJB and get a proxy back. There's still some work to do, as
I'm getting this exception:
//START SNIPPET: localbean
public void testCalculatorViaLocalBeanInterface() throws Exception {
Object object = initialContext.lookup("CalculatorImplLocalBean");
assertNotNull(object);
assertTrue(object instanceof CalculatorImpl);
CalculatorImpl calc = (CalculatorImpl) object;
assertEquals(10, calc.sum(4,6));
assertEquals(12, calc.multiply(3,4));
}
java.lang.reflect.UndeclaredThrowableException
at $LocalBeanProxy0.sum($LocalBeanProxy0.java)
at
org.superbiz.calculator.CalculatorTest.testCalculatorViaLocalBeanInterface(CalculatorTest.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:228)
at junit.framework.TestSuite.run(TestSuite.java:223)
at
org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:35)
at
org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
at
org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
at
org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
at
org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
Caused by: java.lang.IllegalStateException: Received method invocation and
cannot determine corresponding business interface: method=public int
$LocalBeanProxy0.sum(int,int)
at
org.apache.openejb.core.ivm.BaseEjbProxyHandler.getInvokedInterface(BaseEjbProxyHandler.java:188)
at
org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:245)
... 25 more
I haven't dived into this exception much, so I'll keep working on it, but if
anyone has any advice it would be much appreciated!
There are a couple of things I could do with some guidance on, I'd be
grateful for any help anyone could give.
JNDI:
I've added the following code to JndiBuilder.bind():
try {
if (deployment.isLocalbean()) {
Class beanClass = deployment.getBeanClass();
LocalBeanReference ref = new LocalBeanReference(deployment);
optionalBind(bindings, ref, "openejb/Deployment/" +
format(deployment.getDeploymentID(), beanClass.getName(), null));
String internalName = "openejb/Deployment/" +
format(deployment.getDeploymentID(), beanClass.getName(),
InterfaceType.LOCALBEAN);
bind(internalName, ref, bindings, beanInfo, beanClass);
String name = strategy.getName(beanClass,
JndiNameStrategy.Interface.LOCALBEAN);
bind("openejb/local/" + name, ref, bindings, beanInfo,
beanClass);
bind("openejb/remote/" + name, ref, bindings, beanInfo,
beanClass);
}
} catch (NamingException e) {
throw new RuntimeException("Unable to bind localbean deployment
in jndi.", e);
}
I created a LocalBeanReference class - which what is bound into JNDI. This
takes a CoreDeploymentInfo object, and its getObject() creates a proxy.
Here's the code:
package org.apache.openejb.core.ivm.naming;
import org.apache.openejb.core.CoreDeploymentInfo;
import javax.naming.*;
public class LocalBeanReference extends Reference {
private CoreDeploymentInfo deployment;
public LocalBeanReference(CoreDeploymentInfo deployment) {
this.deployment = deployment;
}
public Object getObject() throws javax.naming.NamingException {
return deployment.getLocalBean();
}
}
I'm concerned that this isn't the right approach - I notice that the other
interfaces bind a BusinessRemoteHome/BusinessLocalHome class, should this
follow the same pattern, or could just bind a ObjectReference with the
proxy?
Also, the default Global JNDI name is <className>LocalBean - is this ok?
Class loading:
I've added a method to CoreDeploymentInfo, which will create a new proxy.
The code I've written to create the proxy using the ASM library returns a
byte[]. To load this class I'm creating a new ClassLoader, which is a child
of the ClassLoader that the bean itself is created from, and calling
defineClass(). I'm not sure if this is right, I'd appreciate any thoughts
anyone has.
Cheers,
Jon