OpenEJB Application Composer, new features: JAXRS, JAXWS, @Classes…


Go further in standalone webapp testing

It always has been possible to use OpenEJB to test small part of webapps in embedded mode but it needed to perfectly know all internals…mainly means nobody was doing it excepting for some particular advanced tests in OpenEJB itself.

But these days REST, JAXWS etc testing in standalone can be very interesting when working on an issue or simply to get very fast test executions.

It already works for EJBContainer part but well, it is not the faster and there is some place between Arquillian testing (which is fast regarding absolute time but slow compared to ApplicationComposer since this last one is closer to OpenEJB), EJBContainer (too “main()” oriented) and ApplicationComposer (it needs some few knowledge of OpenEJB model classes but then you get the control of what is deployed and the benefit of the execution speed).

So the idea was to add some sugar in OpenEJB + ApplicationComposer to let JAXRS tests be trivial.

Quick reminder on ApplicationComposer

ApplicationComposer is a JUnit runner so you need to decorate your test class with

@RunWith(ApplicationComposer.class)

Then you need to define in your class

  • one of more modules to deploy (@Module)
  • optionally some container configuration (@Configuration)
  • your tests as usual (@Test)

Modules can be an array of classes (Class<?>[]) so OpenEJB will discover the application (that’s the lazy way) but the idea was mainly to create a “model” class (WebApp, EjbJar, …).

@Classes annotation

Today we can use OpenEJB *Modul classes in Application @Module methods but it is quite confusing to use it since that’s really internal part of OpenEJB. So if you can stick to model classes it is better.

Ok but how do I define classes of my application since for instance WebApp object doesn’t contain any information about it?

That’s why @Classes annotation was added: decorate your @Module method with @Classes and specify classes as parameters. For instance:

@Module
@Classes({ Foo.class, Bar.class })
public WebApp myWebApplication() { .... }

@EnableServices

Then when you test an application using remote services (jaxrs, jaxws, ejbd…) you generally add a @Configuration method to activate the startup of these services.

@Configuration
public Properties configuration() {
    final Properties p = new Properties;
    p.setProperty("openejb.embedded.remotable", "true");
    return p;
}

You can now use @EnableServices as an alias for this method.It seems nothing but this way code is generally more readable.

Not convinced? Ok let look this annotation parameters.

value() – or how to select needed services

The value parameter is an array of names of services needed for your test. So for instance:

@EnableServices({ "httpejbd", "cxf-rs" })

will activate the JAXRS service (cxf-rs and it needs httpejbd so we define both).

Ok that’s fine but not very very user friendly. That’s why we added aliases:

@EnableServices(&quot;jaxrs&quot;)

will do the same :).

So currently available aliases are:

  • jaxrs: activate rest (jax-rs is supported too)
  • jaxws: activate soap webservices (jax-ws is supported too)
  • ejbd: activate remote ejb support through the ejbd protocol

httpDebug()

Another interesting shortcut added is the httpDebug() parameter. It replace this configuration code:

properties.setProperty("httpejbd.print", "true");
properties.setProperty("httpejbd.indent.xm", "true");
properties.setProperty("logging.level.OpenEJB.server.http", "FINE");

What does it do?

It simply prints all request/response done through httpejbd HTTP transport (so mainly services previously cited).

It can be a very easy way to see SOAP data for instance.

Some sugar in WebApp class

WebApp class got some more methods too:

  • contextRoot(String): define under which context the webapp should be deployed
  • addServlet(String, String, String…): add a servlet defining it name, class and (optionally) mappings
  • addInitParam(String, String, String): add an init parameter to a servlet from its name, key, value (the servlet has to exist)

Put it all together

Here a small sample (taken from OpenEJB trunk) where a simple REST Application is defined and tested.

package org.apache.openejb.server.cxf.rs;

import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.openejb.jee.WebApp;
import org.apache.openejb.junit.ApplicationComposer;
import org.apache.openejb.junit.Classes;
import org.apache.openejb.junit.EnableServices;
import org.apache.openejb.junit.Module;
import org.apache.openejb.server.cxf.rs.beans.MyRESTApplication;
import org.apache.openejb.server.cxf.rs.beans.RestWithInjections;
import org.apache.openejb.server.cxf.rs.beans.SimpleEJB;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import java.io.InputStream;
import java.io.StringWriter;

import static org.junit.Assert.assertEquals;

@EnableServices("jax-rs")
@RunWith(ApplicationComposer.class)
public class SimpleApplicationTest {
    public static final String BASE_URL = &quot;http://localhost:4204/foo/my-app&quot;;

    @Module
    @Classes({ RestWithInjections.class, SimpleEJB.class }) // scan these classes
    public WebApp war() {
        return new WebApp() // define rest Application
                .contextRoot("foo")
                .addServlet("REST Application", Application.class.getName())
                .addInitParam("REST Application", &quot;javax.ws.rs.Application&quot;, MyRESTApplication.class.getName());
    }

    @Test
    public void first() {
        String hi = WebClient.create(BASE_URL).path(&quot;/first/hi&quot;).get(String.class);
        assertEquals("Hi from REST World!", hi);
    }
}
Advertisements

12 thoughts on “OpenEJB Application Composer, new features: JAXRS, JAXWS, @Classes…

  1. Andrew Finch

    Hi I’m just starting to run some tests with this set up. My problem is that @Module seems to run on each and every test. This takes about 3 – 5 seconds each time and soon adds up. Is there a way I can have the ejb init run once?

    Reply
    1. rmannibucau Post author

      Yeah and that’s a cool stuf which allows us to be very well integrated with Mockito for instance (compared to arquillian).

      Did you try arquillian adapter btw? maybe it matches more your need.

      Reply
  2. Andrew Finch

    Not yet. I’ve been playing about with openejb and was struggling as we have a mix of EJB2 & 3. I came across this and some related posts regarding using @Module and this seemed to be the solution. However I can’t continue if each test takes 3-5 seconds. I’ll have a look at arquillian.

    Reply
    1. rmannibucau Post author

      well then it depends what you put in @Module (maybe get in touch with the openejb mailing list)

      basically arquillian should make it faster IMO

      Reply
  3. Andrew Finch

    So tried out the Arquillian start up and get the following org.jboss.weld.exceptions.DefinitionException: Exception List with 1 exceptions:
    Exception 0 :
    java.lang.RuntimeException: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial

    I seem to be going from one problem to another.

    Reply
  4. Andrew Finch

    Weld – because that was the getting started tutorial tells me to do. I am a bit confused as to where openejb now comes from. It is not mentioned in the tutorial and I am trying arquillian because of issues with openejb.

    Where should the aquillian.xml be placed and do I need to add dependencies on openejb and System props like System.setProperty(Context.INITIAL_CONTEXT_FACTORY, “org.apache.openejb.core.LocalInitialContextFactory”);
    System.setProperty(“openejb.deployments.classpath.exclude”, “.*”);
    System.setProperty(“openejb.deployments.classpath.include”, “”);

    Thanks

    Reply
  5. Andrew Finch

    Exactly the same issue:

    INFO – Adding OpenWebBeansPlugin : [CdiPlugin]
    INFO – class: org.apache.deltaspike.core.impl.exception.control.extension.ExceptionControlExtension activated=true
    INFO – class: org.apache.deltaspike.core.impl.message.MessageBundleExtension activated=true
    SEVERE – CDI Beans module deployment failed
    java.lang.RuntimeException: javax.naming.NoInitialContextException:

    Reply
  6. rmannibucau Post author

    do you have any arquillian enricher dependency? if yes just drop them

    if not please just move the discussion over openejb users mailing list, it will be more appropriated 😉

    Reply
  7. Andrew Finch

    I’m literally copying the code the tutorials and from the svn you just posted. Thanks very much for your help. Will tackle this another day.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s