Total Pageviews

Showing posts with label ejb. Show all posts
Showing posts with label ejb. Show all posts

Tuesday, July 10, 2012

Good examples of asynchronous method calls in EJB 3.1

Doing parallel processing in EJB containers before EJB 3.1 was a pain in the ass. You have to fiddle around with JMS and Message Driven Beans.
EJB 3.1 introduces asynchronous method calls and simplified the management of concurrently running tasks a lot. I found two pretty good examples how to use asynchronous method calls:

http://satishgopal.wordpress.com/2011/04/24/ejb-3-1-asynchronous-methods/
http://docs.oracle.com/javaee/6/tutorial/doc/gkkqg.html

Friday, January 20, 2012

Iterating over result list from a JPA query

Sometimes when using EJB 3.x, it is necessary to use JPA QL or SQL native queries to fetch objects from the database. It might be used to achieve better performance or to just fetch a particular set of attributes of the object but not the complete object with all its dependencies.

There's one thing you have to keep in mind when doing this: The result list containing the object will be an array of objects!

"The SELECT clause queries more than one column or entity, the results are aggregated in an object array (Object[]) in the java.util.List returned by getResultList( )"

Working example:
 Query query = manager.createQuery("SELECT v1.bitbit, v1.numnum, v1.someTime, t1.username, t1.anotherNum FROM MasatosanTest t1 JOIN MasatoView v1 ON v1.username = t1.username;");  
   
   List results = query.getResultList( ); // Fetches list containing arrays of object  
   
   Iterator it = results.iterator( );  
   
   while (it.hasNext( )) {  
   
     Object[] result = (Object[])it.next(); // Iterating through array object   
   
     Boolean first = (Boolean) result[0]; // Fetching the field from array  
   
     /* Likewise for all the fields, casting accordingly to the sequence in SELECT query*/  
   
   }  
   
   

There's is even the possibility to avoid casting completely by using a constructor expression with the appropriate arguments in the SELECT section:
 SELECT new org.somepackage.XEntity(x.a, x.b) FROM XEntity x  

Remember to declare the appropriate constructor.
The code fragments and the solution in this blog post was taken from this question on stackoverflow.


Saturday, June 27, 2009

Testing your EJB3 beans in an embedded EJB container using OpenEJB with Maven as build system

Intro

I am currently working on a private project implementing a web application using GWT as frontend and EJB3 as backend technology.
Testing my EJB3 beans using JUnit4 turned out to be very complicated. I had to manually inject all the required resources like EntityManager, EntityManagerFactory and all EJB3 beans the bean under test uses.
This may work for a simple project with a few beans but this will definitely not work for a huge project.
So I was looking for a better and less complicated way to test my beans.
Embedded Glassfish came to my mind, but this project isn't final yet, so I stumbled across a blog entry of Adam Bien's blog where he talks about OpenEJB and I thought just give it a try.
I use Maven as build system for all my projects so everything below this line just fits for Maven. If you use Ant or something different you may have to do other things to set up your testing environment.

Maven configuration

Using the OpenEJB embedded container is very easy. Just add the following dependency to your POM:

   <dependency>
      <groupId>org.apache.openejb</groupId>
      <artifactId>openejb-ejbd</artifactId>
      <version>3.1.1</version>
      <scope>test</scope>
   </dependency>

In my case it turns out that the dependency activeio-core version 3.0.0-incubator is not hosted in any publicly available maven repository (well at least not in those I use). So I grabbed it from here and pushed it into my running Nexus instance.
In case you use OpenJPA as your persistence provider you have to configure the Maven surefire plugin to use the OpenEJB Java Agent. This is described in detail on this OpenEJB site.

Necessary files

My project consists of three maven modules:
  1. project-entities (contains all JPA entities and the production persistence.xml under src/main/resources/META-INF)
  2. project-api (contains all session beans and services)
  3. project-webapp (the GWT web application)
In this article I concentrate on testing my session beans and services. So I will focus on the project-api module. It is absolutely important to create the file ejb-jar.xml under src/test/resources/META-INF in the project-api module.
Because I only work with annotations this file is nearly empty in my case. It just contains the following line:

<ejb-jar/>
 

In case you have configured a persistence.xml file under src/test/resource/META-INF of your module under test (in my case project-api) using RESOURCE_LOCAL I recommend to delete this file completely. In my case this file was interfering with the OpenEJB setup and all my beans were not deployed into the embedded container. Hence, my embedded tests were not working.

Configuring the OpenEJB embedded container for testing

Now it's time to configure the OpenEJB embedded container. This can be done in two ways. I will only explain the configuration in a JUnit base test class, so this can be used by all unit tests deriving from this class. There is another way in configuring the container using an XML file. Please consult the OpenEJB website for further details.
Like I said before, I am using Hibernate as persistence provider. The setup of the embedded container is done in a method annotated with the JUnit annotation @Before, so it get's called before a test is executed. You may wish to change this in a way it better fits into your environment (using @BeforeClass, etc ...)

  @Before
  public void initializeEmbeddedContainer() throws Exception {
    Properties properties = new Properties();
    properties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
        "org.apache.openejb.client.LocalInitialContextFactory");

    ....
    ....
    ....
    context = new InitialContext(properties);
  }

In the above code snippet the bold lines are important. They are responsible for starting the embedded container. There are a few more properties you have to set to get the embedded tests running. Now you have to override the settings you made in your persistence.xml for running in OpenEJB.
The following lines will do that for you:
 

   properties.put("puName", "new://Resource?type=DataSource");
    properties.put("puName.JdbcDriver", "org.hsqldb.jdbcDriver");
    properties
        .put("puName.JdbcUrl", "jdbc:hsqldb:mem:testdatabase");
    properties.put("puName.hibernate.dialect",
        "org.hibernate.dialect.HSQLDialect");
    properties.put("puName.hibernate.hbm2ddl.auto", "update");

    properties.put("puName.hibernate.show_sql", "true");
    properties.put("puName.hibernate.format_sql", "true");

puName stands for persistence unitname. Please replace this with the real name of your persistence unit. The lines in bold are necessary. I am using HSQL DB, but this should work with any JDBC database. Don't forget to let Hibernate create the DB schema for you, otherwise your tests will fail because of non existent tables.
There is just another configuration property you may want to use: Restarting the OpenEJB embedded container between tests to avoid strange side effects in your tests. This is done by setting the property:

properties.put("openejb.embedded.initialcontext.close", "destroy");

But be aware that this property is an undocumented feature and may change in further versions of OpenEJB. This Jira entry recommends to achieve the same effect in configuring the maven surefire plugin.
So the complete method to initialize your in-container tests will look like this:

  @Before
  public void initializeEmbeddedContainer() throws Exception {
    Properties properties = new Properties();
    properties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
        "org.apache.openejb.client.LocalInitialContextFactory");

    properties.put("puName", "new://Resource?type=DataSource");
    properties.put("puName.JdbcDriver", "org.hsqldb.jdbcDriver");
    properties
        .put("puName.JdbcUrl", "jdbc:hsqldb:mem:testdatabase");
    properties.put("puName.hibernate.dialect",
        "org.hibernate.dialect.HSQLDialect");
    properties.put("puName.hibernate.hbm2ddl.auto", "update");

    context = new InitialContext(properties);
  }
 

Setting up a unit test

The last thing to do now is getting your beans from the embedded container. This can be done in two ways. One way is to use a special OpenEJB annotation to inject the bean into your test class. As this is an elegant way I prefer to code this with plain old Java method calls using JNDI lookup, because the first solution will make your code depend on OpenEJB API.
This is how it works with local EJBs:

IServiceLocal localService = (IServiceLocal) getContext().lookup(ServiceImplLocal);

where IServiceLocal is the local interface of the session bean and ServiceImplLocal is the JNDI name of the bean implementation. The OpenEJB standard JNDI name for beans is {deploymentId}{interfaceType.annotationName}.
The deploymentId is the name of the EJB implementation (in our case ServiceImpl) and the interfaceType is Local, because the EJB under test is a local EJB.

Running your tests

Simply call
mvn clean test

Thursday, February 08, 2007

Timer problems in JBoss with TimerBeans


Since I updated to JBoss 4.0.4.GA I randomly receive the following execption in one of my applications:


23:22:19,812 ERROR [TimerServiceImpl] Cannot create txtimer
java.lang.IllegalStateException: Unable to persist timer
at org.jboss.ejb.txtimer.DatabasePersistencePolicy.insertTimer(DatabasePersistencePolicy.java:126)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
Caused by: java.sql.SQLException: Unique
constraint violation: in
statement [insert into TIMERS
(TIMERID,TARGETID,INITIALDATE,TIMERINTERVAL,INSTANCEPK,INFO) values
(?,?,?,?,?,?)]
at org.hsqldb.jdbc.Util.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
at org.jboss.resource.adapter.jdbc.CachedPreparedStatement.executeUpdate(CachedPreparedStatement.java:95)
at org.jboss.resource.adapter.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:251)
at



It turns out to be a problem with a TimerBean.
A solution is described in the JBoss JIRA: http://jira.jboss.com/jira/browse/JBAS-3380
To make is short:
The "localDB.script" file ($JBOSS_INSTALL_DIR/server/default/data/hypersonic) must be cleaned up by deleting all (or the particular) timer entries (INSERT INTO TIMERS ...). Those entries are inserted by JBoss and represent timers which should be executed after a server crash. Unfortunately the ID generator for inserting unique timer ids doesn't generate unique ids :-(

Thursday, June 15, 2006

Moving towards JBoss 4.0.4.GA

I decided to upgrade my JBoss 4.0.3.SP1 to the newest version 4.0.4.GA. I am only interested in the EJB3 container so I have chosen to use the installer package to download.
The installation is quiet easy using the installer. Just simply choose the EJB3 container and everything gets installed. But the hardest part is still in front of us.
My client application fails with different exceptions communicating with the server. Argh!! Yes of course, I had to update my jboss client libraries. So here is the list of necessary libraries to update:
  • jboss-j2ee
  • jboss-ejb3x
  • jboss-ejb3
  • jboss-annotations-ejb3
  • jboss-aspect-library-jdk50
  • jbossall-client
  • jboss-aop-jdk50-client
After this I tried to deploy my application to the server, but it failed because of a missing class. I don't have the stacktrace anymore, sorry. But it stated something about a missing class with a package name like org.apache.commons.discovery, so I decided to put the commons-discovery in version 0.2 - which I had from my previous JBoss installation - and put it into the directory $jboss_home\server\default\deploy\ejb3.deployer. That was the trick. Now it's working!