« - »

EJB Datasource Outside of the EJB Jar File

8 October 2010

Maybe I’m just getting old and slow, but I don’t remember having this much trouble finding out how to do something for quite some time. It seemed like such a normal, every-day requirement: build an EJB .jar file in such a way that I could configure the datasource reference externally, which would allow me to use these components in multiple applications without having to rebuild the EJB .jar uniquely for each independent use. Surely I was not the first person to have such a need. But after searching and searching, I starting to think that it just could not be done, to which I has the same response as this guy:

ahhh vinnie i feel your pain!

i’ve been looking for a solution to this for so long as well. and the solutions offered are always along the same lines.

i can’t believ an ‘ENTERPRISE’ component platform as JEE is supposed to be is so crumby. i guess they’ve only had six chances over what? ten years to get this right.

the fact that runtime configuration is embedded INSIDE the actual deployables and there is no way to override them is the biggest JEE spec joke.

even worse, when using EAR files, the database is hard coded inside a deployable of the deployable. so in the case above for an ear you’d have to unzip the ear file, possibly unzip every jar file, change one line in a descriptor, rezip everything and then redeploy for every seperate deployment. i have spent countless hours reading the specs trying to find the fix for this – as i simple could not BELIEVE there would be none for such an obvious situation.

and this is how its supposed to be? this is the best we can do? even for third party components supplied by someone else? still? in 2010? really? you’re serious?

hows this for a consumer product brochure – in order to change the channel on your tv, get a phillips head screwdriver and take the back off your remote control, pull apart the board and xxxxx….

Fortunately, though, it really can be done; there are just quite a few things that all have to line up in order for it to actually work. At least I was able to make it work on Glassfish 2.1.1 using a project composed of an .ear file that contained both a .war file and an EJB .jar file. Your mileage may vary, but here’s what I ended up with once I finally got all of the parts to play nice with each other:

.ear file
+- /lib directory
|  +- persistence.jar file
|     +- /META-INF directory
|        +- persistence.xml file
+- webapp.war file
+- ejb.jar file

First of all, you have to remove the persistence.xml file from inside the EJB .jar file. There should be no persistence.xml file in either the ejb .jar file, the webapp .war file, or even loose in the .ear file. The persistence.xml file should be located in the META-INF directory of its own independent persistence.jar file (choose any name that you like for the .jar, actually), which should then be place inside of a /lib directory, which should be placed at the root of the .ear file along side the webapp.war file and the ejb.jar file.

It is also important the that the persistence.xml file name the persistence unit explicitly, name the ejb.jar file explicitly, and itemize all entity bean classes. When it is all said and done, it should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
            http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
	<persistence-unit name="puName" transaction-type="JTA">
		<provider>oracle.toplink.essentials.PersistenceProvider</provider>
		<jta-data-source>jdbc/yourDatasourceName</jta-data-source>
		<jar-file>your-ejb.jar</jar-file>
		<class>your.entity.bean.package.SomeClass</class>
		<class>your.entity.bean.package.SomeOtherClass</class>
		<properties>
			<property name="some.property" value="true"/>
			<property name="some.other.property" value="4"/>
		</properties>
	</persistence-unit>
</persistence>

Inside of the .war file, I also placed an ejb reference in the web.xml file, and added an annotation to one of the servlets referencing the persistence unit name. The ejb ref was pretty standard stuff:

<ejb-local-ref>
	<ejb-ref-name>ServiceName</ejb-ref-name>
	<ejb-ref-type>Session</ejb-ref-type>
	<local-home/>
	<local>your.stateless.service.package.ServiceName</local>
</ejb-local-ref> 

… as was the servlet annotation:

    @EJB(name="ServiceName")
    @PersistenceContext(unitName="puName")
    private ServiceName serviceName;

In the EJB annotation, the value of the name parameter must match the value of the ejb-ref-name element in the web.xml. In the PersistenceContext annotation, the value of the unitName parameter must match the value of the name attribute of the persistence-unit element in the persistence.xml file.

That’s it. It took me forever to figure it all out, and some of the things that I have done here may not even be necessary, but once I got it to work, I stopped looking at it and moved on to other things. I just wanted to lay it all out here before I forgot, plus I hate to see someone else have to go through the same thing. Hope this saves someone that trouble!


http://blog.restafarian.org/2010/10/ejb-datasource-outside-of-the-ejb-jar-file/

Leave a reply

You must be logged in to post a comment.