Bringing Scala into the Java EE Space

Merging Scala and CDI using SBT

DanielHinojosa
Merging-Scala-and-CDI-using-SBT

JAXconf speaker Daniel Hinojosa previews his ‘Functional Programming in Scala with CDI’ session.

JAXConf will take place in San Jose next month, and as
part of the conference, co-founder of the Albuquerque Java User’s
Group in Albuquerque, Daniel Hinojosa will present his ‘Functional
Programming in Scala with CDI’ case study, in which he will look at
merging the Scala programming language with CDI. In this article,
Daniel Hinojosa gives us a taster of what to expect from his
JAXconf session, as he looks at getting a CDI implementation to
work with SBT.

There is no denying that Scala is a new language to be reckoned
with. With more developers trying and settling on the language, it
can’t be ignored. Given the new circumstances we have an important
question – “How well does Scala work in the new Java EE space, if
at all?” At JAX 2011 in San Jose, I will be presenting a case study
entitled “Functional Programming in Scala with CDI”. My aim is to
merge these two technologies which have essentially been incubated
in their own ecosystems, and publish the results.

Some of the issues I want to investigate:

1. How purely functional can you operate in CDI?

2. Can you inject reuseable functions with ease in CDI?

3. Is there hindrance in using Scala with Mojarra JSF and AJAX
frameworks?

4. Do functional design patterns work in the CDI
environment?

5. Can integration and acceptance testing in Scala + CDI
+Arquillian be used with popular Scala testing frameworks like
ScalaTest, Specs, and ScalaCheck?

6. Can a CDI implementation work with SBT (Simple Build Tool)
and how will it compare to Maven?

7. Do Scala structures like implicit work in CDI?

This article will describe line item 6, and I am happy to report
that it has been successful.

What is SBT?

Simple Build Tool (SBT for short) is a Scala-based build system,
completely developed in Scala. SBT has an extremely low learning
curve to set up and configure. It is an Ant, Maven, Buildr
competitor used exclusively for Java and Scala projects. SBT comes
included with all the major testing frameworks and tools, including
the ones we will be covering in this article. SBT has an embedded
Scala console, supports multiple projects, and has an extensible
plug-in architecture. SBT currently has some initial support for
IDEA, Eclipse, TextMate, Emacs, and VIM. Since SBT is fairly new,
you may still find that there will be some work involved in getting
it integrated with your favorite editor or IDE. See the resources
below for SBT integration support.

Creating Your Project

Creating a project in SBT is just a simple matter of creating an
empty directory that will house your new project and running the
sbt command then answering a few questions about your
project. Listing 1 shows what a typical initialization will look
like.

Folder Conventions

SBT uses the same folder conventions as Maven. As you can see
from Figure 1, all Scala source code is placed in the
src/main/scala directory, and all Java source code in the
src/main/java directory.

The directory src/main/resources is a folder in which
you can place any files that your code relies on: property files,
XML files, images, etc. Since this is a web application, all web
specific files go into the webapp directory including WEB-INF
configuration files.

Defining a Project

Unlike Ant or Maven that use an XML file to configure your
build, configuration in SBT is done using an actual Scala class.
The Scala class should be placed in the project/build
directory inside your project folder and the class must extend the
DefaultWebProject class for any SBT web application. In
the included example, I created a file called CDIScalaProject.scala
and placed it in the project/build directory. You can call
the Scala build file whatever you want, as long as the class
inherits DefaultWebProject for a web project or
DefaultProject for a standard non-web application.

For our example we are going to be using CDI with Scala using
Seam 3. Seam 3 is the latest release of the Seam Framework and is
thus far the most mature CDI based web framework to date. Its CDI
implementation uses Weld. Listing 2 shows a completed project file
with the dependencies required for this article and project.

The first line contains the required imports for the Project.
The class declaration itself is much like Java with some slight
differences. In Line 2, CDIScalaProject class receives a
ProjectInfo parameter named info. In Scala, one
difference in declaring variables and parameters is that the
declarations are reversed; the name of the variable comes before
the class type. Therefore in line 2, CDIScalaProject has
one parameter, info of the type ProjectInfo. The extends
keyword works much like in Java in that it declares that
CDIScalaProject will inherit from
DefaultWebProject. The difference between Java and Scala
is that we specify in our extends clause which parental constructor
will get the call based on the parameter signature. In the
CDIScalaProject example, it is the constructor that
accepts a ProjectInfo object.

In Line 3, 4, and 5 of Listing 2, our CDIScalaProject
declares that dependencies can be found in the Scala-Tools
Maven2 Repository
and the JBoss Maven 2 Repository.

Each remote repository is located at a particular web address.
For those unfamiliar with Maven repositories, Maven Repositories
are sites that maintain a library of dependencies and their
sources. Maven repositories come in either the remote or local
varieties.

Remote repositories are Internet or network based repositories
that contain the library that will be downloaded by your build
tool, in our case, SBT. Local repositories are repositories that
contain cached dependencies from remote repositories previously
downloaded, critical dependencies not found elsewhere, and in-house
projects that have not been published.

Lines 7 through 20 show the dependency requirements for our
project. Each repository indexes a dependency by its Maven vector
which consists of groupID, artifactID, and version. You can think
of a Maven vector like an address to locate a resource within a
Maven repository.

For example, in line 10 of Listing 2, SBT will get the
seamservlet library, version “3.0.0.CR3″, which is listed under the
group ID org.jboss.seam.servlet. The library vector is
delimited by a ‘%’ and the intent is to make it feel like the slash
directory that you are familiar with in your shell. The method,
withSources(),will tell SBT to download the source jar
files along with the compiled jar library.

Each dependency line can also specify how the library is to be
included in the final package, in our case, our war file. Lines 7
through 10 are dependencies marked as “compile” which will be
included in the war file. Lines 12 through 15 are dependencies
marked as “test” which will only be available when testing
production code. Lines 17 through 20 are dependencies marked
“provided” which will be available for compiling and testing but
not for packaging since these libraries are already provided by our
application server. Finally, Lines 23 and 24 are a workaround for
SBT so that they do not include source jar files into the final war
product.

  

Running SBT, an Introduction

Running SBT is a straightforward process and is governed by
actions. If you are coming from Maven, some of these action names
are already very familiar to you. Here is a small sample of actions
that you will need for the article.

reload: Compiles the project definition file.

compile: Compiles all main source files in your
project.

test-compile: Compiles all test source files in your
project.

update: Downloads all dependencies from repositories
into the /lib_managed directory of your project.

clean-lib: Cleans up the /lib_managed
directory. This is useful in case some libraries are still around
that you don’t want anymore.

Each action can be run from the command prompt of your shell by
running the command sbt along with the action you wish to run. For
example, running sbt compile at the command prompt will
compile your entire project. Running sbt test would
compile and test your entire project. Alternatively you can run
actions by invoking the SBT environment shell by running the
command sbt. Once in the sbt shell, you can run all your actions
without typing sbt before each action. This is especially
useful for triggered executions which I’ll be discussing next.

Triggered Executions

Triggered executions are like the regular actions we mentioned
in the previous section. The difference is when the action is
complete it will wait until you make another change to a file. Once
SBT notices that a change has been made to a file, it will run your
action again until you hit the ENTER key. Triggered
execution actions are named the same as the regular actions except
they are prepended by a “~”. Here is another small sample set of
sbt triggered executions that will be useful for this article.

~compile – Compile all main source files in your
project then wait for a source file to change, after which time the
changed files will be compiled again.

~test-compile – Compile all test source files in your
project then wait for a test source file to change, after which
time the changed test files will be compiled again.

~test – Run all tests, then wait for a file to
change, after which time the file will be compiled and tested
again.

~test-quick – Run all failed, new, and recompiled
tests then wait for a source or test file to change, after which
time, the files will be compiled and tested again.

~test-failed – Run all failed and new tests then wait
for a source or test file to change, after which time, the files
will be compiled and tested again.

Folder setup

In Figure 1 we have some files that need to be included in the
WEB-INF folder in order for you to use CDI and to use Scala with
CDI. First, in order for the war file to become a CDI based war
file you need to include a beans.xml file in the
webapp/WEBINF folder. The beans.xml file can be
used to map components used for dependency injection but for our
purposes we will leave an empty shell as shown in Listing 3.

Secondly, I am including a blank faces-config.xml in
the webapp/WEB-INF directory so that a Java EE Application
server can detect this war file as a Java Server Faces ready war
file. Again this file, as seen in Listing 4, will be an empty
shell, since we don’t have page navigation directions at this time.
Next, the file jboss-scanning.xml is a vital file if you
are considering using Scala with your Java EE war file in a JBoss
Application Server. The jboss-scanning.xml file will
specify what classes the Application Server can scan. If this file
is not present, JBoss will complain about certain Scala types it
was unable to scan and will refuse to load your war file. Listing 5
shows what should be included in jboss-scanning. xml file.
Notice that we will be telling JBoss to skip all scala packages in
the scala-library.jar file located in
WEB-INF/lib/scala-library.jar.

Lastly, the tried and true web.xml file is required. Our targets
for this project are modern application server systems like JBoss
6.0.0.Final and Glassfish 3.1 so the setup is fairly small and
familiar to the seasoned Java Web Developer. In Listing 6, we
declare a session time out, a context parameter that we are in a
Development project stage and we declare a FacesServlet to
process our Java Server Faces on files that end in .xhtml
suffix.

If you are not using a modern application server there is some
more initial setup required for this project to work with your
web-app 2.5 container. Please visit “Pre-Servlet 3.0 Configuration”
Seam-Servlet documentation for additional
configuration.

Creating our war file

We are now ready to create our war file. In Listing 7, we run
the following commands in a terminal using sbt. As mentioned above
in “Running SBT, an Introduction”. The reload command will
recompile our CDIScalaProject. scala build file for use.
If there is an error, you can recompile by running sbt
reload again. The update command will download our dependencies.
Running sbt clean and package will create our war file.

Once completed locate your war file in the target/scala_2.8.1
directory. Typically the war file will be the name of the folder
your project is in followed by the scala version it was built with
and then the version number of your project. For example, a project
folder called cdi-scala, my war file is called
cdi-scala_2.8.1-1.0.war.

Your file is now ready to be deployed to either JBoss
6.0.0.Final, Glassfish 3.1, or your Java EE 6 compliant application
server of choice.

Upgrading Weld in Glassfish 3.1

Weld is the CDI Reference Implementation of JSR-299, Java
Contexts and Dependency Injection for the Java EE platform. It is
the core Dependency Injection framework used in both JBoss
6.0.0.Final and Glassfish 3.1. Currently the Weld implementation in
Glassfish 3.1 needs to be upgraded in order for your war file to
work as expected. This is the nature of bleeding edge technologies
and case studies. Therefore, please visit the Seam and Glassfish integration guide at
seamframework.org to get a workaround on this issue and any other
issues that may arise.

Conclusion

This is merely the first step for my case study. I will be
exploring and testing how far I can go with Scala and CDI and
determine its boiling point. This project is freely available on
GitHub and has everything contained in this article,
including code that I will be using to pressure test the Scala
language with CDI/Seam3.

For more information on the ‘Functional Programming in
Scala with CDI’ session, check out the JAXConf website!
Early Bird registration ends TODAY – register now, and save up to
$200.

Author
DanielHinojosa
Daniel Hinojosa has been a self-employed developer, teacher and speaker for private business, education, and government since 1999. He also currently teaches programming at the University of New Mexico Continuing Education. His business is revolved around the Java ecosystem, encompassing multiple languages and frameworks. Daniel is a Pomodoro Technique practitioner and is co-founder of the Albuquerque Java User's Group in Albuquerque, New Mexico.
Comments
comments powered by Disqus