Session and Entity Beans with Scala!

The most of J2EE applications developed are usually web + database applications. There’s usually a web framework like Java Server Faces used and jdbc, JPA, Hibernate, etc are used for the database interactions.
I’m on the quest to do all the above in Scala, and make life simpler because of Scala’s concise way of writing code and its various other advantages which have been elaborated on elsewhere.
So for my web application which was a Java EE 6, I chose:
JSF 2.0 for the MVC framework.
JPA for the database interactions.
Session Beans to interact with the Entity Beans.
Glassfish v3 prelude application server
Java derby Database(default)

All of the web pages were written in xhtml. The application I chose to rewrite was Dr. Cay Horstmann’s Simple Quiz web application from his blog here.

The design of the application is simple. It is a simple quiz based on common known facts of Java. So there’s a question and choices(using radio buttons) and at the end, there’s a page which displays the score.
For this, we use:
1. A managed bean.
2. A session bean.
3. 2 Entities.
4. index.xhtml and done.xhtml pages(one for the quiz, one for the score at the end)

To begin with, I simply rewrote all the Java code in Scala. Including the annotations used. However, the manner in which Scala annotations are written are different. For example, in JSF 2.0, the managed bean is annotated like this(thats right! No XML!):


@ManagedBean(name = "quiz")
@SessionScoped
public class QuizMB

In Scala:


@ManagedBean{val name = "test"}
@SessionScoped
class ScalaMB 

Again, in Java:

@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)    
private Collection<Choice> choices = new ArrayList<Choice>();

In Scala((the targetEntity is only necessary to work around a bug in 2.7 that will be fixed in 2.8 apparently):

@OneToMany{val cascade = Array(CascadeType.ALL),val targetEntity=classOf[Choice], val fetch = FetchType.EAGER } 
var choices: java.util.List[Choice] = new java.util.ArrayList[Choice]();

And my Session Bean looked like this:


@Stateless class QuizSB {

 @PersistenceContext private[this] var em: EntityManager = _

 def getQuestions():JList[Question]= {
 ................
 }

 def makeQuestions() {
 ...........
 }

def makeQuestion( _text:String, answer:String, otherChoices:String*) {
 ...........
 }
}

I then tried to access an instance of the SessionBean through the ManagedBean like this:

@ManagedBean{val name = "test"}
@SessionScoped
class ScalaMB {

@EJB private[this] var slsb : ScalaSB = _

def getCurrentQuestion():Question = {
 questions = slsb.getQuestions();
 questions.get(currentQuestionIndex);
}
...........
}

And my JPA beans were written as I have done before. A more detailed explanation of JPA for scala can be found here.

So this didnt work! No matter what I tried. Some of the things I tried:
1. Using setter injections instead of field injections for the session and entity beans.
2. Using JSF 1.2, incase the managed bean annotations were not being processed properly.
3. Looked at the bytecode to check the annotations were processed properly.
4. Looked at the glassfish code which handles the dependency injection.

I hung around on the #scala irc room on freenode asking questions. Dr. Horstmann asked around on java.net and after a while, I was very frustrated that a lot of experimentation was leading to little or no progress.
Dr. Horstmann then figured out from looking at this blog that the session bean implementing an interface and being annotated @Local would work! We then realized that we dont even need the interface, we just need to use a @LocalBean annotation, make sure the scala-library.jar was available properly and it would work!
So the final version of the session bean looked like this:


@Stateless 
@LocalBean 
class ScalaSB {

 @PersistenceContext private[this] var em: EntityManager = _

 def getQuestions():JList[Question]= {
 ................
 }

 def makeQuestions() {
 ...........
 }

 def makeQuestion( _text:String, answer:String, otherChoices:String*) {
 ...........
 }
}

To keep the process of deploying the war to glassfish simple and reliable, I wrote an ant script for it instead of relying on Eclipse to do the job for me.

So after 2 months of working on an already functional Java web app and getting it to work with Scala, whats next? 🙂
Well, whatever is next, will be easier since I’ve already figured out most of the kinks in the process. Or I hope I have…

Advertisements

Ant for Scala!

Ant has come out with a “scalac” task which compiles scala code. Since I did not want to rely on Eclipse to compile my scala code and build jars, etc, I decided to write my own Ant script to automate the process.

To begin with, we need to set the required properties:

I used a build.properties file to set scala.home value.

<property name="scala-compiler.jar" value="${scala.home}/lib/scala-compiler.jar"/>
<property name="scala-library.jar" value="${scala.home}/lib/scala-library.jar"/>

Then we define the scala classpath and the scala compiler command:

<path id="scala.classpath">
<pathelement location="${scala-compiler.jar}"/>
<pathelement location="${scala-library.jar}"/>
</path>

<taskdef resource="scala/tools/ant/antlib.xml">
 <classpath refid="scala.classpath"/>
</taskdef>

This is the main scalac target, here since I have some xml dependencies for my code, I copy them over to the build directory.
Then I compile the scala classes using the scalac ant task. Incase we want to mix scala and java code in the same project, I also have a javac target. Eclipse currently wont allow people to mix java and scala code, so this is cool.

<target name="compile" depends="prepare">
 <copy todir="${build.dir}/WEB-INF/classes">
 <fileset dir="${src.dir}">
 <include name="**/*.xml"/>
 </fileset>
 </copy>
 <scalac srcdir="${src.dir}" destdir="${build.dir}/WEB-INF/classes" classpathref="build.classpath">
 <include name="**/*.scala"/>
 <include name="**/*.java"/>
 </scalac>
 <!-- When we mix Scala and Java... -->
 <javac srcdir="${src.dir}" destdir="${build.dir}/WEB-INF/classes" classpathref="build.classpath">
 <include name="**/*.java"/>
 </javac>
 </target>
 

I build a war and deploy this war in the Glassfish server, so I have a target to build the war.

<target name="package" depends="compile">
 <jar jarfile="${deploy.war}">
 <fileset dir="${web.dir}"/>
 <fileset dir="${build.dir}"/>
 </jar>
</target>

Figuring all this out from the distributed help online was time consuming and painful, so I’m glad I can share :-).