Red Hat

In Relation To Nicklas Karlsson

In Relation To Nicklas Karlsson

Gavin King gets his star

Posted by Nicklas Karlsson    |    Jan 11, 2011    |    Tagged as

Not sure if this has been posted but I just noticed that Gavin King has been awarded the title of JCP Star Spec Lead. Congratulations!

Read the press release here

Spreadsheets in Seam 3

Posted by Nicklas Karlsson    |    Jun 27, 2010    |    Tagged as Seam

While the community is pondering on the question as how to do JSF headless rendering for xhtml templates for content delivery, I started planing on how to make the Excel-centric spreadsheet module from Seam 2 more generic for the upcoming Seam 3 release. This blog is just a documented brainstorming session where I call for feedback so don't panic if you feel you didn't learn anything new once you finished reading.

The model

Excel-generation didn't really have that much of a model in Seam 2. The various UI tags worked pretty much straight against the rendering library, so the first step in a more generic solution would be a model for the spreadsheet. So, how does a spreadsheet application look like? The answer to that is of course It depends on the spreadsheet application but most of them have a collection of named worksheets that has a collection of cells that are formatted in various ways. Let's start with the workbook (I omit getters/setters for brevity):

public class Workbook
{
   private List<Worksheet> worksheets = new ArrayList<Worksheet>();
   private List<FormattingRule> formattingRules = new ArrayList<FormattingRule>();
}

We'll talk about FormattingRules shortly. Now the worksheet:

public class Worksheet
{
   private String name;
   private List<Cell> cells = new ArrayList<Cell>();
   private List<FormattingRule> formattingRules = new ArrayList<FormattingRule>();
}

and the cell:

public class Cell
{
   private Coordinate coordinate;
   private CellSpan span;
   private CellFormatting formatting;
}

a Coordinate is a class for modeling a (column, row) tuple:

public class Coordinate
{
   private int column;
   private int row;
}

and a CellSpan for modeling col/rowspans

public class CellSpan
{
   private int columnSpan;
   private int rowSpan;
}

Formatting

Now for the formatting. This is modeled by the CellFormatting class:

public class CellFormatting
{
   public enum Type { CASCADING, ABSOLUTE }
   public Type type = Type.CASCADING;
   // Lots of formatting objects for Fonts, Borders, Backgrounds etc...
}

Where the enum is used for marking if the formatting should be absolute or merged/cascaded with previous rules. What previous rules? That's what I said I'll get back to when I talked about the Workbook class. Workbooks and SpreadSheets can have a list of FormattingRule:s that are cascaded

public interface FormattingRule
{
   public abstract boolean appliesTo(Cell cell);
   public abstract CellFormatting getCellFormatting();
}

So if you want all cells in the entire Workbook to have a particular font, you would place an implementation of a FormattingRule in the Workbook that appliesTo all cells and returns a formatting for that font. Then if you would like to have alternate rows with grey background in a certain worksheet, you would in that worksheet place a FormattingRule implementation that appliesTo cell.getCoordinate().getRow()s that are odd and return a formatting for grey background. For final tuning of a cell, it could also have some formatting that would be merged in for the final result.

Generating the model

You could of course assemble a Workbook model by hand but that would be a bit tedious so there would of course be builder classes that could transform a JSF datatable (with ICEfaces/RichFaces variants for bling-bling-support) to a Workbook. Another tool would be a Workbook from JavaBean builder that would take an Iterable<Foo> and a String[] of field names and generate a workbook from that (keeping track of Coordinates with an internal cursor) etc.

Importing and exporting

So what do we do with the model? We import and export then of course. We could read a workbook with

public interface SpreadsheetReader
{
   public abstract Workbook readWorkbook(byte[] data);
}

and write one with

public interface SpreadsheetWriter
{
   public abstract byte[] writeWorkbook(Workbook workbook);
   public abstract byte[] writeWorkbook(Workbook workbook, byte[] template);
}

This means that we could have different implementations that do different things. There could be implementations like

@Inject SpreadsheetWriter write;

or

@Inject @Excel SpreadsheetWriter write;

or

@Inject @OpenOffice SpreadsheetWriter write;

or in the case of multiple implementations

@Inject @Excel(implementation="jxl") SpreadsheetWriter write;

The output from the could then be put in a database, written to the user, mailed etc.

Open issues

Does it work? How about the EL-stuff in Seam 2 templates, is it all mappable to FormattingRules? How about usage of the rendered attribute? Any other stuff? Your feedback is appreciated!

On contexts, scopes and conversations

Posted by Nicklas Karlsson    |    Jun 23, 2010    |    Tagged as

Contexts in JSR-299 is so important that it actually was incorporated in the name after a few attempts so let's have a look at what the contexts and scopes really are. We'll be using Weld as the reference when we want to get into implementation details but the core stuff is implementation agnostic and follow the rules of the specification. This blog posting is sort of a "scopes and contexts for dummies" with some simplifications, for a more formal approach you might want to Read The Fine Specification.

Contexts

A context is like a labeled shelf. There are shelves named @RequestScoped, @SessionScoped etc. When you use a bean of a particular scope, a bean instance is fetched from that shelf (or one is created and placed there if it wasn't already there) so that you are guaranteed to get the same instance the next time you reference it (withing the same lifecycle)

As a curiosity can be mentioned that there can actually be many shelves for a particular scope (as long as only one is active at any given time). 5 minutes of fame and honor to the one that can find a usecase for that. I think it has something to do with child activites that once was a part of the spec.

Scopes

The scope is the link between a bean and a context. Different contexts/scopes have different lifecycles and that determines for how long your stuff should be kept on the shelf. The shelf is automatically wiped clean when the scope hits it's end-of-life (e.g. the contents of the session context is destroyed when the session expires etc). There is no cheating, in Seam you could place almost any bean in any scope but in CDI, a bean of a particular scope always end up on the corresponding shelf. A bean has one and only one scope.

Proxies

Proxies are wrappers. There are different kinds of proxies, there are placeholder proxies used at injection points for normal scoped beans that look up the real instance before invoking methods on it and there are proxies that wrap interceptors and stuff around the real instance of the bean class.

Behind the scenes

So what really happens when you have something like this

@Model
public class Foo
{
   @Inject Bar bar;

   public String getPong()
   {
       return bar.pong();
   }
}

and

@SessionScoped
public class Bar implements Serializable
{
    public String pong()
    {
        return "pong";
    };
}

is that Weld at boot time creates the beans for both Foo and Bar. Foo is a @Named @RequestScoped bean (@Model stereotype) and Bar is a @SessionScoped one. There are no actual instances created at this time but there is a proxy injected at

@Inject Bar bar;

which has the ability to look up the Bar instance when needed. At this point both the request context and session contexts are empty. Now for the magic. When you in a xhtml page do something like

#{foo.pong}

the EL-resolver kicks in and comes to the conclusion that we need the named (EL-available) bean foo as a starting point. The BeanManager will resolve the bean and notice that Foo is @RequestScoped so it will ask the RequestContext for an instance. Since the request context is empty, an instance is generated, using the Foo-bean as template. This instance is placed in the request context in case someone needs it during the same request.

The getPong() method on that instance is called which hits the proxy for Bar. Since Bar is @SessionScoped, the BeanManager consults the session context for an instance. Since there is none there, one is created, and stuck in the session context for later reference. This instance is the one that has it's pong() method invoked.

When the request is over, the request context is destroyed and any destructors of Foo are called but since the session context is still alive (the session didn't terminate), the instance for Bar stays alive.

Now another request from the same webapp comes along. The request scope is once again empty and we have a new instance for foo but this time bar is already found in the session context and we get the same instance of Bar. Just as we should since we have a new request (fresh request context) but same 'ol session (old session context). In this way we can mix injection between contexts - we can inject @RequestScoped beans in @SessionScoped ones and vice versa and the proxies will make sure the correct instances are hit (or created) in the contexts.

Context not active

All contexts are not active all the time. Getting a context not active exception from an @ApplicationScoped bean is a bit tricky but the request context is only available when there is an active HTTP request and the session context is only available when there is an active HTTP session. It means that accessing beans in those contexts are no-go from e.g. MDB:s. Why is this?

Weld-specific stuff ahead, using the request context as an example: There is only one request context. Really. All 5000 concurrent users of your webapp share the same request context instance. Yup, the actual context data is stored in a ThreadLocal<BeanStore> field which means that (lucky for us) each users thread has own data in the field.

BeanStore is an interface and the particular implementation of it that is stuck in the ThreadLocal field of the request context is wrapping a HTTP servlet request. This means that adding stuff to that bean store actually places it in the request and clearing the bean store removes all keys from the request that belong to that bean store. The request attributes names are filtered through a naming scheme so that attributes that start with the @RequestScoped class name are considered belonging to that bean store.

What this means in practice is that the servlet request has to be there in order to work as backing storage for the bean store in the request context. The active-flag of the context is just there to indicate that at this point, Weld has populated that context with a true bean store.

So actually, you can't put stuff directly on the @RequestScoped shelf. You are only allowed to put things in a box (the servlet request backed bean store) Weld has placed on the shelf. The placing of the box is coupled to the activation of the context and the removal of the box is coupled to the deactivation. These activations and deactivations are handled by servlet request listeners that watch for the creation and destruction of the request.

When we're talking request scope, the context is short-lived and a new box is placed on the shelf when the request begins and it is cleared out when it ends but how about session scope? The story is very similar with the exception that the stuff belonging to the session bean store is not destroyed when the request ends. When the next request comes in, the session context is re-populated with a bean store that wraps the HTTP session. Since the previous request also used the HTTP session as backing storage, stuff placed in the session context then lives on in session attributes starting with the @SessionScoped class name. As you notice, for both request and session context, naming plays an important role. There are other things floating around the HTTP request and session attributes and we don't want to hit anything not belonging to us when we e.g. clear out a bean store.

It is important to realize that the limitations are not that of Welds implementation. Sure, there could be other ways of implementing the contexts that would make them appear available all the time but they could per definition not be semantically correct. You could also implement stuff without writing directly e.g. to the underlying HTTP session but when it comes to session replication, it's a Good Thing.

As a curiosity can be mentioned that due to the fact that the specification say the session context must survive session invalidation (which is not a Good Thing when you have direct HTTP session backed beanstore and try to access it after invalidation) there is a sort of buffering built into the session context that loads on init and caches stuff if the session should go AWOL at some point.

Honey, we need to have a conversation

The conversation context is actually like a named sub-session-context. The @RequestScoped shelf can have only one box where stuff is stored in but on the @ConversationScoped shelf there can be many boxes. The labels on the boxes is the conversation ID. Conversations can be either transient (the default) and in this case it behaves much like the request context and only lives during one HTTP request. This is not very useful, therefore conversations can be promoted to non-transient (long-running). This is achieved by calling the begin() or begin(String) methods on the Conversation bean that's available for injection. When the request ends, the Conversation Manager decides the fate of the conversation context by looking at the transient flag of the Conversation. If it is transient, the conversation context is destroyed, if it's non-transient it's left alone and the generated (or assigned) conversation ID is passed along as a HTTP parameter to the next request.

The Conversation Manager is also the one which determines if we should start with an empty, transient conversation and conversation context or if we should resume an existing one when a request comes in. The cid parameter is looked for in the incoming HTTP request. No parameter present means transient conversation but if there is a value for cid, say 1, the conversation manger picks down the box labeled 1 from it's storage and loads it into the conversation context. Well, actually it wraps the HTTP session with a conversation-beanstore suited to match that conversation id (again, naming play an important role) and pre-populates the Conversation instance with the cid and transient flagged to false. We are free to switch conversations, promoting and demoting them and the HTTP session will mirror those contexts through its attributes, suited to match the names of the conversations.

If you think you can get cute and do some URL-rewriting by modify the passed-along cid-parameter feel free. Since your own session is used as backing storage, the only thing you can do is switch to another conversation of your own (or bomb out because the cid was not known). There is no way you can access conversational data from another user, even the specification says you can't cross the HTTP session boundary.

As a curiosity could be mentioned that it's harder and harder with modern browsers to actually get new sessions since tabbed browsings etc have brought along the side-effect that the session and cookies are shared among browser instances. Earlier it was usually enough to start a new browser but nowadays you usually have to use incognito/private browsing to test the session boundaries with the same brand of browser.

Conclusion

Hopefully you are now confused at a higher level. You might also want to check out the specification on how to write custom contexts and scope types. You might also want to have a look at the Weld source code in the org.jboss.weld.context package and look at how the BeanManagerImpl does the resolving.

A Hitchhikers Guide to Java EE 6 application setup, Part V

Posted by Nicklas Karlsson    |    Jun 22, 2010    |    Tagged as Java EE

In this shortish part, we'll add some interfaces to our application so external users can read the current greetings. Expanding the interfaces so greetings can be added is left as an exercise for the reader

JAX-RS

REST is hip (and now in EE 6 as JAX-RS) so let's throw it in. Add

package com.acme.greetings;

import java.util.List;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path(value = "/RESTExport")
public class RESTExporter
{

   @Inject
   GreetingServer greetingServer;

   @GET
   @Path("/greetings")
   @Produces("application/xml")
   public List<Greeting> getGreetings()
   {
      return greetingServer.getGreetings();
   }

}

That fetches the current greetings (notice the injection) from the server and presents them in XML format. To hook up the JAX-RS implementation, RESTEasy, add the following to web.xml

<context-param>
	<param-name>resteasy.scan</param-name>
	<param-value>true</param-value>
</context-param>
<context-param>
	<param-name>resteasy.servlet.mapping.prefix</param-name>
	<param-value>/resteasy</param-value>
</context-param>
<listener>
	<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<servlet>
	<servlet-name>Resteasy</servlet-name>
	<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>Resteasy</servlet-name>
	<url-pattern>/resteasy/*</url-pattern>
</servlet-mapping>

and the @XMLRootElement annotation to the top of our Greeting class

@Entity
@Audited
@XmlRootElement
public class Greeting

Your greetings should now be available from /Greetings/resteasy/RESTExport/greetings.

JAX-WS

Adding a Web Service is even more simple. Add

package com.acme.greetings;

import java.util.List;

import javax.inject.Inject;
import javax.jws.WebService;

@WebService
public class WebServiceExporter
{
   @Inject
   GreetingServer greetingServer;

   public List<Greeting> getGreetings()
   {
      return greetingServer.getGreetings();
   }

}

That does a similar job as our RESTExporter and then hook it up in web.xml

<servlet>
	<servlet-name>WSExport</servlet-name>
	<servlet-class>com.acme.greetings.WebServiceExporter</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>WSExport</servlet-name>
	<url-pattern>/WebServiceExport/*</url-pattern>
</servlet-mapping>

Hmm. Wonder if you can make it auto-register? Anyway, the WDSL should be viewable from /Greetings/WebServiceExport?wsdl

Conclusion

This was a short one. Partly because setting things up is really straightforward and don't require us to do that many workarounds. Hopefully, once Aslak finishes the Arqullian DBUnit integration (I already heard rumors on JSFUnit integration) I can be back with a more thorough article on testing all parts of the application.

A Hitchhikers Guide to Java EE 6 application setup, Part IV

Posted by Nicklas Karlsson    |    Jun 21, 2010    |    Tagged as Java EE

My wife has delivered our daughter and JBoss has delivered a snapshot of the AS 6 that can do most of the stuff we set out to do, so let's move on!

The good, the bad and our daily workarounds

So, since we're living on the edge here, head over to JBoss Hudson and grab the latest successful build (#1750 or later). Install the envers.jar in the server and change the http listener port like we did in the end of part II. Remember to update your JBOSS_HOME environment variable if you use one.

There is a slight regression with the auto-registration of the faces servlet so add this to your web.xml

<servlet>
	<servlet-name>Faces Servlet</servlet-name>
	<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>Faces Servlet</servlet-name>
	<url-pattern>/faces/*</url-pattern>
</servlet-mapping>

The ZipException is gone so clear out your faces-config.xml from the merged ICEfaces stuff and delete the icefaces directory from your local repository so you can pick up fresh copies of the original jars.

There is also another regression that has something to do with redirects and the ICEfaces PushRenderer (perhaps). If you go straight to the /Greetings context root, the PushRenderer is not that pushy, you'll have to use the full /Greetings/faces/greetings.xhtml for now.

Look mama, no EARs

We're going EJB and let's do some refactorings while we're at it. Remove the GreetingBean and create the following classes

package com.acme.greetings;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;

import javax.annotation.PostConstruct;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Stateful;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.inject.Named;

import org.icefaces.application.PushRenderer;

@Stateful
@ApplicationScoped
@Named
public class GreetingServer implements Serializable
{
   private static final long serialVersionUID = 1L;

   List<Greeting> greetings = new ArrayList<Greeting>();
   
   @Inject
   @Added
   Event<Greeting> greetingAddedEvent;

   @Inject
   GreetingArchiver greetingArchiver;
   
   @Inject
   GreetingEcho greetingEcho;
   
   @PostConstruct
   public void init()
   {
      greetings = greetingArchiver.loadGreetings();
   }

   @Lock(LockType.WRITE)
   public void addGreeting(Greeting greeting)
   {
      greetings.add(greeting);
      PushRenderer.render("greetings");
      greetingAddedEvent.fire(greeting);
      Future<Boolean> result = greetingEcho.echo(greeting);
   }

   @Lock(LockType.READ)
   public List<Greeting> getGreetings()
   {
      return greetings;
   }
}

and

package com.acme.greetings;

import javax.annotation.PostConstruct;
import javax.ejb.Stateful;
import javax.enterprise.inject.Model;
import javax.inject.Inject;

import org.icefaces.application.PushRenderer;

import com.icesoft.faces.context.effects.Appear;
import com.icesoft.faces.context.effects.Effect;

@Stateful
@Model
public class GreetingClient
{
   Greeting greeting = new Greeting();

   @Inject
   GreetingServer greetingServer;

   @PostConstruct
   public void init()
   {
      PushRenderer.addCurrentSession("greetings");
   }
   
   public Effect getAppear()
   {
      return new Appear();
   }

   public Greeting getGreeting()
   {
      return greeting;
   }

   public void setGreeting(Greeting greeting)
   {
      this.greeting = greeting;
   }

   public void addGreeting()
   {
      greetingServer.addGreeting(greeting);
   }
}

The GreetingServer keeps the greetings and the client has injected the server and interacts with it (we've thrown in some annotations for concurrency control to the greeting list). You might notice we also have a new injection

@Inject
GreetingEcho greetingEcho;

which is called like

Future<Boolean> result = greetingEcho.echo(greeting);

This is an asynchronous call to GreetingEcho that looks like

package com.acme.greetings;

import java.util.concurrent.Future;

import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.Stateless;

@Stateless
public class GreetingEcho
{

   @Asynchronous
   public Future<Boolean> echo(Greeting greeting)
   {
      System.out.println(String.format("Got a new greeting: %s", greeting.getText()));
      return new AsyncResult<Boolean>(true);
   }
}

This is kind of funny EE 6 construct since it really exits the @Asynchronous method immedeately, returning a handle to the task. Well, good luck trying to cancel that output before it finished. This is kind of JMS-light. And yes, it's obviously used just for show-off here.

You'll also notice that our DB bean has gotten a new look

package com.acme.greetings;

import java.util.Date;
import java.util.List;

import javax.ejb.Stateless;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Root;

@Stateless
public class GreetingArchiver
{
   @Inject
   @GreetingDB
   EntityManager db;

   CriteriaQuery<Greeting> loadQuery;
   ParameterExpression<Date> timestampParam;

   @Inject
   public void initQuery(@GreetingDB EntityManagerFactory emf)
   {
      CriteriaBuilder cb = emf.getCriteriaBuilder();
      timestampParam = cb.parameter(Date.class);
      loadQuery = cb.createQuery(Greeting.class);
      Root<Greeting> greeting = loadQuery.from(Greeting.class);
      loadQuery.select(greeting);
      loadQuery.where(cb.greaterThan(greeting.get(Greeting_.created), timestampParam));
   }

   public void saveGreeting(@Observes @Added Greeting greeting)
   {
      db.persist(greeting);
   }

   public List<Greeting> loadGreetings()
   {
      Date tenMinutesAgo = new Date();
      tenMinutesAgo.setTime(tenMinutesAgo.getTime() - 10 * 60 * 1000);
      return db.createQuery(loadQuery).setParameter(timestampParam, tenMinutesAgo).getResultList();
   }
}

The persistence has been much simplified thanks to CMT.

And finally the view to use them

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:ui="http://java.sun.com/jsf/facelets">
	<h:head>
		<title>
			Greetings
		</title>
	</h:head>

	<h:body>
		<h:form>
			<ice:inputText id="feedback" value="#{greetingClient.greeting.text}" effect="#{greetingClient.appear}"/>
			<h:message for="feedback" />
			<h:commandButton value="Add" action="#{greetingClient.addGreeting}" />
			<h:dataTable value="#{greetingServer.greetings}" var="greeting">
				<h:column>
					<h:outputText value="#{greeting.text}"/>
				</h:column>
			</h:dataTable>
		</h:form>
	</h:body>
</html>

JMS and JavaMail

Speaking of JMS, let's add a MDB

package com.acme.greetings;

import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/GreetingTopic"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic") })
public class GreetingMailer implements MessageListener
{
   @Resource(mappedName = "java:/Mail")
   Session mailSession;

   @Override
   public void onMessage(Message message)
   {
      TextMessage textMessage = (TextMessage) message;
      try
      {
         mail(textMessage.getText());
      }
      catch (Exception e)
      {
         // Forgive me, for I have sinned
         System.out.println(String.format("No mailing: %s", e.getMessage()));
      }
   }

   private void mail(String greeting) throws MessagingException
   {
      MimeMessage message = new MimeMessage(mailSession);
      message.setFrom(new InternetAddress("greetingmaster@nowhere.org"));
      message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress("you@yourplace.com"));
      message.setSubject("New greeting has arrived!");
      message.setText(greeting);
      Transport.send(message);
   }
}

This is a message driven bean that listens to the topic /topic/GreetingTopic and when a message is recieved, it grabs the default Mail session from the application server and send off a notification, configure it in the mail-service.xml in the deploy directory. You should also add the topic to the deploy/hornetq/hornetq-jms.xml like

<topic name="GreetingTopic">
   <entry name="/topic/GreetingTopic"/>
</topic>

There are probably better ways of deploying topics but I'm not writing a JBoss AS tutorial here. This MDB isn't going to see any action unless someone actually send it messages. Let's add a

package com.acme.greetings;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.enterprise.event.Observes;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

@Stateless
public class JMSDispatcher
{
   @Resource(mappedName = "/ConnectionFactory")
   ConnectionFactory connectionFactory;

   @Resource(mappedName = "/topic/GreetingTopic")
   Topic topic;

   public void broadcast(@Observes @Added Greeting greeting) throws JMSException
   {
      Session session = null;
      MessageProducer producer = null;
      Connection connection = null;
      try
      {
         connection = connectionFactory.createConnection();
         session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
         producer = session.createProducer(topic);
         TextMessage message = session.createTextMessage(greeting.getText());
         producer.send(message);
      }
      finally
      {
         if (producer != null)
         {
            producer.close();
         }
         if (session != null)
         {
            session.close();
         }
         if (connection != null)
         {
            connection.close();
         }

      }
   }
}

This bean observers the same added greeting as the GreetingArchiver and sends the greeting of to our topic. There are probably better ways of writing this but I'm not writing a JMS tutorial (either). Hmm, I forget what kind of tutorial I'm actually writing.

Something for the future

This snapshot doesn't have everyting yet, I'd like to have @Scheduled greetings so we don't get lonely. This doesn't actually work yet, but let's add it and keep upgrading our snapshots so perhaps one day we'll get lucky.

package com.acme.greetings;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.inject.Inject;

@Singleton
public class ArbiBean
{
   static final List<String> comments = new ArrayList<String>()
   {
      private static final long serialVersionUID = 1L;
      {
         add("Tried the new JRebel? I heard it can read your thoughts?");
         add("Where can I find the specs?");
         add("Shouldn't you be using RichFaces 4 instead?");
         add("How is the Seam 3 performance compared to Seam 2?");
         add("PIGBOMB!");
      }
   };

   @Inject
   GreetingServer greetingServer;

   @Schedule(second = "*/15")
   public void comment()
   {
      greetingServer.addGreeting(new Greeting(getRandomComment()));
   }

   private String getRandomComment()
   {
      return comments.get(new Random(comments.size()).nextInt());
   }
}

This one should start up and send comments to the server every 15 seconds. But like I said, not yet.

Conclusion

This ends part IV. In part V we'll add JAX-RS and JAX-WS to share our greetings with the world. If you haven't noticed it by now, developing against snapshots and alpha-releases require a fair amount of workarounds. But as a developer you can choose - do you want to sit around and wait for the final product or do you want to join the round and get first-hand knowledge on things to come (filing JIRAs as you encounter issues).

In this third part we'll be hooking up JPA 2 with the static metamodel generator, Bean Validation and Envers

JPA

Let's get persistent. When we're talking persistence, we need a persistence.xml so let's make a folder META-INF src/main/resources and create one there

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0">
	<persistence-unit name="Greetings">
		<jta-data-source>java:/DefaultDS</jta-data-source>
		<properties>
			<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
			<property name="hibernate.hbm2ddl.auto" value="create-drop" />
			<property name="hibernate.show-sql" value="true" />
		</properties>
	</persistence-unit>
</persistence>

We're using the standard HSQL DefaultDS that comes with JBoss AS 6. If you want to be really hip, google around for @DataSourceDefinition which is a new kid on the block in EE 6 (haven't tried if AS 6 supports it yet, though)

Next, let's expand our model from Strings to a Greeting entity. Create a

package com.acme.greetings;

import static javax.persistence.TemporalType.TIMESTAMP;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Entity
public class Greeting
{
   @Id
   @GeneratedValue
   int id;

   String text;
   
   @Temporal(TIMESTAMP)
   Date created = new Date();

   public int getId()
   {
      return id;
   }

   public void setId(int id)
   {
      this.id = id;
   }

   public String getText()
   {
      return text;
   }

   public void setText(String text)
   {
      this.text = text;
   }
}

change the GreetingBean to

package com.acme.greetings;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.inject.Named;

import org.icefaces.application.PushRenderer;


@ApplicationScoped
@Named
public class GreetingBean implements Serializable
{
   Greeting greeting = new Greeting();
   List<Greeting> greetings = new ArrayList<Greeting>();

   @Inject
   @Added
   Event<Greeting> greetingAddedEvent;

   @Inject
   GreetingArchiver greetingArchiver;
   
   @PostConstruct
   public void init()
   {
      greetings = greetingArchiver.loadGreetings();
   }

   public void addGreeting()
   {
      greetings.add(greeting);
      greetingAddedEvent.fire(greeting);
      greeting = new Greeting();
      PushRenderer.render("greetings");
   }

   public Greeting getGreeting()
   {
      return greeting;
   }

   public void setGreeting(Greeting greeting)
   {
      this.greeting = greeting;
   }

   public List<Greeting> getGreetings()
   {
      PushRenderer.addCurrentSession("greetings");
      return greetings;
   }

   public void setGreetings(List<Greeting> greetings)
   {
      this.greetings = greetings;
   }
}

We have also injected an event that is fired when comments are added:

@Inject
@Added
Event<Greeting> greetingAddedEvent;

so we need a qualifier called Added:

package com.acme.greetings;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target( { METHOD, FIELD, PARAMETER, TYPE })
public @interface Added
{
}

and greetings.xhtml to

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:ui="http://java.sun.com/jsf/facelets">
	<h:head>
		<title>
			Greetings
		</title>
	</h:head>

	<h:body>
		<h:form>
			<ice:inputText value="#{greetingBean.greeting.text}" effect="#{greetingBean.appear}"/>
			<h:commandButton value="Add" action="#{greetingBean.addGreeting}" />
			<h:dataTable value="#{greetingBean.greetings}" var="greeting">
				<h:column>
					<h:outputText value="#{greeting.text}"/>
				</h:column>
			</h:dataTable>
		</h:form>
	</h:body>
</html>

(we changed the order of the table and the input fields as it was getting annoying to have the field and button move down as we add comments)

Of course since we are firing events it would be nice if someone is actually listening. Let's create a GreetingArchvier:

package com.acme.greetings;

import java.util.List;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@ApplicationScoped
public class GreetingArchiver
{
   @PersistenceContext
   EntityManager db;

   @Inject
   UserTransaction userTransaction;

   public void saveGreeting(@Observes @Added Greeting greeting)
   {
      try
      {
         userTransaction.begin();
         db.joinTransaction();
         db.persist(greeting);
         db.flush();
         userTransaction.commit();
      }
      catch (Exception e)
      {
         e.printStackTrace();
         // The recommended way of dealing with exceptions, right?
      }
   }

   public List<Greeting> loadGreetings()
   {
      return db.createQuery("from Greeting").getResultList();
   }

}

That observes @Added Greetings and store them to the database. Notice also the loadGreetings() method that GreetingBean calls in it's @PostConstruct to populate itself with old comments. Well, with create-drop in our persistence.xml there won't be much to load but let's fix that later.

JPA 2

That's all nice but we're trying to be livin' on the edge so let's bring in JPA and typesafe queries and with those we better have some static metamodel generator, otherwise the attributes will quickly become a burden. There is Eclipse integration available (google around) but if you're doing automated maven-based builds, you're going to need this anyway. Since both Eclipse and Maven are involved in building, be prepared for some chicken-egg-project-cleaning-and-refreshing in Eclipse from time to time when adding new entities. Anyways, open up pom.xml and add some plugin repositories:

<pluginRepositories>
	<pluginRepository>
		<id>jfrog</id>
		<url>http://repo.jfrog.org/artifactory/plugins-releases/</url>
	</pluginRepository>
	<pluginRepository>
		<id>maven plugins</id>
		<url>http://maven-annotation-plugin.googlecode.com/svn/trunk/mavenrepo/</url>
	</pluginRepository>
</pluginRepositories>

The maven-compiler-plugin will need an argument to not process annotations automagically once we slap jpamodelgen on the classpath

<configuration>
	<source>1.6</source>
	<target>1.6</target>
	<compilerArgument>-proc:none</compilerArgument>
</configuration>

and the job should be taken over by our new build-plugins:

<plugin>
	<groupId>org.bsc.maven</groupId>
	<artifactId>maven-processor-plugin</artifactId>
	<version>1.3.5</version>
	<executions>
		<execution>
			<id>process</id>
			<goals>
				<goal>process</goal>
			</goals>
			<phase>generate-sources</phase>
			<configuration>
				<outputDirectory>target/metamodel</outputDirectory>
			</configuration>
		</execution>
	</executions>
	<dependencies>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-jpamodelgen</artifactId>
			<version>1.0.0.Final</version>
		</dependency>
	</dependencies>
</plugin>
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>build-helper-maven-plugin</artifactId>
	<version>1.3</version>
	<executions>
		<execution>
			<id>add-source</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>add-source</goal>
			</goals>
			<configuration>
				<sources>
					<source>target/metamodel</source>
				</sources>
			</configuration>
		</execution>
	</executions>
</plugin>

Dan Allen thinks this is a lot of configuration for this task, I'll have to remember to ask if he ever got his simple, elegant solution to place the artifacts in usable places ;-)

Run mvn eclipse:eclipse to have the target/metamodel added to eclipse and do the project level Maven, refresh project configuration.

Run the maven build and you should see the Greeting_ class appear in target/metamodel and in the WAR structure. Now let's bring it into use:

First we add EntityManger/EntityManagerFactory producers (the recommeded CDI way of wrapping them)

package com.acme.greetings;

import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;

public class DBFactory
{
   @Produces @GreetingDB @PersistenceContext EntityManager entityManager;
   @Produces @GreetingDB @PersistenceUnit EntityManagerFactory entityManagerFactory;
}

We also need a qualifier for that

package com.acme.greetings;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target( { METHOD, FIELD, PARAMETER, TYPE })
public @interface GreetingDB
{
}

Finally, let's modify or GreetingArchiver:

package com.acme.greetings;

import java.util.Date;
import java.util.List;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Root;
import javax.transaction.UserTransaction;

@ApplicationScoped
public class GreetingArchiver
{
   @Inject
   @GreetingDB
   EntityManager db;

   @Inject
   UserTransaction userTransaction;

   CriteriaQuery<Greeting> loadQuery;
   ParameterExpression<Date> timestampParam;

   @Inject
   public void initQuery(@GreetingDB EntityManagerFactory emf)
   {
      CriteriaBuilder cb = emf.getCriteriaBuilder();
      timestampParam = cb.parameter(Date.class);
      loadQuery = cb.createQuery(Greeting.class);
      Root<Greeting> greeting = loadQuery.from(Greeting.class);
      loadQuery.select(greeting);
      loadQuery.where(cb.greaterThan(greeting.get(Greeting_.created), timestampParam));
   }

   public void saveGreeting(@Observes @Added Greeting greeting)
   {
      try
      {
         userTransaction.begin();
         db.joinTransaction();
         db.persist(greeting);
         db.flush();
         userTransaction.commit();
      }
      catch (Exception e)
      {
         e.printStackTrace();
         // The recommended way of dealing with exceptions, right?
      }
   }

   public List<Greeting> loadGreetings()
   {
      Date tenMinutesAgo = new Date();
      tenMinutesAgo.setTime(tenMinutesAgo.getTime() - 10 * 60 * 1000);
      return db.createQuery(loadQuery).setParameter(timestampParam, tenMinutesAgo).getResultList();
   }
}

Bean Validation

Adding Bean Validation is a breeze, just stick the annotations on the entity fields in Greeting:

@Size(min = 1, max = 50)
String text;

and attach a message to the input field in greetings.xhtml:

<ice:inputText id="feedback" value="#{greetingBean.greeting.text}" effect="#{greetingBean.appear}"/>
<h:message for="feedback" />

I tried placing a @NotNull on text but it still failed on submit because the values came in as empty string (might be this is the designed behavior) so I used min = 1 instead.

Envers

If you would like to have auditing on your entities, you need to add the Envers dep to pom.xml

<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-envers</artifactId>
	<version>3.5.1-Final</version>
	<scope>provided</scope>
</dependency>

I cheated a little and marked it provided as it was pulling in a lot of deps. I downloaded the envers.jar and dropped it in the server common lib with it's other hibernate buddy-jar:s. After that we can stick an annotation on the entity

@Entity
@Audited
public class Greeting

Last but not least to enjoy automatic data auditing we need to add the Envers listeners to persistence.xml

<property name="hibernate.ejb.event.post-insert"
	value="org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.post-update"
	value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.post-delete"
	value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.pre-collection-update"
	value="org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.pre-collection-remove"
	value="org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.post-collection-recreate"
	value="org.hibernate.envers.event.AuditEventListener" />		

This concludes part II, next time we'll be looking at EJB:s and MDB:s in more details. And perhaps abandoning our WAR-only utopia for now. Guess I'll have to learn about the maven EJB plugin. Hints for good tutorials accepted.

PS. Have you checked the size of the WAR file after you've taken all these technologies into use? Around 320k. And of those ~85% are the ICEfaces libs (the only external deps)

A Hitchhikers Guide to Java EE 6 application setup, Part II

Posted by Nicklas Karlsson    |    Jun 6, 2010    |    Tagged as Java EE

This is part II of my series on how to set up a Java EE 6 application and stuff as many technologies into a simple application that can ever fit. And then some.

ICEfaces

Now let's pull in ICEfaces. The guys at RedHat/JBoss have a RichFaces fetisch so it's only fair that the competition gets some attention, too. And it increases my chances of getting a t-shirt in the ICEfaces blogging competition. Oh yeah, and it's a nice framework in general.

Now since we're living on the edge, lets pull in their 2.0 alpha3 version. Unfortunately, the new component set didn't make A3 so it's a bit vanilla at this stage. Anyway, let's add their snapshots repository to our pom.xml

<repositories>
	<repository>
		<id>ICEfaces snapshots</id>
		<url>http://anonsvn.icefaces.org/repo/maven2/snapshots/</url>
	</repository>
</repositories>

and add a version property

<icefaces.version>2.0-A3</icefaces.version>

and add the deps

<dependency>
	<groupId>org.icefaces</groupId>
	<artifactId>icefaces</artifactId>
	<version>${icefaces.version}</version>
	<exclusions>
		<exclusion>
			<groupId>javax.faces</groupId>
			<artifactId>jsf-impl</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.icefaces</groupId>
	<artifactId>icepush</artifactId>
	<version>${icefaces.version}</version>
</dependency>

Notice how we exclude the jsf-impl? We're using an appserver for crying out loud! No need to throw stuff like that in, it's already provided.

Next let's change out GreetingBean to actually do something more useful

package com.acme.greetings;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

import org.icefaces.application.PushRenderer;

@ApplicationScoped
@Named
public class GreetingBean implements Serializable
{
   String greeting;
   List<String> greetings = new ArrayList<String>();

   public void addGreeting()
   {
      greetings.add(greeting);
      greeting = "";
      PushRenderer.render("greetings");
   }

   public String getGreeting()
   {
      return greeting;
   }

   public void setGreeting(String greeting)
   {
      this.greeting = greeting;
   }

   public List<String> getGreetings()
   {
      PushRenderer.addCurrentSession("greetings");
      return greetings;
   }

   public void setGreetings(List<String> greetings)
   {
      this.greetings = greetings;
   }

}

We've changed the GreetingBean to become @ApplicationScoped, that is, common for everyone so we have a sort of a chatroom. In getGreetings() we register the PushRenderer for our session and in addGreeting we trigged a render to all the currently active clients. This mechanism allows for DOM-changed to be pushed to the clients withoug need for active polling or browser refresh. Neat, huh?

Registering the PushRenderer sessions in a getter like this is a bit of a hack that stems from the fact that we have this application-scoped Grand Unified Bean that is initialized only once (for the first user triggering it) while the sessions need to be registered for each client on their FacesContext (I actually got this wrong the first time). No worries, we will fix this in the next part where we refactor it into GreetingServer and GreetingClient which have more appropriate scopes. Writing applications is a constant flow of refactorings and improvements, remember?

Let's for now forget about such trivialities as concurrent access to the list etc (we're moving it to a concurrency-controlled @Singleton later on). We're in a happy place...

Fixing the broken test is left as a exercise for the reader.

Now let's change our greetings.xhtml to use the new backing bean

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/facelets">
	<h:head>
		<title>
			Greetings
		</title>
	</h:head>

	<h:body>
		<h:form>
			<h:dataTable value="#{greetingBean.greetings}" var="greeting">
				<h:column>
					<h:outputText value="#{greeting}"/>
				</h:column>
			</h:dataTable>
			<h:inputText value="#{greetingBean.greeting}"/>
			<h:commandButton value="Add" action="#{greetingBean.addGreeting}" />
		</h:form>
	</h:body>
</html>

Repack. Redploy. Re...what...the...$CURSE$ is a ZipException and what does it want from me? Oops. Known bug in M3, let's work around it

When the going gets tough, the tough get going. Locate icefaces-2.0-A3.jar from your local repository. Extract it's faces-config.xml, replace your own faces-config.xml with it (it was empty, anyways) and finally rip out the entire faces-config.xml from the icefaces jar (picture the heart scene from Indiana Jones and the Temple of Doom).

I could have said move faces-config.xml from the icefaces jar to the application WEB-INF but that sounded a lot more cool.

Repack. Redeploy. Rejoyce. Business as usual.

Point your browser at http://localhost:8080/Greetings-1.0.0-SNAPSHOT/faces/greetings.xhtml and add some text. Now comes the nice part - open another browser (another brand) or use the incognito mode (you know the mode where we can surf... gifts to our loved ones without leaving traces in the browsing history) or the IE new session to open another session to the application. This is important because browsers commonly share session and cookies between tabs so we want to make sure there's no cheating involved here. Tap in some comment in the other application and they should become visible immediately. Ta-daa...

ICEfaces 2

Now lets bring in some ice components. Wait, didn't you just say they were slipped from alpha3? Yes, the new ones but you are still able to use the components from the 1.8-series by adding some compatibility lib. Let's add the deps to pom.xml

<dependency>
	<groupId>org.icefaces</groupId>
	<artifactId>icefaces-compat</artifactId>
	<version>${icefaces.version}</version>
</dependency>
<dependency>
	<groupId>org.icefaces</groupId>
	<artifactId>icefaces-comps-compat</artifactId>
	<version>${icefaces.version}</version>
</dependency>

And yes, to avoid the dreaded ZipException when deploying the application, you have to move the contents from the faces-config.xml files in the jars in your local repository into your applications own faces-config.xml before assembling and deploying the application.

Next, lets' modify the greetings.xml to add the namespace

<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:ui="http://java.sun.com/jsf/facelets">

and let's change the input field to the iced version that supports effects

<ice:inputText value="#{greetingBean.greeting.text}" effect="#{greetingBean.appear}"/>

and finally we add an effect-producer to GreetingBean

@Produces
@RequestScoped
public Effect getAppear()
{
     return new Appear();
}

Bling-bling!

Some URL cleaning

As I mentioned before, the URL isn't that user-friendly, let's see what we can do about that. Let's start with the http listener port. We have two options - read the documentation or search all xml files that contain the string 8080. Let's go with the second option as I know that's how you do stuff usually anyway. bindings-jboss-beans.xml in server\default\conf\bindingservice.beans\META-INF sounds promising. s/8080/80.

Next - the welcome file. Edit web.xml and add

<welcome-file-list>
	<welcome-file>faces/welcome.xhtml</welcome-file>
</welcome-file-list>

(Hey! It's actually working! I was just getting to the part where I would complain about having to add a redirecting index.html)

Next - the web context root. Sure, it could be fixed by changing the name of the war as they are in synch if not otherwise stated but let's state otherwise. There is no standard way of doing this(?) so let's do the vendor specific thingie instead. Add jboss-web.xml next to web.xml containing

<jboss-web>
    <context-root>Greetings</context-root>
</jboss-web>

Now we have gone from

http://localhost:8080/Greetings-1.0.0-SNAPSHOT/faces/greetings.xhtml

to

http://localhost/Greetings

A note on testing

As you expand your application to bring in new dependencies (such as ICEfaces) always keep in mind that testing those classes also means you have to provide the dependencies in the Arquillian deployment. So be sure to add the dependent jars, the view of the world the Arquillian testing archives have is what you pack in them manually (apart from what the appserver already provides).

This concludes part II, in the next part I'll get to JPA 2 and the static metamodel generator conf.

The goal of this blog post is to walk you through an Java EE 6 application from a simple, static web page until we have a full blown stack that consist of the stuff in the list below. I'm calling this stack Summer because after a long, hard winter Spring may be nice but boy, wait until Summer kicks in ;-)

  • CDI (Weld)
  • JSF 2 (facelets, ICEfaces 2)
  • JPA 2 (Hibernate, Envers)
  • EJB 3.1 (no-local-view, asynchronous, singletons, scheduling)
  • Bean Validation (Hibernate Validator)
  • JMS (MDB)
  • JAX-RS (RESTEasy)
  • JAX-WS
  • Arqullian (incontainer-AS6)

We will pack all this in a single WAR. Just because we can (spoiler: in part IV). Noticed that apart from the component and testing frameworks, they are all standards? That's a lot of stuff. Fortunately, the appserver already provides most of the stuff so you're app will still be reasonably small.

As for the environment I'm using

  • Eclipse (Galileo SR2)
  • JBoss 6.0 M3
  • Maven 3 (beta1)
  • Sun JDK 6
  • m2eclipse 0.10

This will not be your typical blog post where everything goes well - we will hit bugs. There will be curses, blood and guts and drama and we will do workarounds and rewrites as we move along. Pretty much the same as your average day as a software developer probably looks like. I'm also no expert in the technologies I use here so there are probably things that could be done better. Consider this more of a write-down of my experiences in EE6-land that will probably mirror what others are going through. I will also not point you to links or additional information, I assume that if I say RESTEasy, you can google up more information if you are interested.

And I almost forgot: don't panic.

In the beginning: Project setup

So, lets start things off - go and download the stuff mentioned in the environment if you don't already have it. I'm not going to insult your intelligense by walking you through that (remind me to insult it later). Besides, it's pretty straightforward.

Let's make a new Maven project (File -> New -> Project... -> Maven -> Maven Project. We skip the archetype selection and just make a simple project with group id com.acme, artifact id Greetings of version 1.0.0-SNAPSHOT packed as a WAR. Now finish the wizard and now you should have a nice, perfect project. It will never be this perfect again as our next step is adding code to it.

Maven tip-of-the-day for Windows users. Google up on how you change the path to your local repo as it might be somewhere under Documents And Settings which has two effects: classpath gets huge and there could be problems due to the spaces. Change it to something like c:\java\m2repo

The first thing we notice that m2eclipse has J2SE-1.4 as default. How 2002. Besides, that will make using annotations impossible so lets change that. Edit the pom.xml and throw in

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>2.3.1</version>
			<configuration>
				<source>1.6</source>
				<target>1.6</target>
			</configuration>
		</plugin>
	</plugins>
</build>

Save and right-click the project root and go Maven -> Update Project Configuration. Aah, that's better

JSF

Let's wake up JSF. We create a folder WEB-INF in src/main/webapp and throw in a web.xml because no web app is complete without it (enforced by the maven war plugin). OK, actually this can be configured in the plugin but let's keep the web.xml since we'll need it later.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"/>

and an empty faces-config.xml next to it

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
              version="2.0"/>

and in webapp we add a greeting.xhtml like

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/facelets">
	<h:head>
		<title>
			Greetings
		</title>
	</h:head>

	<h:body>
		<h:outputText value="Hello world"/>
	</h:body>
</html>

Will it blend? I mean, will it deploy? Do a mvn clean package and you should have a Greetings-1.0.0-SNAPSHOT in your projects target directory. Throw it into the AS server/default/deploy directory and start up the server and go to

http://localhost:8080/Greetings-1.0.0-SNAPSHOT/faces/greetings.xhtml

The url is not pretty, but the server port, web context root, welcome files and JSF mappings can all be tuned later, let's focus on technologies and dependencies for now. But wait - at which point did we define the JSF servlet and mappings in web.xml? We didn't. It's automagic for JSF-enabled applications.

EJB and CDI

Next step is bringing in some backing beans, let's outsource our greeting. We make a stateless EJB and use it in CDI

package com.acme.greetings;

@Stateful
@Model
public class GreetingBean 
{
	public String getGreeting()
	{
		return "Hello world";
	}
}

The @Stateful defines a stateful session EJB (3.1 since it's a POJO) and the @Model is a CDI stereotype that is @RequestScoped and @Named (which means the lifecycle is bound to a single HTTP request and it has a name that can be referenced in EL and defaults to greetingBean in this case). But we have a problem - the annotations don't resolve to anything. So we need to pick them up from somewhere(tm). Fortunately we can have all the APIs picked up for us by adding the following to our pom.xml

<dependencies>
	<dependency>
		<groupId>org.jboss.spec</groupId>
		<artifactId>jboss-javaee-6.0</artifactId>
		<version>1.0.0.Beta4</version>
		<type>pom</type>
		<scope>provided</scope>
	</dependency>
</dependencies>

Sun Java API artifacts are a bit amusing since getting hold of them can be a bit tricky. First they publish them in the JSR:s and then they treat them like they're top secret. Fortunately Glassfish and now JBoss have started making them available in their repositories (although under their own artifact names, but still)...

We also need to make sure we have set up the JBoss repositories for this according to http://community.jboss.org/wiki/MavenGettingStarted-Users. Have a look at what happened in the projects Maven Dependencies. Good. Now close it and back away. It's getting hairy in there so better trust Maven to keep track of the deps from now on.

The imports should now be available in our bean so we import

import javax.ejb.Stateful;
import javax.enterprise.inject.Model;

and EL-hook the bean up with

<h:body>
	<h:outputText value="#{greetingBean.greeting}"/>
</h:body>

in greetings.xhtml.

Just as no web application is complete without web.xml, no CDI application is complete without beans.xml. Let's add it to WEB-INF

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd" />

Package and redeploy. We get a warning about encoding when compiling so lets add this to our pom.xml

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Back to http://localhost:8080/Greetings-1.0.0-SNAPSHOT/faces/greetings.xhtml SUCCESS! No. Wait. Huge stack trace hits you for 300 points of damage. Let's back up on our EJB, there are still some issues with 3.1 style EJBs in WAR-only-packaging on AS 6 M3. Remove the @Stateful annotation and it becomes a normal CDI managed POJO. Repackage. Redploy. Recoyce.

Testing

Testing is hip nowadays so let's bring in Arquillian. Arquillian is the latest and greatest in EE testing (embedded or incontainer). Start using it now. In a year or so when everone else catch up you can go I've been using it since Alpha. Add the following property to pom.xml:

<arquillian.version>1.0.0.Alpha2</arquillian.version>

and these deps

<dependency>
	<groupId>org.jboss.arquillian</groupId>
	<artifactId>arquillian-junit</artifactId>
	<version>${arquillian.version}</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.8.1</version>
	<scope>test</scope>
</dependency>

and this profile

<profiles>	
	<profile>
		<id>jbossas-local-60</id>
		<dependencies>
			<dependency>
				<groupId>org.jboss.arquillian.container</groupId>
				<artifactId>arquillian-jbossas-local-60</artifactId>
				<version>1.0.0.Alpha2</version>
			</dependency>
			<dependency>
				<groupId>org.jboss.jbossas</groupId>
				<artifactId>jboss-server-manager</artifactId>
				<version>1.0.3.GA</version>
			</dependency>
			<dependency>
				<groupId>org.jboss.jbossas</groupId>
				<artifactId>jboss-as-client</artifactId>
				<version>6.0.0.20100429-M3</version>
				<type>pom</type>
			</dependency>
		</dependencies>
	</profile>
</profiles>

Maven will probably now download the entire internet for you.

Let's write our first test and place it in the test source folder:

package com.acme.greetings.test;

import javax.inject.Inject;

import org.jboss.arquillian.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ArchivePaths;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.impl.base.asset.ByteArrayAsset;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.acme.greetings.GreetingBean;

@RunWith(Arquillian.class)
public class GreetingTest 
{
	@Inject
	GreetingBean greetingBean;

	@Deployment
	public static JavaArchive createTestArchive() 
	{
		return ShrinkWrap.create("test.jar", JavaArchive.class).addClass(
				GreetingBean.class).addManifestResource(
				new ByteArrayAsset("<beans/>".getBytes()),
				ArchivePaths.create("beans.xml"));
	}

	@Test
	public void testInjection() 
	{
		Assert.assertEquals("Hello World", greetingBean.getGreeting());
	}

}

and then we try it out with mvn test -Pjbossas-local-60. If we have the AS running we can save some time, otherwise the manager will start it automagically. Setting the JBOSS_HOME env helps. What happens here is we use Shrinkwrap to create a deployment which consist of our GreetingBean and an empty beans.xml file (for CDI) and the bean is then injected for use in our tests.

This concludes Part I. In part II we will set up ICEfaces and expand our application and in part III we'll set up JPA. Part IV is for MDB and EJB and part V for adding JAX-RS and JAX-WS for importing and exporting stuff.

back to top