My current project is looking at how to expose Enterprise Java Beans to other technologies. I am most concerned with C#, but any other languages would be cool. We looked at the WS-* standards (and CXF which is a great tool) but the different versions across the vendors provided difficult.
We then looked at QMF, which is an management framework written on top of the QPID messaging fabric. You can learn about QMF here. This post will walk you through an eaxmple of exposing an EJB in jboss over the QMF Bus. Gregory Mostizky is working on a deployer, so this should get easier.. but this is a good enough to criticize.. so I am posting it.
To get started, you will need the gcc tools, ant, and jboss5 installed. Next.. get the code:
# Get the latest QPID Code svn co http://svn.apache.org/repos/asf/qpid/trunk # Get my example Code: git clone git://github.com/bkearney/qmfExample.git
Build the latest qpidd broker and java code
cd trunk/qpid/cpp ./bootstrap ./configure --prefix ~/qpidlocal make install cp ../java ant
Once this is done, you should be able to launch the most current qpidd
export LD_LIBRARY_PATH=~/qpidlocal/lib ~/qpidlocal/sbin/qpidd
Now…. build the example code:
cd ~/qmfExample/javaAgent # Edit the build.properties file to point to your local # installation ant install
You can now start up jboss, and run the example python script to access the bean
export PYTHONPATH=~/trunk/qpid/python cd ~/qmfExample/pythonConsole python ./qmfExample.py
Thats all there is. Python is now calling EJBs! Now… lets see how we did it. All the code below is in the qmfExample/javaAgent/src
directory. Lets first look at the Session Bean we created:
package qmf.example.ejb;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import org.apache.qpid.agent.annotations.QMFHide;
import org.apache.qpid.agent.annotations.QMFObject;
import qmf.example.BaseClass;
import qmf.example.DerivedClass;
@Stateless(name="ServiceBean")
@QMFObject(className="ExampleService", packageName="qmf.example.ejb")
public class ServiceClassBean implements ServiceClass
{
public BaseClass getBase(String name, String description) {
BaseClass bc = new BaseClass() ;
bc.setName(name) ;
bc.setDescription(description) ;
return bc ;
}
public DerivedClass getDerived(String name, String description, int count) {
DerivedClass dc = new DerivedClass() ;
dc.setName(name) ;
dc.setDescription(description) ;
dc.setCount(count) ;
return dc ;
}
public List findMany() {
ArrayList list= new ArrayList() ;
list.add(getBase("JarJar", "My Friend")) ;
list.add(getDerived("Binks", "Not My Friend", 12)) ;
ArrayList data = new ArrayList() ;
data.add(11) ;
data.add("Info") ;
data.add(getBase("Wotto", "Also My Friend")) ;
list.get(0).setStuff(data) ;
return list ;
}
@QMFHide
public void doHokeyPokey() {
System.out.println("Turn yourself around") ;
}
}
This is pretty normal except for 2 annotations. One, @QMFObject, gives
the name and package to expose. The second, @QMFHide, causes the method
to be ignored. The bean returns 2 classes, a base class and a derived
class. We have annotated the base class so that the marshalling code
knows about the derived class. This is a similar pattern to JAXB:
package qmf.example;
import java.util.ArrayList;
import org.apache.qpid.agent.annotations.QMFSeeAlso;
@QMFSeeAlso({DerivedClass.class})
public class BaseClass
{
.....
The final magic, is a beans.xml file which tells the JBoss microcontainer to start up the agent. Here is the code for that:
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="QPIDConnection" class="org.apache.qpid.client.AMQConnection">
<constructor>
<parameter>amqp://guest:guest@/?brokerlist='tcp://localhost'</parameter>
</constructor>
</bean>
<bean name="ServiceBean" class="org.apache.qpid.agent.ManagedEJB">
<property name="name">ServiceBean</property>
<property name="className">qmf.example.ejb.ServiceClassBean</property>
<property name="jndiLocation">qmfExample/ServiceBean/local</property>
</bean>
<bean name="QMFAgent" class="org.apache.qpid.agent.Agent">
<property name="label">agent</property>
<property name="sessionTransacted">false</property>
<property name="connection">
<inject bean="QPIDConnection" />
</property>
<property name="managedObjects">
<list elementClass="org.apache.qpid.agent.ManagedObject">
<inject bean="ServiceBean" />
</list>
</property>
<property name="registeredClasses">
<list elementClass="java.lang.String">
</list>
</property>
</bean>
</deployment>
As I said earlier, the deployer should make this easier. Specifically.. it will remove the need for the beans file. But.. this will work until the deployer is done.
Jun 13, 2009 @ 13:46:48
This post appears mad on Planet Fedora http://planet.fedoraproject.org/
Jun 14, 2009 @ 12:36:57
Yeah.. mis-matched pre tags. Should be fixed now. Thanks!
Jun 17, 2009 @ 14:19:22
Updated the example paths a bit based on some other languages I am adding to the example.
Now.. C# to EJB over QMF « Join the Kearneyville
Jun 19, 2009 @ 21:24:34
QMF#4: Ruby accessing EJBs running in JBoss « Join the Kearneyville
Jul 07, 2009 @ 14:36:41