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.
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 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.
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.
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.