My name is Gurkan Erdogdu and I am the CTO of the MechSoft Mechanical and Software Solutions. I have been active in the Java and Java EE platform more than 10 years. Strong supporter for the Free and Open Source Software, and actively participating within the Open Source based foundations like, Apache Software Foundation, JBoss, and recently Open Web Foundation. I am the member of the Apache Software Foundation and Open Web Foundation. Writing blog at gurkanerdogdu@blogspot.com. Gurkan has posted 24 posts at DZone. View Full User Profile

Writing Collapsed EAR and CDI Applications With SIwpas

07.16.2010
| 4577 views |
  • submit to reddit

SIwpas, Simple Web Profile Application Server is a Java EE Web Profile compatible server that contains the Apache Software Foundation projects. SIwpas aim is to integrate Apache Software Foundation(ASF) JavaTM Platform, Enterprise Edition 6 (Java EE 6) Web Profile Specification related projects into the Apache Tomcat 7 for producing a Java EE 6 Web Profile compatible server.

 In this article, I will show a simple Calculator JSF 2.0 example outlining:

  • How to use EJBs in CDI Managed Beans  using dependency injection, 
  • How to use CDI Interceptors and Decorators for EJB session beans
  • How to use CDI Managed beans in JSF 2 runtime

If you would like to try the example, download SIwpas from http://code.google.com/p/siwpas/ , sample Eclipse Web Project "siwpas-sample-collapse" from http://siwpas.googlecode.com/svn/trunk/samples/siwpas-sample-collapse/  and deploy it into the SIwpas!. Hit the URL, http://localhost:8080/siwpas-sample-collapse/calculate.jsf

Example Screens

Initial Screen

Initial Screen

Writing 5 to X and 5 to Y, and click Calculate

Calculation Result

Let's start to code!

We will have a JSF page that adds two numbers and prints result to page.

JSF 2 CDI Managed Bean

We have a JSF CDI Managed bean that we will use it from our JSF page via EL expressions. Our managed bean has  @RequestScoped, means that it will be instantiated at the start of request and discard at end of request by OpenWebBeans CDI container. It's name is "calculator that is explicitly defined by @Named annotation. If we would want default name for our managed bean, just annotate it using @Name without "value". 

Our managed bean injects  an EJB session bean using two different approaches;

  1. Using @Inject annotation : This is provided by the CDI. Here OpenWebBeans injects CDI Session Bean that proxies the actual session bean instance proxy.
  2. Using @EJB annotation :  This is provided by the Java EE. Here OpenWebBeans directly injects Session Beans proxy instance.
Result is the same. Both injection technique works in SIwpas. 
@Named(value="calculator")
@RequestScoped
public class CalculatorBean
{
//Inject using OpenWebBeans
private @Inject ICalculator calculator;

//Inject using @EJB with default interface type of field injection
private @EJB ICalculator injectViaEjbAnnotation;

private int x;

private int y;

private int result;

public String add()
{
this.result = calculator.add(x, y);
System.out.println(injectViaEjbAnnotation.add(x, y) == this.result);
return null;
}

public int getX()
{
return this.x;
}

public void setX(int x)
{
this.x = x;
}

public int getY()
{
return y;
}

public void setY(int y)
{
this.y = y;
}

public int getResult()
{
return this.result;
}

public void setResult(int rESULT)
{
this.result = rESULT;
}
}

 Writing Our Session Bean

We will have stateless session bean. First write an local interface,

@Local
public interface ICalculator
{
public int add(int x,int y);
}

 Then, implementation

@Stateless
@Log
@Interceptors(value={OldTypeInterceptor.class})
public class Calculator implements ICalculator
{
private @Inject SimpleBean simpleBean;

public int add(int x, int y)
{
System.out.println(simpleBean);
return x+y;
}

@PostConstruct
public void postConstruct()
{
System.out.println("In post construct Bean");
}
}

Here, you see some annotations on the Calculator Session Bean. @Stateless is a marker  annotation that  states class is a session bean. @Interceptors is defined by the EJB specification that adds interceptors to the  session bean. 

CDI Interceptors

Interesting thing here is @Log annotation. @Log is the CDI interceptor binding annotation. It adds CDI related interceptor instance to the session bean interceptor stack. It is called after old type interceptor instance.

Here is the code for @Log

@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.TYPE,ElementType.METHOD})
public @interface Log
{

}

 @InterceptorBinding is a marker annotation for interceptor bindings. 

Let's look at the actual interceptor

@Interceptor
@Log
public class LogInterceptor
{
private @Inject SimpleBean simple;

@PostConstruct
public void postConstruct(InvocationContext context)
{
System.out.println(simple);
System.out.println("Post Construct");
}

@PreDestroy
public void preDestroy(InvocationContext context)
{
System.out.println("Pre Destroy");
}

@AroundInvoke
public Object around(InvocationContext ctx) throws Exception
{
System.out.println("Logging");
return ctx.proceed();
}
}

This is CDI based interceptor class. It is annotated with @Interceptor and @Log. It applies to all beans that are annotated with @Log, like our calculator bean.

 CDI Decorators

 CDI decorators are similar to CDI interceptors. Basic difference is that their methods are unique to some bean classes. Let's look at decorator class

@Decorator
public class AddDecorator implements ICalculator
{
private @Inject @Delegate ICalculator calculator;

public int add(int x, int y)
{
return calculator.add(x, y);
}

}

Here, we annotate AddDecorator class with @Decorator. AddDecorator class implements ICalculator and injects delegate instance with @Inject @Delegate. Here, @Delegate is important, because it provides information to CDI container regarding which bean instances will have this decorator in their's decorator stack. Here, AddDecorator is applied to all bean instances that have ICalculator in their API types. We can also add qulifier into the @Delegate injection points. In this case, decorator will be available for beans that have both same API type and qualifier. If there is no explicit qualifier, like above, qualifier is @Default.

CalculatorBean has an API type ICalculator  and qualifier @Default. Therefore,AddDecorator is added into its decorator stack. Decorators are called after interceptors. 

Enabling Intereptors and Decorators

To use interceptors and decorators, we have to enable them in the bean archive. Therefore we include them into WEB-INF/beans.xml file.

<beans>
<interceptors>
<class>siwpas.sample.interceptor.LogInterceptor</class>
</interceptors>

<decorators>
<class>siwpas.sample.decorator.AddDecorator</class>
</decorators>
</beans>

 Now, they can be used inside the bean archive.

Our JSF Page

Let's look at our JSF page, look at how we use EL expressions with managed bean name, "calculator"

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Collapsed EAR</title>
</h:head>
<h:body>
<h:form>
<h:outputText>X :</h:outputText>
<h:inputText value="#{calculator.x}"></h:inputText>
<h:outputText>Y :</h:outputText>
<h:inputText value="#{calculator.y}"></h:inputText>

<h:commandButton value="Calculate" action="#{calculator.add}"></h:commandButton>
</h:form>
<div>
<h:outputText value="Result : #{calculator.result}"></h:outputText>
</div>
</h:body>
</html>

Our web.xml for some JSF stuff

<web-app 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"
version="3.0">

<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jsp</param-value>
</context-param>

<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>*.jsf</url-pattern>
</servlet-mapping>

</web-app>

 How it Works

When a request comes from browser, CDI container looks for a bean with name "calculator". It finds the CalculatorBean and looks it's scope. In our example, our scope is @RequestScoped. It instantiates its instance and save it in the request scope. CDI container injects all of its dependencies (both CDI and Java EE dependencies. You can also inject @Resource, @WebServiceRef, @PersistenceContext, @PersistenceUnit Java EE components.)

When EL method "add" is executed, CDI container executes all interceptors, decorators of the EJB bean and finally execute the bean "add" method. After request is completed, request scoped is destroyed and all of its instances are discarded. Response is sent to the browser.

Conclusion

Java EE 6 simplifies the development of the web applications. That is the main motivation behind Java EE 6! It also provides Java EE Web Profile that contains only standards for implementing Java EE web applications.

Further Info

SIwpas Page : http://code.google.com/p/siwpas/

Apache OpenWebBeans : http://openwebbeans.apache.org

Apache MyFaces : http://myfaces.apache.org

Apache OpenJPA : http://openjpa.apache.org

Apache OpenEJB : http://openejb.apache.org

Apache Tomcat : http://tomcat.apache.org

Java EE 6 Web Profile :http://jcp.org/en/jsr/detail?id=316

Published at DZone with permission of its author, Gurkan Erdogdu.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Michal Huniewicz replied on Thu, 2010/07/22 - 4:58am

Gurkan, thanks for the article.

I got a question though. You said:
Our managed bean has  @RequestScoped, means that it will be instantiated at the start of request and discard at end of request by OpenWebBeans CDI container.

From my observations, it isn't so, as I get TWO instances of a @RequestScoped bean per request, it's just that submitted properties are copied (but regular instance variable are gone).

Could you please clarify on that?

EDIT: Nah, my bad. Used @Named instead of @ManagedBean and it gave me strange behaviors. :)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.