Posts Tagged ‘ejb’

Test your EJBs with JMeter

Note: This is my first blog post on my newly upgraded WordPress blog (prior to thijaguar-tachometer.jpgs, I used Blogger). Hopefully everything goes OK!

Sometimes it’s helpful to do some performance benchmarks on your EJBs. There are a few different ways to do this, but I’ve found that Apache’s JMeter is an excellent tool for benchmarking. Unfortunately, JMeter doesn’t come with a general-purpose sampler for testing arbitrary EJBs. Luckily, it isn’t very difficult to create one.

For this article, I’m using the JBoss application server to host my EJBs. The process for using other containers should be quite similar.

1.) Create a factory to lookup your EJBs.

The first thing that you’ll probably want to do is create a simple singleton factory class to create instances of your EJB client for your test. I use something like the following:

public class MyServiceFactory {
  private static final Log log = LogFactory.getLog(MyServiceFactory.class);
  private static MyService service;
  private static MyServiceFactory me;
 
  private MyServiceFactory() { }
 
  static {
    MyServiceFactory.me = new MyServiceFactory();
  }
 
  public static MyServiceFactory getInstance() {
    return MyServiceFactory.me;
  }
 
  public MyService getService() {
    if (MyService.service == null) {
      // Get the remote interface of the music search service
      try {
        log.info("Loading the service...");
 
        // JNDI the old-fashioned way:
        Context ctx = new InitialContext();
        service = (MyService)ctx.lookup("MyAction/remote");
        if (service == null) {
          log.error("Didn't get the service!");
        }
      } catch (NamingException e) {
        log.error("Error looking up the remote service", e);
        return null;
      }
    }
    return service;
  }
}

2.) Write the test

Next, we’ll need to write the test itself. To do this, we’ll extend the AbstractJavaSamplerClient class in JMeter’s org.apache.jmeter.protocol.java.sampler package. This abstract class has a runTest method that we will override, and this method implements the actual test. We will also override the getDefaultParameters method to provide some reasonable defaults values which will be displayed in JMeter’s GUI application.

package us.mikedesjardins.demo.jmeter;
 
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
 
public class DigitalContentServiceEJBTestSampler extends AbstractJavaSamplerClient {
  public SampleResult runTest(JavaSamplerContext context) {
    SampleResult results = new SampleResult();
    MyService service = MyServiceFactory.getInstance().getService();
 
    results.sampleStart();
    Long param1 = context.getLongParameter("PARAM_1");
    String param2 = context.getStringParameter("PARAM_2");
 
    MyResult result = service.myMethod(param1, param2);
    if (result != null) {
       results.setSuccessful(true);
       results.setResponseCodeOK();
       results.setResponseMessage("'myResult:" + myResult);
    } else {
       results.setSuccessful(false);
    }
    results.sampleEnd();
    return results;
  }
 
  @Override
  public Arguments getDefaultParameters() {
    Arguments args = new Arguments();
    args.addArgument("PARAM_1", "4815162342");
    args.addArgument("PARAM_2", "Iculus");
    return args;
  }
}

3.) Setup JMeter

JMeter’s extra libs directory is ${JMETER_INSTALL_LIB}/lib/ext. Into that directory you will need to copy any jars that your EJB client will need. In you’re using JBoss, you will want to copy the jbossall-client.jar into that directory as well (for the JNDI client and other remoting goodies) – presumably other application servers have similar client jar files available.

When you fire up JMeter, your new sampler should appear in the Samplers menu. Enjoy!

Photo Credit: Bill Jacobus

Tags: , , ,
Posted in blog | 1 Comment »


Don’t Ignore serialVersionUID

Okay,I admit that this one should have totally been obvious to me long ago. But I’m still a bit of a JEE newcomer (been doing it for almost five years), so perhaps I can be forgiven.

If you do a lot of ORM or EJB remoting, you probably deal with a lot of Serializable classes. And you’re probably used to the annoying warning message that you see all the time in your IDE when you’re working with Serializable classes:

The serializable class BlaBlaBla does not declare a static final serialVersionUID field of type long BlaBlaBla.java myProject/src/main/java/us/mikedesjardins/foo/domain/entity line 44

If you’re like me, you roll your eyes and politely add a @SuppressWarnings(“serial”) to the top of the class definition (or, worse, you just shut the warning message off in your IDE altogether. Even I don’t do that!). You reason with yourself that current versions of Java conveniently and automatically compute the serialVersionUID at run-time, so there’s no need to bother with the formality of a version number on your class – it’s just a nuisance holdover from days of Java yore.

IT’S A TRAP!
Now that I’ve found myself well into a new project with this lazy philosophy, I’m starting to run into problems. I have a client of my EJB that uses one of these Serializable objects, and I’m finding that when I make the most trivial changes to my shared classes, I need to compile both the server and the client components. The two components that were supposed to be loosely coupled are now hopelessly intertwined. So I did some further research on how the JVM computes the ad-hoc serialVersionUID at runtime when it isn’t provided.

This article over at JavaWorld does a far better and more thorough job of explaining it than I will. In a nutshell, backward-compatability with respect to serialization and de-serialization is a lot less fragile than the cases that the serialVersionUID generation is protecting you against. That version generation algorithm computes an SHA hash based on the class name, sorted member variables, modifiers, and interfaces.

In reality, serialization and de-serialization generally only breaks when one of the following things happens to your class (from the aforementioned article at JavaWorld):

  • Delete fields
  • Change class hierarchy
  • Change non-static to static
  • Change non-transient to transient
  • Change type of a primitive field

Ensure Minimal Coupling Between Components
To ensure that your components which use Serialization have minimal runtime dependencies on each other, you have two options:

  • Declare a specific serialVersionUID, and update it whenever you make a change that breaks backward compatability.
  • Don’t rely on any classes for use as transfer objects which will potentially change. This one is pretty obvious, but sometimes you will be surprised down the road at which classes are modified more often than others.
  • Don’t use your own objects at all when transferring data. Instead, rely on classes like Integers, Strings, or HashMaps to shuttle data around among components. (Obviously, protocols like SOAP and REST rely on XML documents for this to ensure maximum de-coupling, but you’re presumably using something like EJB remoting to avoid the complexity or overhead of these protocols).

Photo Credit: Mike Johnson

Tags: , , ,
Posted in blog | 1 Comment »


Configure Spring to automatically re-connect to your EJBs

If you have a service that is a client of a remote EJB, you may have run into the situation where the EJB server shuts down and restarts. When this happens your EJB client may need to be restarted as well, in order to re-discover and reconnect to the EJBs; otherwise you’ll end up with connection exceptions in the client.

If you’re using Spring to autowire your EJB clients, it’s quite easy to configure the service so that the home interface will refresh on connection failures. Note that if you’re using EJB3, you will need to upgrade to at least version 2.5.5 of Spring. There is a bug in earlier versions of Spring which prevented this technique from working with EJB3.

In your spring file, make sure you configure your slsb references to have cache-home disabled, and refresh-home-0n-connect-failure thusly:

<jee:remote-slsb id="myService" jndi-name="MyService/remote"
        business-interface="us.mikedesjardins.services.MyService"
        cache-home="false" lookup-home-on-startup="false"
        home-interface="us.mikedesjardins.services.MyService"
        resource-ref="false" refresh-home-on-connect-failure="true">
    <jee:environment>
           <!-- Include any relevant environment settings here -->
    </jee:environment>
</jee:remote-slsb>

With this, you should be able to restart your EJB hosts without needing to restart your EJB clients!

Photo Credit: Wanko

Tags: , ,
Posted in blog | Comments Off