Friday, January 15, 2010

Who is the best JPA Provider in WebLogic?

http://www.theserverside.com/news/thread.tss?thread_id=44219

Posted by: Gavin King on February 10, 2007 in response to Message #227266
And by the way - I'm a bit out of date, but the actual measurements I did a year or so ago of simple CRUD performance of Hibernate vs. Kodo gave a mixed bag of results. They are slightly faster on creation/destruction of the persistence context and on inserts, we are a bit faster on queries. For mass operations on many objects, they are faster if you use standard APIs, we are quicker if you use StatelessSession. Etc.

Nowhere did I find anything that was a big enough difference that you would prefer one product over the other on the basis of performance alone.

Which confirmed to me that the BEA marketing line of the time that "Kodo is faster than Hibernate" is just the usual marketing BS, which was my initial reaction.

Thursday, January 14, 2010

EJB3 Weblogic 10 and backward compability

(http://blog.sunfire.nu/2008/12/ejb3-weblogic-10-and-backward.html)

Been trying to develop EJB3s that will be hosted on a Weblogic 10 server, and some client applications that will be running on Weblogic 8.
Took me a while to figure out how to get the JDNI names and stuff right for the EJBs as well as how to be compatible with EJB2 spec (since Weblogic 8 and JDK1.4 doesn't support EJB3).

There are of course a million tutorials and examples to find using google, so that's were I started. Found one here to start with but I ended up getting ClassCastExceptions. Looking at the EJB3 specs I found the mappedName attribute of the @Stateless annotation, and after setting that I got my client code working. Since mappedName is vendor-specific the information will not be applicable if you're running a different application server.

package ejb;
public interface TestRemote {
public String echo(String s);
}
----------------------
package ejb;
import javax.ejb.*;

@Stateless(mappedName="Base")
@Remote(TestRemote.class)
public class TestBean implements TestRemote {
public String echo(final String s) {
return "echo: " + s;
}
}

The clients can now perform a lookup like this:

Properties p = new Properties();
p.put("java.naming.factory.initial","weblogic.jndi.WLInitialContextFactory");
p.put("java.naming.provider.url", "t3://localhost:7001");
p.put("java.naming.security.principal", "weblogic");
p.put("java.naming.security.credentials", "weblogic");
InitialContext ctx = new InitialContext(p);
TestRemote test = (TestRemote) ctx.lookup("Base#ejb.TestRemote");
test.echo("Hello");

After getting my clients to access the EJB3s (the clients were using WLS10 libraries and JDK6) and calling methods on them I moved on to get them to work with WLS8 clients.
This turned out to involve a little more effort, suddenly it wasn't enough to write POJOs and annotations.
First of all, we need to create a EJB2 equivivalent business interface for our EJB3 interface (TestRemote) that must extend javax.ejb.EJBObject and contain the same methods that must throw java.rmi.RemoteException.

package ejb;
public interface TestRemote2 extends javax.ejb.EJBObject {
public String echo(String s) throws java.rmi.RemoteException;
}

Second, we need a Home interface that the EJB2 client can lookup and use to create the EJB:

package ejb;
import java.rmi.RemoteException;
import javax.ejb.*;
public interface TestRemoteHome extends EJBHome {
public TestRemote2 create() throws CreateException, RemoteException;
}

Notice that the create method returns the EJB2 interface (of course...).
Finally, we update the bean class itself:

package ejb;

import javax.ejb.*;

@Stateless(mappedName="Base")
@Remote(TestRemote2.class)
@RemoteHome(TestRemoteHome.class)
public class TestBean implements TestRemote {
public String echo(final String s) {
return "echo: " + s;
}
}

Ok, we changed the Remote annotation to contain the EJB2 interface instead and we added the RemoteHome annotation as well to specify the Home interface to publish. Notice that we still implement TestRemote (not the EJB2 interface) so at least we don't have to worry about RemoteExceptions here.

The client code looks like this:

// Context setup as before
Object o = ctx.lookup("Base#ejb.TestRemoteHome");
TestRemoteHome home = (TestRemoteHome)PortableRemoteObject.
narrow(ctx.lookup("Base#ejb.TestRemoteHome"),
TestRemoteHome.class);
TestRemote21 test = home.create();
test.echo("Hello");

That's all there is to it.

Update after comments:
To enable both EJB3 and EJB2 beans you just add the interfaces in the @Remote annotation like this:
@Remote({TestRemote2.class, TestRemote.class})

Why use ejb-ref in web.xml?

The advantage is indirection. If the code directly references EJBs in your servlets through JNDI, it will work just when the JNDI name does not be changed during deployment.

By using an ejb-ref you create an alias for the bean. During coding, the alias is used to locate the beans home.

eg. context.lookup("java:comp/env/ejb/myBean");

The developer also creates an entry in the web.xml like this:

EJB remote reference:
<ejb-ref>
<ejb-ref-name>ejb/myBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<ejb-ref-home>some.package.MyBeanHome</ejb-ref-home>
<ejb-ref-remote>some.package.MyBeanRemote</ejb-ref-remote>
<ejb-link>MyAppEJB.jar#myBean</ejb-link>
</ejb-ref>
EJB local reference:
<ejb-local-ref>
<ejb-ref-name>ejb/myBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>com.myapp.session.MyBeanLocal</local>
<ejb-link>MyAppEJB.jar#myBean</ejb-link>
</ejb-local-ref>




On deployment, the deployer creates a mapping between the alias ejb/myBean and the JNDI name that the bean is actually deployed with. This will allows the deployer to change a beans' JNDI name without modifying the code (If you used JNDI directly, you have to modify it).

The name referenced in the ejb-link (in this example, myBean) corresponds to the <ejb-name> element of the referenced EJB's descriptor. With the addition of the <ejb-link> syntax, the <ejb-reference-description> element is no longer required if the EJB being used is in the same application as the servlet or JSP that is using the EJB.

In WebLogic, since the JAR path is relative to the WAR file, it begins with "../". Also, if the ejbname is unique across the application, the JAR path may be dropped and just put the bean name at there.

Mapping is vendor specific feature. For example, in WebLogic this is done in the weblogic.xml file.