JBoss Seam

Upgrading a Seam 2 app to JBoss 7

I recently went through the process of upgrading a Seam 2.X application to JBoss 7.1.1. While Marek Novotny’s tutorial will lead you down the right path, there was one issue that led me down a rabbit hole.

Initially, the intention was to use Hibernate 3 as a JBoss module allowing it to be shared among applications. This deviates from the tutorial, but simplifies the library requirements if you are deploying several Seam 2 applications to the same server. Unfortunately, this issue cropped up:

14:54:13,042 WARN  [org.jboss.modules] 
  (MSC service thread 1-4) Failed to define class 
  org.jboss.as.jpa.hibernate3.infinispan.InfinispanRegionFactory 
  in Module "deployment.jboss-seam-booking.ear:main" from Service Module 
  Loader: java.lang.LinkageError: Failed to link org/jboss/as/jpa/hibernate3/
  infinispan/InfinispanRegionFactory (Module "deployment.jboss-seam-
  booking.ear:main" from Service Module Loader)
...
Caused by: java.lang.NoClassDefFoundError: 
  org/hibernate/cache/infinispan/InfinispanRegionFactory
...
Caused by: java.lang.ClassNotFoundException: 
  org.hibernate.cache.infinispan.InfinispanRegionFactory from 
  [Module "deployment.jboss-seam-booking.ear:main" from Service Module Loader]

Apparently this problem will be resolved in JBoss 7.1.2, but in order to get something working now an alternative approach was necessary.

The next step was to attempt to bundle the Hibernate 3 jars within the application as discussed in the tutorial. This worked fine except that JBoss still attempted to manage Hibernate 3 as a JPA provider. This produced the same exception shown above.

After researching the issue, the following setting was discovered. This setting is specified for each persistence unit in persistence.xml:

<properties>
   <property name="jboss.as.jpa.managed" value="false"/>
</properties>

Success! This setting stops the JBoss container from managing Hibernate 3 as a JPA provider. Once this setting was changed, the application deployed successfully.

By |JBoss Seam|Comments Off on Upgrading a Seam 2 app to JBoss 7

JBoss Seam: Agile RIA Development Framework

JBoss just published a white paper that describes how Seam enables rapid development of RIAs by eliminating technology hurdles and placing developer focus back on solving business problems. Specific enterprise use cases demonstrate how increasingly complex features can rapidly be introduced into a software product with Seam in an iterative fashion.

The white paper is written in a way that avoids a technical deep-dive so that regardless of technical expertise, the value of Seam can be well understood. This allows not only developers but also management understand why JBoss Seam is the right framework for an organization’s next agile RIA development project. I authored the paper in collaboration with my colleague Nirav Assar.

Enterprise Mashups with RESTful Web Services and jQuery (Part 1)

RESTful web services and jQuery make it easy to create an enterprise mashup. This 2 part article discusses how to create a simple enterprise mashup using jQuery. Part 1 introduces what is required of your enterprise services, the simplicity of JSON, and how to consume your RESTful web services using jQuery. Part 2 will cover consuming services from across the enterprise with JSONP, accessing secure resources, and handling error conditions.

Enterprise Web Services: Got REST?

First things first, we need RESTful web services to provide the data we intend to consume. Are there already web services exposed in your enterprise that provide a RESTful API? Do these services support JSON? If not, there are a wide array of technologies that make it simple to expose RESTful web services from your existing applications.

If you have RESTful web services, but they only support an XML result it is quite simple to support JSON with JAX-RS. JAX-RS uses the HTTP Accept header to determine what media type should be sent back as a result. The following HTTP header entry would indicate that the client is requesting a JSON result:

Accept: application/json

RESTEasy provides a portable JAX-RS implementation that makes it simple to expose services supporting a variety of media types. If you happen to be using Seam, exposing RESTful services through RESTEasy is a no-brainer. See the Seam documentation for more details.

Why use JSON when you have XML?

It is now common to expose REST services that return a result in JSON format. The format is described as a lightweight data-interchange format. The major advantage to JSON is that it is JavaScript native format. This means if a RESTful service is invoked through a JavaScript AJAX call and returns a JSON result, the data returned by the service can be used without additional parsing.

For example, we could have the following URL tied to a consultants list resource.

http://solutionsfit.com/services/rest/consultants

When a GET request is received for this URL the following JSON response is generated.

[{
 "consultant" : {
   "firstName": "Jacob",
   "lastName": "Orshalick",
   "blogFeed": "http://solutionsfit.com/blog/feed"
 },
{
 "consultant" : {
   "firstName": "Nirav",
   "lastName": "Assar",
   "blogFeed": "http://assarconsulting.blogspot.com/feeds/posts/default"
 }
}]

If this JSON result was stored in a JavaScript variable named solutionsfitConsultants, I could alert the user of Jacob Orshalick’s blog URL with the following JavaScript snippet.

var consultant = solutionsfitConsultants[0].consultant;

alert(consultant.firstName + ' ' + consultant.lastName);

Obviously this makes it very easy to render results to the user by removing the additional step of parsing that is required with XML.

Request and display JSON data with jQuery

jQuery makes it simple to consume a RESTful service providing a JSON result through a simple AJAX call. Let’s look at an example. The following HTML provides the shell for the service results I want to display in my mashup.

<table width="100%">
  <thead>
    <tr>
      <th>
        Consultant
      </th>
      <th>
        Blog Feed
      </th>
    </tr>
    <tbody id="consultants">
    </tbody>
</table>

The jQuery getJSON function makes it simple to consume the service that provides us the list of consultants. The getJSON function sends an AJAX GET request to the resource URL with an HTTP Accept header of application/json.

jQuery.getJSON(
  'http://solutionsfit.com/services/rest/consultants&callback=?',
  function(data) {
    jQuery.each(data, function(i,item) {
      var consultant = item.consultant;
      var consultantHtml = '<tr>' +
        '<td>' + consultant.firstName + ' ' 
          + consultant.lastName + '</td>' +
        '<td><a href="' + consultant.blogFeed + '">' +
          'Blog Feed</a></td>' +
        '</tr>';

      jQuery("#consultants").append(consultantHtml);
    });
  }
);

Notice that we also use the jQuery each function to loop through the JSON results. Each result in the returned JSON array is set into the variable item.

We then generate the HTML to add to the table for each consultant and set it into the consultantHtml variable. We then select the

element that will contain the consultant results using it’s element ID and use the jQuery append function to append the consultantHtml.

When the page is fully rendered, the resulting HTML will be:

<table width="100%">
  <thead>
    <tr>
      <th>
        Consultant
      </th>
      <th>
        Blog Feed
      </th>
    </tr>
    <tbody id="consultants">
      <tr>
        <td>
          Jacob Orshalick
        </td>
        <td>
          <a target="_blank" 
              href="http://solutionsfit.com/blog/feed/">
            Blog Link
          </a>
        </td>
      </tr>
      <tr>
        <td>
          Nirav Assar
        </td>
        <td>
          <a target="_blank" href=
            "http://assarconsulting.blogspot.com/feeds/posts/default/">
            Blog Feed
          </a>
        </td>
      </tr>
    </tbody>
</table>

Note that only JavaScript libraries and HTML have been used to consume the service. This provides the flexibility to render this content in a web application, a portal, or even a static HTML page!

That’s it for round one of enterprise mashups. Stay tuned for part 2 which will discuss how to gather data from across the enterprise with JSONP and how accessing secured services is made easy.

Serving up JSONP from your JAX-RS Web Services

If you are developing RESTful services that will be consumed by AJAX clients on different servers, you will likely need to support JSONP. JSONP allows your RESTful web services to support cross-domain communication by enabling your clients to bypass the same-origin policy browser restriction. While some JAX-RS implementations support JSONP, this article demonstrates how any JAX-RS web service can support JSONP through a servlet filter.

Why you would use JSONP

Cross-domain communication is a common problem when developing rich web clients that utilize RESTful web services. Browsers impose the same-origin policy which is described in depth in: Cross-domain communications with JSONP.

To paraphrase the problem, a script loaded from one location, say http://solutionsfit.com/blog/, could not execute an AJAX request that gets properties from a service outside of the domain solutionsfit.com. The diagram below describes this scenario.

If the AJAX request to geonames.org returned a basic JSON response, the browser would not allow access to this data. This is a problem for many AJAX applications, especially mashups, which may access a number of resources to generate content. JSONP (JSON with padding) solves this problem by wrapping the returned data with a function.

The function is invoked as a callback once the AJAX call completes with the JSON results passed as an argument. This requires that the callback function be defined in the web page. So, in the diagram above, if the response from geonames.org returns a function that takes the JSON result as an argument, we can bypass the same-origin policy. This of course requires the web service being invoked to support JSONP.

Creating a Servlet Filter to process JSONP requests

JAX-RS does not support JSONP by default. Some implementations provide an extension to produce JSONP content but some do not (see the RESTEasy JIRA issue). As a Seam user, RESTEasy is the perfect option for exposing RESTful services due to it’s tight integration. As RESTEasy does not currently support JSONP, I needed a solution. Fortunately, you can add support of JSONP using a servlet filter. The following implementation is a naive approach, but shows the general idea.

public class JSONPRequestFilter 
     extends org.jboss.seam.web.AbstractFilter {
  public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain chain) throws IOException, ServletException {
    if (!(request instanceof HttpServletRequest)) {
       throw new ServletException("This filter can " +
         " only process HttpServletRequest requests");
    }

    HttpServletRequest httpRequest = (HttpServletRequest) request;
      
    if(isJSONPRequest(request))
    {
      ServletOutputStream out = response.getOutputStream();

      out.println(getCallbackParameter(httpRequest) + "(");
      chain.doFilter(request, response);
      out.println(");");

      response.setContentType("text/javascript");
    }
    else
    {
      chain.doFilter(request, response);
    }
  }

  private String getCallbackMethod(HttpServletRequest httpRequest)
  {
    return httpRequest.getParameter("callback");
  }

  private boolean isJSONPRequest(HttpServletRequest httpRequest)
  {
    String callbackMethod = getCallbackMethod(httpRequest);
    return (callbackMethod != null && callbackMethod.length() > 0);
  }
}

This filter processes any request that provides a callback function parameter (the signature of a JSONP request). It wraps the JSON return data with a function, the value of the callback parameter. In my appication I needed to support multiple media return types so I implemented a more robust approach that checks the Accept header to verify that text/javascript or application/javascript is an accepted media type. It also wraps the HttpServletRequest to inform RESTEasy that application/json is the preferred media type. This ensures that RESTEasy provides a JSON response.

Configuring the JSONP Servlet Filter

To configure the filter to apply to RESTful web service requests, you would simply add the following to your project’s web.xml.

<filter>
  <filter-class>com.solutionsfit.rest.JSONPRequestFilter</filter-class>
  <filter-name>JSONPRequestFilter</filter-name>
</filter>
  
<filter-mapping>
  <filter-name>JSONPRequestFilter</filter-name>
  <url-pattern>/seam/resource/rest/*</url-pattern>
</filter-mapping>

The url-pattern should match the base URL pattern for your RESTFul web service requests. The default base URL for a Seam configuration is shown above. Once this is complete, you can bypass the same-origin policy by making JSONP requests to your JAX-RS web services.

Security Considerations

As a final note, be aware that there are security considerations associated with the use of JSONP and cross-site request forgery attacks. The same-origin policy exists to eliminate this issue, so appropriate precautions should be taken to ensure that security is enforced. Always ensure that you understand the implications of using JSONP prior to enabling it for your web services and prior to invoking a service that provides JSONP support.

Second-level caching: Still an effective performance tuning technique

I keep reading discussions regarding the performance of Seam applications. These discussions are generally centered around the performance overhead of the interception techniques used by Seam. While this is definitely a valid issue in certain scenarios, see this excellent forum discussion started by Tobias Hill, many tend to blame Seam too quickly for their performance issues. If it is taking many seconds or even minutes to load a page, in most cases your application is more likely to blame than Seam.

In my experience, most performance issues stem from data access. Improperly tuned queries (a common culprit) and not using the second-level cache of your ORM provider when appropriate can lead to some serious performance implications in your application. While second-level caching is nothing new, here I will describe why it is important to a Seam application and how you can improve performance using Hibernate’s second-level cache provider.

Before I go any further, note that second-level caching is not the only caching solution you have available if you are using Seam. Seam provides a multi-layer caching solution that allows you to cache page fragments and objects easily while abstracting away the details. You can read all about Seam’s multi-layer caching solution in Chapter 34 of Seam Framework: Experience the Evolution of Java EE.

Loading Reference Data

Seam provides an elegant solution to the common problem of associating entities based on a dropdown selection. Take the common booking example with Seam. We are attempting to book a Hotel and we need to input credit card information. The type of credit card is likely to be a dropdown, but that dropdown is going to need to associate to a CreditCardType entity.

@Entity
public class CreditCardType implements Serializable
{
  @Id
  private Long providerId;
  private String description;
  // ... ...
}

Our Booking class then needs a reference to the CreditCardType class.

@Entity
public class Booking implements Serializable
{
  @Id
  private Long id;
  // ... ...
  @ManyToOne
  private CreditCard creditCard;
  // ... ...
}

To make this task simple, Seam provides the <s:entityConverter /> component which ensures that the user selection is converted to an entity for association with your object.

<h:selectOneMenu id="creditCard" value="#{booking.creditCard}"
    required="true">
  <s:selectItems noSelectionLabel="" var="type"
    value="#{creditCardTypes}"
    itemLabel=”#{type.description}” />
    <s:convertEntity />
  </s:selectItems>
</h:selectOneMenu>

As you can see this is quite simple, but we need to load the creditCardTypes into the conversation context in order to associate an instance to our entity. This is because the creditCardTypes need to be managed instances in the conversation-scoped persistence context. It is quite simple to accomplish this through a @Factory method scoped to the conversation.

@Name(“bookingAction”)
@Scope(CONVERSATION)
public class BookingAction implements Serializable {
  // ... ...
  @In private EntityManager entityManager;

  @Factory(“creditCardTypes”)
  public List<creditcard> loadCreditCardTypes()
  {
    return entityManager.createQuery("select c from " +
      "CreditCardType as c order by c.description").getResultList();
  }
  // ... ...
}

Great, so now we can load our entities into the context and associate them using a dropdown, so what’s the catch? The factory method only executes once, right?  The problem is that the query that loads the CreditCardType instances into the conversation context executes every time a new conversation requests the dropdown list.  This can cause the initial page load to lag.

This may not be a problem in this simple case as we only have this one dropdown, but what if we have many dropdowns on the screen? Even further, what if this dropdown list is used by several conversations? Doesn’t it seem wasteful to hit the database every time we need it? We can avoid the database hit and still achieve the same benefits by using second-level caching.

Second-level caching with Hibernate

Second-level caching is intended for data that is read-mostly. It allows you to store the entity and query data in-memory so that this data can be retrieved without the overhead of returning to the database. You can configure the cache expiration policy, which determines when the data will be refreshed in the cache (e.g. 1 hour, 2 hours, 1 day, etc.) according to the requirements for that entity. An entity like CreditCardType is certainly read-mostly so it is definitely a good candidate for the second-level cache.

Using Hibernate, it is quite simple to cache an entity by using the @Cache annotation.

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class CreditCardType implements Serializable {
  // ... ...
}

We then need to include the jars necessary for a second-level cache provider. I tend to use Ehcache as I find it simple to use and it is fully supported by Seam’s multi-layered caching solution.

Once you include the appropriate jars, you must configure Hibernate to use second-level caching. In your persistence.xml file, add the following properties for your persistence-unit definition.

<persistence-unit name="myBookingDS">
  ... ...
  <properties>
    <property name="hibernate.cache.provider_class"
      value="org.hibernate.cache.EhCacheProvider" />
    <property name="hibernate.cache.use_second_level_cache"
      value="true" />
    <property name="hibernate.cache.use_query_cache"
      value="true" />
    ... ...
  </properties>
<persistence-unit>

The hibernate.cache.provider_class should be specific to the cache provider you are using. Hibernate supports a number of implementations as described in the reference documentation.

Notice that we also set hibernate.cache.use_query_cache to true. This allows us to take the caching a step further by caching the query itself and not just the entities. In order to cache the query, we can take two approaches: use the Hibernate Session API or the Hibernate @NamedQuery annotation. Let’s look at the Hibernate Session API approach first. Our factory method above changes to the following:

@Name(“bookingAction”)
@Scope(CONVERSATION)
public class BookingAction implements Serializable {
  // ... ...
  @In private EntityManager entityManager;

  @Factory(“creditCardTypes”)
  public List<CreditCard> loadCreditCardTypes()
  {
    Session session = (Session) entityManager.getDelegate();

    Query query = session.createQuery("select c from " +
      "CreditCard as c order by c.description");
    query.setCacheable(true);

    return query.list();
  }
  // ... ...
}

Now you will notice in the logs that once the creditCardTypes have been loaded, even a new conversation does not cause a database call the next time these entities are requested. The query and the entities are loaded directly from the second-level cache in-memory.

The other approach is to use the Hibernate @NamedQuery annotation which gives the option to cache your query.

@Entity
@NamedQuery(name="getCreditCardTypes",
  query="select c from CreditCard as c " +
      "order by c.description",
  cacheable=true)
public class CreditCardType implements Serializable
{
  @Id
  private Long id;
  private String description;
  // ... ...
}

The @NamedQuery can then be retrieved through the createNamedQuery() method in the EntityManager API.

While we are only showing one scenario here, there are many cases where second-level caching can be applied in your application.

No silver bullet

By no means am I claiming here that second-level caching is the solution for every scenario. Performance tuning is somewhat of an art. It is definitely handy to know the various potential hot spots when tuning an application, but a solution that works in one case may not work in others. Simply read up on the various approaches and techniques to tune your application so that you can apply each technique when the time is right.

Seam Framework promotion at JavaRanch

Michael Yuan and I will be answering questions about the book and Seam in general at JavaRanch this week in the JBoss forum.  If you would like to ask us a question feel free to stop by!  They will be selecting four random posters in the forum to win a free copy of the book provided by Prentice Hall. We look forward to a good week of questions and hope to see you there!

Seam UI Refcard Released

As a follow-up to the Core Seam Refcard, DZone has now released my companion reference for using Seam with JSF. The Seam UI Refcard has now been released through the DZone Refcardz site and includes:

  • Simplifying JSF
  • Page Navigation
  • JSF Component Annotations
  • JSF Component Tags
  • Hot Tips and more…

So download the Seam UI Refcard here and please send your comments and feedback to refcardz@dzone.com. For in-depth coverage of Seam 2.1, you can also purchase the just released Seam Framework: Experience the Evolution of Java EE.

In a related story, JavaLobby posted an interview with me to coincide the release of the reference card. Check it out!

Seam Framework: Available in Paperback

I just got my hands on a hard copy of my book, Seam Framework: Experience the Evolution of Java EE. For those who have been awaiting the paperback release, you can order your copy today from Amazon or Barnes and Noble. The book is the second edition of the best-selling JBoss Seam covering the latest and greatest features of Seam 2.1 and Web Beans (JSR-299). Check it out!

Seam Framework: All Chapters Now Available

All early access chapters for Seam Framework: Experience the Evolution of Java EE have now been released through Safari Rough Cuts. The only book specifically covering Seam 2.1 now includes new chapters on Seam 2.1 security, an introduction to Web Beans (JSR-299), multi-layer caching, using Maven with Seam, and much more! You can download the source code or learn more here.

These chapters are still undergoing copy-editing so if you would like to pre-order the final print edition, you can order from amazon today. The final edition is scheduled for print release in February. Check it out!

By |JBoss Seam, JBoss Seam 2E News|Comments Off on Seam Framework: All Chapters Now Available

Core Seam 2.1 Refcard Released

Have you been searching for a quick reference for setting up and configuring your Seam applications? Well search no more! The Core Seam Refcard has now been released through the DZone Refcardz site and includes:

  • Component annotations
  • Seam-gen commands and configuration
  • Conversation management
  • Common components.xml configuration
  • Seam security
  • The Seam application framework
  • Hot tips and more…

So download the Core Seam Refcard here and please send your comments and feedback to refcardz@dzone.com. For in-depth coverage of Seam 2.1, you can also purchase the upcoming Seam Framework: Experience the Evolution of Java EE. Enjoy!