Tuesday, June 7, 2011

Mixing J2EE 6 and Scala, a first shot

I must confess I do admire a lot people recognized as craftsmen, all from different domains like Martin Fowler, James Coplien, Uncle Bob,Martijn Verburg, Martin Odersky, Jonas Boner. I like to follow Corey Haines adventures, listen to Venkat Subramaniam presentations... Apologies to the many others I forget.
In the desert land of french IT service it is hard to get satisfaction in our everyday projects, and we have very few opportunities to cross the path of such masters . Personally my only satisfactions come from my own learning from the masters... alas from book, videos, articles.Few chats with one of them in a twitter exchange is worth all the gold on earth.
Stop self-pitying, hopefully, all the time out of the daily job can be dedicated to exploration, discovery...and blog buddies =D

Recently we tried o to promote J2EE 6, hoping that the current client would accept to finally switch to a universally adopted standard, we once more had to start dealing with a mess, some big ball of muddy mixed services and strange God objects. Tough play. Fortunately J2EE 6 is lighter (pruning), easier to use (optional XML, more AOP), richer in terms of API, really more business oriented than the 5.0 level was,  and it really gazes to a brighter cloudy future.
Naturally, I came to acquire a copy of a J2EE 6  book in order to upgrade my knowledge from the 5.0 version up to the 6.0 one, in a more friendly approach. I chose Antonio Goncalves' Beginning JavaEE6 with GlassFish 3, 2nd Edition. Don't be foolished by the title. Although every naive java developer can start with the content, every astute J2EE developer can find in almost every page valuable information. Reading this gold mine will help you in grabbing good habits and fully adopting the 6.0 standard peacefully. So, this is a good way to escape from the everyday routine.

As I promised myself to try to deliver something on a regular base(shame on me I am late, too few hours during the day), I did not want to re-do a carbon copy of Mr Goncalves book content. There are still so many presentations exposing J2EE6 and its benefits.
Like a lot of developers I have some difficulties in self organization so I planned to work on a kind of small personal planning board (very, very light kanban one). A J2EE application would be a good approach. In the mean time it came to me how difficult it was to study so many things in parallel (too many books). I have started practicing Scala, upgrading to J2EE6, recently started playing with Clojure, and still gazing to Lisp and Erlang

Why not gathering the J2EE6 adventure and the Scala one, for a while ? It may be ambitious. Maybe not. So before even trying to attempt  a Reenskaugh/Coplien DCI approach, selecting my Use Cases, identifying the Roles, planning some form of architecture, I have to set up an environment, a working skeleton as defined by Nat Pryce and Steve Freeman in Growing object Oriented software guided by tests. This approach would allow me to define a broad picture of a working environment mixing Scala and J2EE 6.

How can I start ? The most important thing to do is to start. After all incredible people like David Pollack must have been starting somewhere before becoming experts in application servers design like Lift.

I want to work in a J2EE6 environment using the Scala language. So let set a Maven 3.0 environment to work with my IntelliJ 10.5. I am going through this experience the hard way: I will set the dependencies as the sum of all the dependencies needed both in a J2EE project, and inScala project. For a very first baby step I will focus on creating an entity, paired with some managing EJB service. What I want is a working shell. An embedded environment for TDD. Second step (I hope in some upcoming article) will be to make the stuff deployable.

Let the entity be an elementary task, then I will create a task service.

I want to work with J2EE, so I may need the following dependencies:


        
            
                org.eclipse.persistence
                javax.persistence
                2.0.3
            
            
                org.eclipse.persistence
                eclipselink
                2.2.0
            
            
                org.glassfish
                javax.ejb
                3.1
            
            
                org.glassfish.extras
                glassfish-embedded-all
                3.1
                test
            
            
                org.apache.derby
                derby
                10.8.1.2
            
            
                junit
                junit
                4.8.2
                test
            
            
                org.scala-lang
                scala-library
                2.8.1
            
        
    

The javax.persistence and javax.ejb dependencies reference the J2EE standards definitions. The eclipse link dependency is the JPA 2.0 implementation I chose, following Antonio's recommendations.

For test scope only I set a reference to the Glassfish embedded container. The embedded container appeared in J2EE 6 in order to simplify the development of unitary tests on EJB components but in a standard J2SE context providing the same managed environment - so facilities (transaction, CDI, AOP, security...) -as the one found into application servers.

The Scala library is the 2.8.1 as I have to work with the Scala Maven plugin. Discussing about plugins configuration I defined the following build configuration:


        src/main/scala
        src/test/scala
         
      
        ${project.basedir}/src/main/resources
      
    
    
      
        ${project.basedir}/src/test/resources
      
    
        
            
                org.scala-tools
                maven-scala-plugin
                
                    
                        
                            compile
                            testCompile
                        
                    
                
                
                    2.8.1
                
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                2.3.2
                true
                
                    1.6
                    1.6
                
            
            
                org.apache.maven.plugins
                maven-jar-plugin
                2.3.1
            
        
    

Well, this is really a brute force approach. I defined all I think I needed and chose to work into scala directories.

In order to avoid download problems, I selected the set of following repositories:


        
            UK-plugin
            http://uk.maven.org/maven2/
        
        
            scala-tools.org
            Scala-tools Maven2 Repository
            http://scala-tools.org/repo-releases
        
    

    
        
            glassfish-maven-repository.dev.java.net
            GlassFish Maven Repository
            http://download.java.net/maven/glassfish
        
        
            UK
            http://uk.maven.org/maven2/
        
        
            EclipseLink Repo
            http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo
        
        
            scala-tools.org
            Scala-tools Maven2 Repository
            http://scala-tools.org/repo-releases
        
    

Fine we are ready to start ! IntelliJ starts up, recognizes my Scala facets, So far, so good, happy camper I am.

I need a task. I want to persist it and reload it. For starting purpose, let say my task will have a title and of course an id. The test cases are defined as

import org.junit.Test
import org.junit.Assert._

class TestTask {

  @Test
  def id_WithTestValue_ShouldBeBound() {
    val task = new Task
    task.id = 17
    assertEquals(17, task id)
  }
  
  @Test
  def title_WithTestValue_ShouldBeBound() {
    val task = new Task
    task.title = "myTitle"
    assertEquals("myTitle", task title)
  } 
  
}

This leads me to the following Task definition template:

import javax.persistence._

@Entity
@NamedQuery(name = "findAllTasks", query = "SELECT t FROM Task t")
class Task {

  @Id@GeneratedValue var id: Long = 0
  @Column(nullable = false) var title: String = null
}

For clarity purpose, as a first shot, I chose to annotate my Scala fields. As Scala definitions are short, I found more elegant to leave the annotations on the same lines as the field declarations.
Naturally I flagged the definition template with the @Entity annotation. Then I cheated, anticipating a named query dedicated to the selection of all persisted tasks.
How fine and simple is this class template definition, all the beauty of Scala in the uniform access principle application: "It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove" (A. de Saint Exupery)

Hurrah, I've got an entity... written in Scala.

Now I want a service to manage this basic skeleton task. How will I query the service in an embedded mode ? I need this very nice stuff introduced in J2EE 6 and destined to ease the integration tests: an embedded EJB container !!! As a reference implementation, Glassfish does provide one (the purpose of the reference in the testing scope).
All I have to to then, is to :
  1. start the embedded container
  2. find my service through JNDI lookup
  3. persist my task
  4. assert my task id has been set
  5. reload my list of persisted tasks
  6. assert my list is not empty

So be it:

import org.junit.Test
import javax.ejb.embeddable.EJBContainer
import com.promindis.planning.entities.Task

import org.junit.Assert._
import java.util.List

final class TestTaskService {
  @Test
  def createTask_WithTestTask() {
    val ec = EJBContainer.createEJBContainer
    val ctx = ec.getContext

    val task = new Task
    task.title =   "testing task"

    val service: TaskEJB = ctx.lookup("TaskEJB").asInstanceOf[TaskEJB]
    service.createTask(task)

    assertNotNull(task id)

    val foundTasks: List[Task] = service.findAllTasks()

    assertNotNull(foundTasks)
    assertEquals(1, foundTasks size)


    ctx.close()

  }
}

Compilation error ! Of course, I must create the service. The solution comes easilly, thanks to the J2EE 6 AOP approach:

import javax.ejb.{LocalBean, Stateless}
import javax.persistence.{EntityManager, PersistenceContext}
import com.promindis.planning.entities._
import java.util.List


@Stateless
@LocalBean
class TaskEJB{
  @PersistenceContext(unitName = "planningPU") private var em: EntityManager = null

  def findAllTasks(): List[Task] ={
      val query = em.createNamedQuery("findAllTasks", classOf[Task])
      query.getResultList
  }

  def createTask(task: Task) {
    em.persist(task)
  }
}

The service is flagged as a stateless local bean, hosting an injected entity manager (Dependency injection is cool when sticking to a standard).
Because I don't know how to proceed for now, I decided not to wrapp the java List in a Scala one (maybe you can help me on that point)

On behalf of the service, the container will manage the transactions during the entity manager invocations.
In upcoming steps I will want to query my service remotely. In a standard Java approach, this would require the definition of an interface flagged with a @Remote annotation. But we know that a 100% abstract Scala trait compiles as an interface.

Let's make a try:

import javax.ejb.Remote
import com.promindis.planning.entities.Task
import java.util.List

@Remote
trait TaskEJBRemote {
  def findAllTasks() : List[Task]
  def createTask(task: Task)
}

Easy, so our service becomes:

import javax.ejb.{LocalBean, Stateless}
import javax.persistence.{EntityManager, PersistenceContext}
import com.promindis.planning.entities._
import java.util.List


@Stateless
@LocalBean
class TaskEJB extends TaskEJBRemote {
  @PersistenceContext(unitName = "planningPU") private var em: EntityManager = null

  def findAllTasks(): List[Task] ={
      val query = em.createNamedQuery("findAllTasks", classOf[Task])
      query.getResultList
  }

  def createTask(task: Task) {
    em.persist(task)
  }
}

One minute, I have named a persistence unit to bind to the entity manager. So I need a persistence.xml file.
Easy said, (not-so)easy done:


    
        org.eclipse.persistence.jpa.PersistenceProvider
        com.promindis.planning.entities.Task
        
            
            
            
            
            
            
            
        
    


Although it is embedded, we are still working with a container, so the transaction type appears to be JTA. The logging level is fixed to FINE as I like to understand what happens.
Note that the database connection properties makes part of the j2ee 6 standard:

  • javax.persistence.jdbc.driver
  • javax.persistence.jdbc.url
  • javax.persistence.jdbc.user
  • javax.persistence.jdbc.password

I chose a drop-and-create-tables ddl-generation schema so to get rid of my database table after test.

Everything's ready. Engage. I open a command console and hit

mvn clean test

Test is automatically run. I have a test failure. Ah right. Some problem with the name service binding. Since J2EE 6, apparently, an agreement has been found onto a global uniform naming convention into the JNDI namespace:

java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>]

Riiiight . Logs in my console give me a hint I would not have guessed alone:

Portable JNDI names for EJB TaskEJB : [java:global/classes/TaskEJB!com.promindis.planning.services.TaskEJBRemote, java:global/classes/TaskEJB!com.promindis.planning.services.TaskEJB]

I replace it with the second defintion
val service: TaskEJB = ctx.lookup("java:global/classes/TaskEJB!com.promindis.planning.services.TaskEJB").asInstanceOf[TaskEJB]

relaunch ...and it works !!!

For the moment I have to trust my environment when it tells me he ran the test, persisted and re-loaded my task. But a real complete environment requires to be able to produce a fully deployable application set >_<.
This will be the next step and I will then be able to run an external client and create records in more permanent database.

One moment, before going to bed, I want to check my remote interface (my Scala trait) is really compiled as an interface. After running:

javap -p TaskEJBRemote.class

I get this:

public interface com.promindis.planning.services.TaskEJBRemote {
 public abstract java.util.List<com.promindis.planning.entities.Task>findAllTasks();
 public abstract void createTask(com.promindis.planning.entities.Task);
}

Good!!!

So we have seen that the promise of a more universal JVM is not only a promise. It does still require some work to do but we are on our way.

I am tired and need four, five hours sleep.

Be seeing you !!!!

3 comments:

Globulon said...

I just had an interesting exchange on twitter with Heiko Seeberger from Typesafe who was kind enough to read the article.

He pointed out - quoting - that "using #Scala for #JEE 6 won't work for real world examples. At least not for CDI." than that
"The #Scala compiler creates too many public fields / final public methods for proxy based solutions like CDI."

I really thank him very much about this fruitful exchange. This will encourage me to go deeper into the exploration of CDI into a more standard way.
The richness of this exchange is very valuable and will guide me into my upcoming experimentation.

Martijn Verburg said...

Useful post - was able to utilise some of the Maven settings for the book examples :-)

Globulon said...

Thank you really. Glad you could use some Maven settings, because I always The Well-Grounded Java Developer MEAP at hand :-).

Post a Comment