Вы находитесь на странице: 1из 28

Issue March 2012 | presented by

www.jaxenter.com
TM

Originally developed under the name Web Beans, the CDI specification was created to fill the gaps between EJB on the back end, and JSF in the view layer. There are currently three CDI implementations available: JBoss Weld,

Apache OpenWebBeans, and Caucho CanDI. Several libraries already provide CDI extensions, such as Apache DeltaSpike, JBoss Seam 3, and Apache MyFaces CODI. Deep-dive into the world of CDI with this issue of JTJ.

CDI
CDI Introduction
A Hollywood Story

#16

Extension Programming
Implementing Additional Functionality with CDI

Apache DeltaSpike
Creating a CDI Extension

Arquillian
Testable Development of CDI

Editorial

CDI much more than a hype!


Putting together a JavaTechJournal issue about CDI is a hard task, one might think. But it was actually completely easy to get all those busy people on board helping out with articles. There are multiple reasons for this. The first one is that CDI was a community-driven technology from the very beginning. The Java Expert Group for CDI was open from the very start and continues to do so. It is one of the prototypes for JSR.next and formed a great community because of this openness. And this community gives back 100 times the effort you put into it. The other reason is that its really fun to work with this technology. CDI is not some freaky artificial phantasm that has no common ground with any real business. Nor is it a long-time-grown monster that has tons of historical burden to carry with it. If you look at a project using CDI, you get the feeling that its really done right. Most of the things you do with CDI just works (tm). CDI felt cool at the first touch but unlike other hyped technologies it still feels cool now, after a few years! Whats more, CDI has already proved itself in big projects. One of my CDI-based projects went live in August 2010, and it serves more than 40,000 concurrent users, easily getting five million page hits per day. And I do know of big banks and insurance companies who handle even more throughput with CDI-based projects! In this JavaTechJournal, we will cover CDI full circle. In our introductory article, we will lay out the basics of the dependency injection core itself: its historical background, basic mechanisms, and key features. A second article will provide the fundamentals of CDI Extension programming, demonstrating how the CDI extension mechanism can be used to implement additional functionality in a portable, vendor-independent way. Another article will explain the CDI Ecosystem, showing how the popular projects Seam3 and MyFaces CODI became Apache DeltaSpike. Last but not least, we will shed a light on testing CDI applications with the JBoss Arquillian framework. Please allow me to finally thank all the authors and all those people who helped us reviewing and editing the content and providing ideas, like Shane Bryzak (JBoss), Matt Benson (ASF) and many more. Mark Struberg

Index

A Hollywood Story

Contexts and Dependency Injection for Java EE (JSR-299)


Mark Struberg and Pete Muir

3 9 14 18

CDI Extension Programming


Implementing additional functionality in a portable, vendor-independent way
Ronald Steininger, Arne Limburg, and Mark Struberg

Apache DeltaSpike Closes the Gaps


Gerhard Petracek and Jason Porter

Creating a stable, reliable and truly portable CDI extension

Arquillian Makes Testing a Breeze


Testable development of CDI
Dan Allen, Aslak Knutsen, and Andrew L. Rubinger

www.JAXenter.com | March 2012

CDI Introduction

Contexts and Dependency Injection for Java EE (JSR-299)

A Hollywood Story
CDI brings Dependency Injection to a new level. Within the first two years of its existence, CDI quickly rose from an unknown little JSR to now being unanimously considered the star of Java EE 6. This article provides an overview of the major CDI features, explores a sample web application, and outlines some of the basic mechanisms of the framework.

by Mark Struberg and Pete Muir


One of the most exciting features of CDI is to allow anyone to write powerful extensions to the core Java EE platform, even change core behaviour itself. These extensions are fully portable across any environment which supports CDI. Several libraries already provide CDI extensions, such as Apache DeltaSpike, JBoss Seam 3, and Apache MyFaces CODI. it became obvious that most features were very useful for any Java environment, including Java SE. At the same time, both Guice and Spring communities had begun an effort to specify the basics of injection as JSR-330: Dependency Injection for Java (nicknamed AtInject). Considering that it did not make sense to provide a new dependency injection container without collaborating on the actual injection API, the AtInject and CDI expert groups worked closely together to ensure a common solution across dependency injection frameworks. As a result, CDI uses the annotations from the AtInject specification, meaning that every CDI implementation fully implements the AtInject specification, just like Guice and Spring. CDI and AtInject are both included in Java Enterprise Edition 6 (JSR-316) and thus an integral part of almost every Java Enterprise Edition server.

A little bit of history


Originally developed under the name Web Beans, the CDI specification was created to fill the gaps between Enterprise Java Beans (EJB) on the back end, and JavaServer Faces (JSF) in the view layer. The first draft targeted only Java Enterprise Edition (Java EE), but during the creation of the specification

www.JAXenter.com | March 2012

CDI Introduction

Essential CDI

Before we go on to dive into some code, lets take a quick look at some key CDI features: Type Safety: Instead of injecting objects by a (string) name, CDI uses the Java type to resolve injections. When the type is not sufficient, a Qualifier annotation can be used. This allows the compiler to easily detect errors, and provides easy refactoring. POJOs: Almost every Java object can be injected by CDI! This includes EJBs, JNDI resources, Persistence Units and Persistence Contexts, as well as any object which previously would have been created by a factory method. Extensibility: Every CDI container can enhance its functionality by using portable Extensions. The attribute portable means that those CDI Extensions can run on every CDI container and Java EE 6 server, no matter which vendor. This is accomplished by a well-specified SPI (Service Provider Interface) which is part of the JSR-299 specification. Interceptors: It has never been easier to write your own Interceptors. Because of the portable behaviour of JSR-299, they now also run on every EE 6-certified server and on all standalone CDI containers. Decorators: These allow to dynamically extend existing interface implementations with business aspects. Events: CDI specifies a type-safe mechanism to send and receive events with loose coupling. Unified EL integration: EL-2.2 opens a new horizon in regard of flexibility and functionality. CDI provides outof-the-box support for it!

is also application-scoped. Here we see our first injection the configuration field is not set by the applications code, but is injected by CDI. The @Inject annotation tells CDI to perform the injection (listing 1). Our application also identifies the current user (note that it doesnt try to perform any authentication or authorization, we simply trust everyone!), and the current user is scoped to the HTTP session. CDI provides the session scope, which ensures that you will get the same instance of an object per HTTP Session (in a web application). By default, CDI beans are not available for use in JSF via the Unified Expression Language. In order to expose it for use by JSF and EL, we add the @Named annotation (listing 2). Now that we have a working application, lets explore some of the CDI features we are using.

Listing 2
@SessionScoped @Named public class User { public String getName() {..} .. } The web page is implemented with JSF 2. We suggest you use a controller class: @RequestScoped @Named public class Mail { private @Inject MailService mailService; private @Inject User user; private String text; // + getter and setter private String recipient; // + getter and setter public String sendMail() { mailService.send(user.getName(), recipient, text); return "messageSent"; // forward to 'message sent' JSF2 page } }

Diving into CDI

Lets start by exploring a sample web application. The application allows you to send e-mail via a web form fairly simple. We only provide code fragments, but they should be enough to get the gist of how CDI is used. After showing each part of the application, we will discuss the details in the next chapter. For our mail application, we need an application-scoped MailService. Application-scoped objects are essentially singletons the container will ensure you always get the same instance whenever you inject it into your application. The replyTo address is taken from the ConfigurationService which

Listing 1
@ApplicationScoped public class MyMailService implements MailService { private @Inject CongurationService conguration; public send(String from, String to, String body) { String replyTo = conguration.getReplyToAddress(); ... // send the email } }

The only missing part now is the JSF page itself, sendMail.xhtml: <h:form> <h:outputLabel value="Username" for="username"/> <h:outputText id="username" value="#{user.name}"/><br/> <h:outputLabel value="Recipient" for="recipient"/> <h:inputText id="recipient" value="#{mail.recipient}"/><br/> <h:outputLabel value="Body" for="body"/> <h:inputText id="body" value="#{mail.body}"/><br/> <h:commandButton value="Send" action="#{mail.send}"/> </h:form>

www.JAXenter.com | March 2012

CDI Introduction

Basic mechanisms
Sometimes it's very helpful to look behind the scenes of a framework to understand at least the very basic mechanisms. Thus we like to explain a few of those techniques first. Dependency Injection: DI is sometimes described as the Hollywood Principle don't call us, we call you. It means that we let the container manage the creation of instances and inject it instead of creating them ourselves with the new operator. Of course, even in DI containers, nothing happens without anyone triggering this process. For a JSR-299 container, this trigger is a call to one of the method
T BeanManager#getReference(Bean<T> type, Qualier... qualiers);

Terminus Contextual Instance: Contextual Instances are exactly our singleton instances per scope, our session singletons, request singletons, etc. Usually a user never uses a Contextual Instance directly, but only via its Contextual Reference Terminus Contextual Reference: By default, a CDI container wraps all Contextual Instances via a proxy and only injects those proxies instead of the real instances. In the CDI specification those proxies are called Contextual Reference. There are plenty of reasons why CDI uses proxies by default: Serialisation: Instead of serialising the full object, we only need to serialise the proxy. On de-serialisation, it will automatically connect to the right Contextual Instance again. Scope differences: With proxies, it is possible to inject a @SessionScoped UserSettings into an @ApplicationScoped MailService because the Proxy will connect to the right UserSettings itself. Interceptors and Decorators: a proxy is the perfect way to implement interceptors and decorators in a non-intrusive way.

which returns an instance of the given type T. By doing so, it will not only create the returned instance, but also all of its @Inject-annotated children in a recursive way. Usually the getReference(Bean<T>) method is not called manually, but internally by the Expression Language Resolver. By writing something like
<h:inputText value="#{mailForm.text}"/>

The lifecycle of a CDI container


Let's look at an easy scenario with a CDI container inside a plain Servlet engine such as Apache Tomcat. If a WebApplication gets started, a ServletFilter will automatically also start your CDI container which will firstly register all CDI-Extensions available on the ClassPath and then start with the class scanning. All ClassPath entries with a META-INF/beans.xml will be scanned and all classes will be parsed and stored as Managed Bean (interface Bean<T>) meta-information inside the CDI container. The reason for scanning this information on startup is to: first. detect errors early and second, vastly improve the performance at runtime. To be able to handle all the CDI Scopes correctly, a CDI container simply uses standard Servlet callbacks like Servlet RequestListener and HttpSessionListener.

the ELResolver will look for the Bean<T> with the name mailForm and resolve the instance. Scopes, contexts, singletons: Each of a CDI containers managed objects is a singleton in the original sense specified by Ward Cunningham, who invented not only the Wiki but also, together with Kent Beck, introduced design patterns into computer science in 1987. A singleton in this sense means that there is exactly one instance in a well-specified context. In a comment on Refactoring to Patterns by Joshua Kerievsky, Ward noted: There is a proper context for every computation. So much of object-oriented programming is about establishing context, about balancing the lifetimes of variables, causing them to live the right length of time and then die gracefully. CDI is all about creating singletons in a well-specified context. In our case, the lifecycle of instances is defined by their scopes. A @SessionScoped-annotated bean exists exactly once per session. We could also name it a session singleton. If a user accesses our @SessionScoped bean for the first time, it will get created and stored inside the session. Every subsequent access will return exactly this same instance. When the session ends, all the CDI-managed instances stored inside it will also be properly destroyed. If we have a @RequestScoped bean, we could call it a request singleton, a @ConversationScoped bean is a conversation singleton, etc. Terminus Managed Bean: There are a few terms used in the CDI specification which need a short explanation. The term Bean in Java is already pretty well-established and means a POJO (Plain Old Java Object) with getters and setters. The terminus technicus Managed Bean now means something completely different. It doesn't refer to instances of a class but meta-information which can be used to create those instances. It is represented by the interface Bean<T> and will be gathered on container startup via classpath scanning.

Standard scopes
JSR-299 defines the most important scopes to build classic web applications: @ApplicationScoped @SessionScoped @ConversationScoped @RequestScoped Those scopes are meta-annotated as @NormalScope which means they have a well-defined lifecycle. Beside those, there is another non-normal scope: @Dependent. If a class doesn't have any explicit CDI scope annotation or is explicitly annotated with @Dependent, an instance will be created for each and every InjectionPoint and will share the lifecycle of the contextual instances they get injected into. An example: if a @Dependent MySecurityHelper is injected in a @RequestScoped MyBackingBean, then the MySecurityHelper instance will be destroyed along with the MyBack-

www.JAXenter.com | March 2012

CDI Introduction

ingBean instance at the end of the request. If you @Inject the MySecurityHelper into a @SessionScoped UserSettings object, it will also be treated as @SessionScoped.

Qualifiers
If an application needs multiple implementations of one and the same interface, this previously has been solved by giving them different names. The problem with this approach is that this string-based solution is not typesafe and can easily lead to ClassCastExceptions. The CDI specification introduced a typesafe way to achieve the same result with the @Qualifier meta-annotation. A small sample: An application needs to access two different databases with JPA. Thus we need two different EntityManagers. To distinguish between those, we just create two @Qualifier annotations @CustomerDb and @AdminDb (in analogue):
@Target( { TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualier public @interface CustomerDb {}

In many EE applications it makes sense to cache some information in the session. An example of such information would be user roles and privileges and the menu tree based on those rights. It's usually not necessary to perform this expensive calculation for each and every request. Rather, it can simply be stored in the session. One problem with this approach is that changing user settings during runtime e.g. when a user logs in temporarily as administrator or changes his view language is not easy. By using the CDI event system we can implement this in a very elegant way. Instead of manually cleaning up all depending information, we just send a UserSettingsChanged event and everyone who is interested can react accordingly. The event itself is typesafely represented by a class, which might also contain payload data:
public class UserSettingsChanged { public UserSettingsChanged(String userName) { this.userName = userName; } private String userName; // + getter und setter ... }

Those Qualifiers can now easily be used to inject the appropriate EntityManager:
public @ApplicationScoped class MyService { private @Inject @CustomerDb EntityManager customerEm; private @Inject @AdminDb EntityManager adminEm; ...

Let's now focus on the event source. For firing a UserSettingsChangedEvent, we first need to inject an event-source:
public class MyLoginBean { private @Inject Event<UserSettingsChanged> userChangedEvent; ... public boolean login(String username, String password) { .. do the login stuff userChangedEvent.re(new UserSettingsChanged(username)); ... } }

If no Qualifier is being used, the pre-defined @Default Qualifier will be assumed.

Producer Methods
In the previous example, we knowingly omitted how those EntityManagers will be created. One possibility would be to use Producer Methods (listing 3). We create @RequestScoped EntityManagers, since an EntityManager is per definition not serialisable thus we cannot store it in the session. We also need to implement a way to properly clean up the EntityManagers at the end of each request. This can be done with disposal methods, using the @Disposes annotation:
// class MyEntityManagerProducers continued public void disposeUdEm(@Disposes @UserData EntityManager em) { em.close(); } public void disposeBoEm(@Disposes @BackOfce EntityManager em) { em.close(); } }

Any class which needs to react on this event can now comfortably observe it via an observer method:

Listing 3
public class MyEntityManagerProducers { @Produces @RequestScoped @CustomerDb public EntityManager createCustomerDbEm() { return Persistence.createEntityManagerFactory(customerDb). createEntityManager(); } @Produces @RequestScoped @AdminDb public EntityManager createAdminEm() { return Persistence.createEntityManagerFactory("adminDb"). createEntityManager(); } ...

Events
The CDI specification defines a flexible but very easily usable eventing mechanism based on the Observer/Observable pattern.

www.JAXenter.com | March 2012

CDI Introduction

public @SessionScoped class MyBackingBean { Locale userLanguage; ... public void refreshLanguage(@Observes UserSettingsChanged usc) { userLanguage = getDefaultLanguageOfUser(usc.getUserName()); } ... }

@InterceptorBinding public @interface Transactional {}

The second part is the interceptor implementation itself. This class must be annotated as @Interceptor and additionally with its intended interceptor binding. The interceptor functionality itself is implemented in a method which gets annotated as @AroundInvoke (listing 4).

If the UserSettingsChange event gets fired, all observer methods of beans in currently active scopes will get invoked.

Final thoughts
After two years of availability, CDI is already seeing wide adoption. It has proven itself in a broad range of projects, from providing productivity in small start-ups to offering reliability and scalability websites with millions of users per day. The Expert Group is currently working actively on CDI 1.1, a specification which will bring small fixes and improvements, including much-requested standardization of Java SE bootstrap functionality for non-web applications.

Interceptors
CDI provides an easy way to create own custom interceptors, as we will show by creating our own @Transactional interceptor. Instead of having to manage the transactions manually, our small interceptor will do this for us as shown in the following usage example:
@ApplicationScoped public class MyUserService { private @Inject EntityManager em; @Transactional public storeUser(User u) { em.persist(u); } }

For implementing this feature, we need to provide two parts. The first one is obviously the annotation itself. It is metaannotated as @InterceptorBinding which marks it as an annotation that is intended to be used for interceptors:
@Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.TYPE, ElementType.METHOD })

Listing 4
@Interceptor @Transactional public class TransactionalInterceptor { private @Inject EntityManager em; @AroundInvoke public Object invoke(InvocationContext context) throws Exception{ EntityTransaction t =em.getTransaction(); try { if(!t.isActive()) t.begin(); return context.proceed(); } catch(Exception e) { .. rollback and stuff } nally { if(t != null && t.isActive()) t.commit(); } } }

Mark Struberg is a software architect with over 20 years of programming experience. He has been working with Java since 1996 and is actively involved in open source projects in the Java and Linux area. He is Apache Software Foundation member and serves as PMC and Committer for Apache OpenWebBeans, MyFaces, Maven, OpenJPA, BVal, DeltaSpike and other projects. He is also a CDI Expert Group member actively working on the specification. Mark works for the Research Group for Industrial Software (INSO) at the Vienna University of Technology.

Pete leads the Seam, Weld and CDI TCK projects, is an adviser to the RichFaces project, and is a founder of the Arquillian project. He has worked on a number of specifications including JSF 2.0, AtInject and CDI. He is a regular speaker at JUGs and conferences such as Devoxx (Javapolis), JAX, JavaBlend, JSFDays and JBoss World. Pete is currently employed by Red Hat Inc. working on JBoss open source projects. Before working for Red Hat, he used and contributed to Seam whilst working at a UK based staffing agency as IT Development Manager.

www.JAXenter.com | March 2012

2ND3RD VICTORIA PARK PLAZA

APRIL 2012 LONDON

CDI Introduction

p r e s e nt s

Developer.Class presents JAX Days. This unique two day training and workshop event is crammed with quality, in-depth training and hands-on Java development activities. Dont miss this amazing opportunity to update your knowledge and introduce yourself to relevant and exciting new topics.

COUNT 10% DIS OMO CODE


USING PR

JTJ READER RECEIVE

J D UG A 2

THE ULTIMATE HANDS-ON LEARNING EXPERIENCE

MONDAY 2nd April, 2012


JavaEE Essentials
with Adam Bien

TUESDAY 3rd April, 2012


Java EE Efficient, Productive and Scalable
with Adam Bien

Groovy from Zero to Hero


with Russel Winder

Pragmatic Architecture
with Ted Neward

The Busy Java Developers Guide to the JVM


with Ted Neward

An Introduction to NoSQL and the Neo4j Graph Database


with Ian Robinson & Jim Webber

Advanced Neo4j
with Ian Robinson & Jim Webber

www.JAXenter.com | March 2012

SIGN UP NOW TO RESERVE YOUR PLACE: WWW.JAXDAYS.COM 8

CDI Extensions

Implementing additional functionality in a portable, vendor-independent way

CDI Extension Programming


In the old days of Enterprise Java, a lot of frameworks were created, each with a very clear technological goal. Unfortunately these quickly became overloaded and stuffed with tons of features to fulfill each and every need. The CDI Expert Group aimed to avoid this problem with the CDI specification by strictly focusing on the core problems of dependency injection and defining a very powerful extension mechanism for implementing additional functionality on top of it. The CDI extension mechanism quickly became popular and a lot of high-quality extensions are already available.

by Ronald Steininger, Arne Limburg, and Mark Struberg


This mechanism is called portable CDI extensions because it is based on a well-specified SPI which must be supported by every certified standalone CDI container and EE 6 server. Thus a CDI extension written on one CDI container will also run on all others: JBoss Weld, Apache OpenWebBeans, Caucho Resin CanDI, IBM WebSphere 8, Oracle Glassfish 3, Oracle Weblogic 12c or Apache TomEE. Because of the portable, vendor-independent way these extensions are implemented, they can be reused with all CDI provider implementations. Projects like Apache MyFaces CODI and JBoss Seam 3 provide collections of important, commonly-needed extensions, letting CDI users easily augment their applications with the extensions they need without weighing down the core CDI implementation.

The first task a CDI container performs is to load all CDI extensions. Next, all of the classes contained within JAR files that have a META-INF/beans.xml marker file will be scanned also. For each of these classes an AnnotatedType will be constructed based on the given class. This object contains metadata about all annotations, constructors, methods, fields, etc. for the processed class. This information can be modified by extensions. Later the CDI container will expose this metadata in Bean<T> instances used to manage contextual objects. The container will start all available contexts after all classes have been scanned and all constraints have been verified.

Writing a CDI extension for a job scheduler


An example integration of a job scheduling service will highlight what is necessary to leverage the extension mechanism in a CDI environment. In this article, we want to go through the steps needed to build such scheduler integration by writing a CDI extension. Creating a CDI extension is as simple as writing a class that implements the interface javax.enterprise.inject.spi.Extension. This class will contain the functionality of our extension. We will see in later chapters how this class can interact with the CDI container.

How does a CDI extension work?


The CDI extension mechanism provides ways to hook custom code into the lifecycle of the CDI container. To leverage this power in our own CDI extensions we must therefore know the very basics of the CDI container lifecycle itself. We will first give you a quick overview of this process and dive into the details later in the article.

www.JAXenter.com | March 2012

CDI Extensions

The Container will pick up our extension via the Java ServiceLoader mechanism. Simply place a file named javax.enterprise.inject.spi.Extension (the same name as the interface) within the META-INF/services folder of your JAR and ensure this file contains the fully-qualified name of the Extension implementation. The container will look up the name of the class at runtime and instantiate it via the default constructor (therefore the class needs a default constructor). Before we delve into the content of the extension, we will first look into Quartz, the scheduler we want to integrate with, and how Quartz would be used without our extension.

@Target(ElementType.TYPE) public @interface Scheduled { String value(); //the jobs schedule }

It would be trivial to change this annotation to enable more advanced features like setting the schedule via dynamic configuration rather than hard-coding it in the jobs source; the annotation needs only to hold the information necessary to let our extension decide how to configure the job. Now its time to look at the extension itself.

The classic way to schedule jobs with Quartz


Quartz is an open-source job scheduling service. The user defines jobs and lets Quartz know when these jobs should be executed via so-called triggers. The scheduler itself will then run these jobs following the given rules. The easiest way to use Quartz in a servlet container is probably to use the QuartzInitializerServlet Quartz provides. This load-on-startup servlet initializes the scheduler automatically and adds a second servlet which actually schedules the jobs. Listing 1 shows a typical code block in that servlet which schedules a job named MyJob to run every ten minutes. Thats a lot of code just to schedule one job (and the code for that job is still missing) but will work just fine for simple use cases and a small number of jobs that dont change much. As soon as the jobs get a bit more complicated, there's a problem: the jobs will not be aware of the CDI container, which means that they cannot use the features provided by CDI. This will be no problem for very simple jobs but won't cut it as soon as the user wants to use a simple @Inject in one of the jobs or a service that uses CDI. Some sort of integration is needed to make all the features provided by CDI available to the job, and the best way to accomplish this is by writing an Extension.

Creating the CDI extension


A CDI extension class implements the javax.enterprise.inject. spi.Extension interface. This is just a marker interface and thus does not define any methods itself. Instead of using a fixed set of methods statically defined in an interface, the container will fire a series of CDI Events during the container lifecycle. The Extension can interact with the CDI container by defining observer methods for such events. An observer method is a non-static non-final method which has an @Observes parameter annotation with the type of the observed event. It

Listing 1
import static org.quartz.JobBuilder.*;2 import static org.quartz.TriggerBuilder.*; import static org.quartz.CronScheduleBuilder.*; ... SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory(); Scheduler scheduler = schedFact.getScheduler(); JobDetail job = newJob(MyJob.class) .withIdentity("myJob") .build(); Trigger trigger = newTrigger() .withIdentity("myTrigger") .withSchedule(cronSchedule("0 0/10 * * * ?")) .forJob("myJob") .build(); scheduler.scheduleJob(job, trigger);

Schedule jobs the CDI way


Lets see how the jobs used with our extension will look: 1. The job implements the java.lang.Runnable interface rather than the Job interface provided by Quartz. This way, the code is not Quartz-specific and the scheduler used by our extension can easily switched later. The scheduler will call the run() method of this Runnable based on the schedule we define. 2. Its possible to use CDI features like injection or interceptors in these jobs. 3. A @Scheduled annotation will tell our extension that this class defines a job that must be scheduled and what its schedule will be (Listing 2). Thats all that is needed to convey the same information as the code example before. For this example, @Scheduled is a simple annotation used to set the schedule:
@Inherited @Retention(RetentionPolicy.RUNTIME)

Listing 2
@Scheduled("0 0/10 * * * ?") public class MyJob implements Runnable { @Inject private MyService service; @Override public void run() { service.doSomething(); } }

www.JAXenter.com | March 2012

10

CDI Extensions

can not only gather information from the CDI container this way; it can also modify this information and even transmit back new information to the container. As a rule of thumb, all things possible via CDI annotations can also be performed programmatically in an extension. You can very easily add or modify scopes, Interceptors, Decorators, InjectionPoints, Producer methods, ObserverMethods, etc. The defined container lifecycle events are: BeforeBeanDiscovery ProcessAnnotatedType ProcessInjectionTarget and ProcessProducer ProcessBean and ProcessObserverMethod AfterBeanDiscovery AfterDeploymentValidation BeforeShutdown The first article of this series described how to observe custom CDI events. Extensions can observe the container system events in exactly the same way. To find every class that has the @Scheduled annotation, the extension should observe the ProcessAnnotatedType event. This system event is fired for every class scanned by the container during boot. A Quartz job and Quartz trigger can be created and started after the container initialization is complete for any such annotation found (Listing 3). An observer for the BeforeBeanDiscovery event which is fired before the scanning process starts can be used to initialize the scheduler.
public void initScheduler(@Observes BeforeBeanDiscovery event) { scheduler = StdSchedulerFactory.getDefaultScheduler(); }

public void startScheduler(@Observes AfterDeploymentValidation event, BeanManager bm) { beanManager = bm; try { scheduler.start(); LOG.info("Started scheduler."); } catch (SchedulerException se) { throw new RuntimeException(se); } }

Finally, the shutdown() method of the scheduler is called in an observer of the BeforeShutdown event.
public void shutdownScheduler(@Observes BeforeShutdown event) { try {

Listing 3
public void scheduleJob(@Observes ProcessAnnotatedType pat) { AnnotatedType t = pat.getAnnotatedType(); Scheduled schedule = t.getAnnotation(Scheduled.class); if (schedule == null) { //no scheduled job, ignoring this class return; } Class<Runnable> jobClass = t.getJavaClass().asSubclass(Runnable.class); if (jobClass == null) { LOG.error("Can't schedule job " + t); return; } JobDetail job = newJob(CdiJob.class) .usingJobData(CdiJob.JOB_CLASS_NAME, jobClass.getName()) .build(); Trigger trigger = newTrigger() .withSchedule(cronSchedule(schedule.value())) .build(); scheduler.scheduleJob(job, trigger); }

The scheduler also has to be started. This can be done in an AfterDeploymentValidation event observer. That event is fired after the container has validated that there are no deployment problems, so all jobs will be scheduled at this point. Additionally, the BeanManager can be stored in the Extension for later use (e.g. in the CdiJob class).

Listing 4
public class CdiJob implements org.quartz.Job { public nal static String JOB_CLASS_NAME = CDI_JOB_CLASS_NAME; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobData = context.getJobDetail().getJobDataMap(); String className = jobData.getString(JOB_CLASS_NAME); Class<Runnable> jobClass; try { jobClass = Class.forName(className).asSubclass(Runnable.class); } catch (ClassNotFoundException e) {

throw new JobExecutionException(e); } BeanManager bm = QuartzExtension.getBeanManager(); Set<Bean<?>> jobBeans = bm.getBeans(jobClass); Bean<?> jobBean = bm.resolve(jobBeans); CreationalContext c = bm.createCreationalContext(jobBean); Runnable job = (Runnable) bm.getReference(jobBean, Runnable.class, c); try { job.run(); } nally { jobBean.destroy(job, c); } } }

www.JAXenter.com | March 2012

11

CDI Extensions

scheduler.shutdown(true); } catch (SchedulerException se) { throw new RuntimeException(se); } }

Summary
One of the most important features of CDI is the possibility to create extensions. With this mechanism, CDI can be extended in a portable, vendor-independent way to provide new features (like custom scopes), implement application-specific functionality (like loading configuration from an external database) or to integrate other technologies in a CDI-like fashion.
Ronald Steininger is a Senior Software Engineer for the Research Group for Industrial Software (INSO) at the Vienna University of Technology. He spent the last six years working with Java on both rich clients and web applications. He and his colleagues use CDI and Java EE 6 for all of their projects since late 2009. He spends his spare time working on his master thesis about the software architecture of campus management systems. Arne Limburg is Enterprise Architect at open knowledge GmbH in Oldenburg, Germany. He is an experienced developer, architect and trainer in the Enterprise environment and also regularly involved in Android development. He frequently speaks at conferences and conducts workshops in those fields. He is also an active participant in open source projects, e.g. as a committer of Apache OpenWebBeans and as initiator and Project Lead of JPA Security. Mark Struberg is a software architect with over 20 years of programming experience. He has been working with Java since 1996 and is actively involved in open source projects in the Java and Linux area. He is Apache Software Foundation member and serves as PMC and Committer for Apache OpenWebBeans, MyFaces, Maven, OpenJPA, BVal, DeltaSpike and other projects. He is also a CDI Expert Group member actively working on the specification. Mark works for the Research Group for Industrial Software (INSO) at the Vienna University of Technology.

The following class does the work needed, so that a CDImanaged instance of the Runnable (our actual job) we defined is run as a Quartz job. 1. It extracts the job class from the Quartz configuration. 2. Before calling the run() method, it receives the actual CDI-managed instance from the BeanManager. 3. After the run() method returns, the instance is destroyed (Listing 4). Our extension sets up all scheduled jobs to use this class, so that all of this happens in a manner completely transparent to the user. Keep in mind that contexts like the RequestContext and SessionContext are not active for this job (there is no active request nor session). If the injected services need these contexts because they depend on beans like a RequestScoped EntityManager, the contexts can be started and stopped in @PostConstruct and @PreDestroy methods of the job. This is container-specific at the moment, but work is underway within the Apache DeltaSpike project to make this possible in a vendor-independent way.

Imprint
Publisher Software & Support Media GmbH Editorial Office Address Darmstdter Landstrae 108 60598 Frankfurt am Main Germany www.jaxenter.com Editor in Chief: Sales: Cindy Ng +44 (0)20 7401 4837 cindyn@sandsmedia.com Entire contents copyright 2012 Software & Support Media GmbH. All rights reserved. No part of this publication may be reproduced, redistributed, posted online, or reused by any means in any form, including print, electronic, photocopy, internal network, Web or any other method, without prior written permission of Software & Support Media GmbH The views expressed are solely those of the authors and do not reflect the views or position of their firm, any of their clients, or Publisher. Regarding the information, Publisher disclaims all warranties as to the accuracy, completeness, or adequacy of any information, and is not responsible for any errors, omissions, in adequacies, misuse, or the consequences of using any information provided by Pub lisher. Rights of disposal of rewarded articles belong to Publisher. All mentioned trademarks and service marks are copyrighted by their respective owners.

Editors: Authors: Copy Editor: Creative Director: Layout:

Sebastian Meyen Claudia Frhling, Diana Kupfer Dan Allen, Aslak Knutsen, Arne Limburg, Pete Muir, Gerhard Petraczek, Jason Porter, Andrew L. Rubinger, Ronald Steininger, Mark Struberg Nicole Bechtel, Lisa Pychlau Jens Mainz Tobias Dorn

www.JAXenter.com | March 2012

12

JAX Innovation Awards 2012


Celebrating the Best Innovations
in the Java Ecosystem
Submissions for the JAX Innovation Awards 2012 open on March 16th. Nominate the people, companies and technologies you think are innovating the most.

Announcing the

MostInnovativeJavaTechnology MostInnovativeJavaCompany TopJavaAmbassador


The JAX Innovation Awards will be presented to winners at a special ceremony on July 9 in San Francisco, CA.

www.jaxconf.com

Apache DeltaSpike

Creating a stable, reliable and truly portable CDI extension

Apache DeltaSpike Closes the Gaps


This article traces the development of Apache DeltaSpike from the roots to its present status. This rapidly-growing project is surrounded by a very active team of developers whose goal is to create a thoroughly tested and stable version 1.0 that is compatible with all major server platforms which support CDI.

by Gerhard Petracek and Jason Porter


In 2004 the world of J2EE started to change with the rise of an alternative framework. Version 1.0 of the Spring framework was released and it became easier to implement enterprise level applications. Spring gained a lot of popularity over time and it also influenced Java EE. With the next version, Java EE focused on Ease of Development as well technical concerns of the growing technical complexities required in applications. Even though Java EE became much simpler, there were still some loose ends. Therefore version 1.0 of JBoss Seam was released in 2006. It provided a toolbox to fix some of the shortcomings. At the same time, the Spring framework provided its own approach for integrating several parts of Java EE in a different manner. About one year later, JBoss Seam version 2.0 was released and the MyFaces community released version 1.0 of a new Spring extension named Apache MyFaces Orchestra. MyFaces Orchestra introduced scopes which differed a lot from what was available so far, but the basic purpose was similar to JBoss Seam. JSF users who preferred the Spring framework got a powerful tool with MyFaces Orchestra, and JSF users who were in favor of Java EE 5 could use the Seam framework as a convenient toolbox. Later on, several dependency injection frameworks inspired a new Java EE specification with the name Contexts and Dependency Injection for Java EE (aka CDI) which was released in 2009 as a part of Java EE 6. In parallel also the Spring framework moved in a very similar direction. Both camps solve the same problems, but there are still significant differences.

of an application server to avoid vendor lock-in. Java EE 6 is the first Java EE specification which doesnt need an additional framework for painless usage or for replacing manual integrations of different parts of the platform. At least thats a common message of some community members. Java EE 6 is closer to this statement than the former versions. However, it turns out the real world isnt that shiny. A lot of new innovations still happen in the Open Source space first and some features might even be too special to be included into a specification. Therefore it was intended to provide a rich set of extension points from the very beginning. That allows to keep specifications in general and CDI in particular consistent and simple without restricting custom approaches and mechanisms. As mentioned earlier, CDI is provided out-of-the-box by Java EE 6+ servers and therefore a very important aspect of CDI extensions is portability which allows them to be used seamlessly in combination with all implementations of the CDI specification. Apache OpenWebBeans and JBoss Weld are such CDI implementations and they allow to use CDI even with plain Java SE. Therefore, neither CDI nor portable CDI extensions are restricted to Java EE. That allows to create different types of CDI extensions. Apache DeltaSpike is such a collection of portable CDI extensions. To understand the roots of DeltaSpike its important to look at two famous portable CDI extensions - JBoss Seam3 and Apache MyFaces ExtCDI (aka MyFaces CODI).

JBoss Seam3
Seam 3 started shortly after JSR 299 completed. The goal of Seam 3 was not to be a complete migration of all things from Seam 2, but it provides a rich toolbox for building standardsbased web applications tailored for traditional and cloud deployments. Certainly some ideas came from Seam 2, but many more came from the community. Unlike the starting

The rise of CDI extensions


In contrast to the Spring framework, CDI is available outof-the-box in Java EE 6+ application servers and therefore its very important to have sufficient standardized hooks for additional frameworks to use them independent of the details

www.JAXenter.com | March 2012

14

Apache DeltaSpike

of Seam 1 and 2, Seam 3 did not simply want to improve JSF support, but to unite many technologies with CDI. Many of the modules developed in Seam 3 demonstrate this such as Mail, JMS, JCR, Reports and Spring-Integration. All of these modules came from the community as a hole was discovered while using the technologies and seeking a more unified and simpler approach for developers. Other areas in developer productivity were explored in Seam 3 such as type safe logging in Solder, exception handling also in Solder though formerly Seam Catch, XML configuration via Seam Config, now in Solder.

Apache MyFaces CODI


Similar to JBoss Seam, MyFaces Orchestra provided better scopes for JSF applications as well as an optional integration with the Java Persistence API (JPA) to allow the usage of an extended persistence context. Originally MyFaces CODI was started to port some concepts provided by MyFaces Orchestra to a portable CDI extension. However, since CDI endorses type-safe dependency injection, MyFaces CODI was designed from scratch and only some of the basic and successful concepts of MyFaces Orchestra were used as basis for some features of MyFaces CODI. The most important qualities of MyFaces CODI, which attracted several users even before the release of version 1.0, are the reality check of existing concepts in combination with innovative new mechanisms, the support for almost all major Java EE 5/6 application servers, an easy but powerful API and SPI as well as a fast and solid implementation, and last but not least, a great community. MyFaces CODI doesnt enforce a specific programming model. Instead it relies on CDI concepts as much as possible and users just use what they need in addition. They can even replace parts of MyFaces CODI with custom implementations which get picked up by the rest of the framework or deactivate parts completely to improve the performance even further. Like CDI itself, MyFaces CODI relies on type-safety as much as possible. This allows use of standard Java support in existing Java IDEs without the need for special IDE Addons. In addition, it avoids mistakes like typos and therefore allows an easier refactoring and maintenance process.

part of the community decided to start a shared CDI extensions project developed and maintained by the community. The Apache Software Foundation was chosen due to its reputation concerning community-driven and vendor-independent projects. Amongst many others, the project management committee of Apache MyFaces was excited about this idea, and the lead developers of MyFaces CODI helped to draft a proposal for such a new Apache project. The hardest part was the name for the project. After some discussions the upcoming community agreed on the intermediate name DeltaSpike. With this name, the community entered the Apache Incubator, which is the entry point for all new Apache projects. Before the project leaves the incubator and graduates to an Apache top level project, the community will vote a final project-name. The initial committers of the DeltaSpike community are representatives of several existing CDI communities which joined the effort from the very beginning. Aside from some other important tasks, the community merges features of the participating extension projects, adds new features and grows a community before DeltaSpike becomes a top level project and leaves the Apache Incubator. Before a feature gets added to DeltaSpike it is discussed by the community.

Progressing fast
Two months after the first e-mail on the mailing list [1], DeltaSpike v0.1 incubating was announced. With this first step, the community started to merge features of Apache MyFaces CODI-Core and JBoss Solder which is a central part of Seam3. Every DeltaSpike release is well tested on multiple containers and many real world projects. Nonetheless it's expected that even APIs will change until version 1.0 based on the feedback of the community and new features and bug fixes will be added quickly. In the next release, the community will add further DeltaSpike-Core features as well as new modules. Besides reviewing, discussing and adding features to DeltaSpike, the community is also working on a great documentation, examples, as well as a test-suite which should ensure true and tested portability across different environments.

The future Apache DeltaSpike


Since CDI encourages the usage of portable CDI extensions, users have to look at several accredited portable CDI extensions like JBoss Seam3 and Apache MyFaces CODI as well as several smaller projects and blog entries about implementing such extensions with varying quality. Several communities of CDI extensions came up with similar ideas and features. Most of the time it is possible to mix multiple portable CDI extensions without problems. However, usually there is no outof-the-box optimization across different extension-projects, and to combine them sometimes requires a detailed know ledge about the projects. For example, it is not difficult to use Seam3 in combination with MyFaces CODI, but both have different security concepts which are not aware of each other out-of-the-box. Instead of implementing and documenting the corresponding adapters for the major extensions, a large

Join the community


There are already several very active community members who enjoy the great cooperation. At Apache the most important part of a project is its community. Especially users who are not familiar with Open-Source communities in general or Apache projects in particular sometimes do not know how to get involved. Therefore the DeltaSpike community is working on a short overview of different types of involvement and the corresponding steps. Everybody is very welcome to get in touch with the community and every question which is not covered by the Wiki [2] is very welcome to improve the Wiki and therefore the experience for new users. Its important to understand that everybody is welcome to join the discussions or to provide feedback to improve DeltaSpike step by step. It makes sense to join the effort as soon as possible because the community moves fast and has agreed on releasing early and often.

www.JAXenter.com | March 2012

15

Apache DeltaSpike

The new era DeltaSpike v1.0 and beyond


After merging the best features and introducing new concepts, you can expect that the result is better than the original parts. An example which is available since v0.1-incubating is @Exclude. In case of @Exclude the community merged @Veto from Solder with @ExpressionActivated and @ProjectStageActivated of MyFaces CODI. Originally, the discussion was about more expressive names for all of those annotations, and the result was a single annotation called @Exclude with the features of the original annotations. This means the final version is more expressive and easier for users without losing functionality. The listings 1-3 show independent beans with the new annotation. The result might sound obvious, but it took some time and a lot of e-mails to find the right name which allowed to merge the functionality and preserve the expressiveness. As mentioned earlier, DeltaSpike will release early and often. So 0.1-incubating doesn't contain that many features for application developers, but DeltaSpike grows rapidly and besides DeltaSpike-Core the community is currently working on two new modules which will be part of the next release. Right now all modules can be used even in Java SE applications. After finishing the most important modules like Security, I18n, Exception handling which can be used in Java SE applications as well, the community plans to start with

several integration modules for Java EE technologies like JSF, JPA, REST, JMS as well as other frameworks like Spring and Quartz. The goal regarding JBoss Seam3 and Apache MyFaces CODI is to add as much as the majority can agree on. Since the community is optimistic to add and/or merge most features in/into DeltaSpike, it is expected to be easy for users of the original extension projects to migrate to DeltaSpike. Instead of using workarounds for the migration, users are invited to join the effort early and share use cases which might not be supported at the time they try to switch to the corresponding module of DeltaSpike. In the end they should see an even better approach they can use. Version 1.0 should be fast, thoroughly tested, very stable and compatible with all major server platforms which support CDI. The DeltaSpike team is already very active, and all of us are confident that it will grow as fast as DeltaSpike itself to reach the goal of a stable, reliable and truly portable CDI extension and even more important: a great community.

Listing 1: Service implementation for project-stage UnitTest


@Alternative @Exclude(exceptIfProjectStage = ProjectStage.UnitTest.class) public class TestServiceMockImpl implements Service { //... }

Listing 2: Service implementation for a database different from type 'prodDB'


@Alternative @Exclude(onExpression = "db_type==prodDB") public class DevServiceMockImpl implements Service { //... }

Gerhard Petracek is Apache MyFaces committer and PMC chair; Apache OpenWebBeans committer and PMC member; Apache DeltaSpike committer, PPMC member and mentor; Apache member; Bean-Validation expert group member and a founder of Apache MyFaces Extensions Validator, Apache MyFaces CODI and Apache DeltaSpike. At IRIAN Solutions Gerhard is responsible for Java-EE trainings and the development of modern web-applications for customers such as Credit-Suisse. Furthermore, he holds lectures at an Austrian University of Applied Sciences and is the author of several articles on JSF and Java-EE. Jason Porter is a software engineer currently working in the Java Enterprise Edition Space and Seam at Red Hat. His specialties include JBoss AS, Seam, CDI, JSF, Java EE, Gradle. He has worked with PHP, Ruby (both stand-alone and Rails), Groovy, XSLT the rest of the web language arena (HTML, CSS, JS, etc). His current position as Senior Software Engineer at Red Hat has him work primarily on Seam, however, he also contributes to JBoss Forge, Arquillian and Apache DeltaSpike.

Listing 3: Utility class which shouldn't be a CDI bean


@Exclude public class CustomUtilClass { //... }

References & Additional Resources


[1] http://mail-archives.apache.org/mod_mbox/incubator-deltaspike-dev/ [2] https://cwiki.apache.org/confluence/display/DeltaSpike

www.JAXenter.com | March 2012

16

JOIN US FOR 4 DAYS CRAMMED FULL OF THE BEST JAVA CONTENT, SPEAKERS, DISCUSSIONS AND NETWORKING
July 9 12, San Francisco, CA

www.jaxconf.com
Java Core Android Java EE Spring Languages Cloud Agile HTML5 Web Architecture Continous Delivery JavaScript Open Source Tools & Framework Java Performance

Big Data & NoSQL

Technical presentations and tutorials In-depth coverage of the latest technologies Practical implementation techniques Neutral coverage of the most important Java Ecosystem topics

Register Now for Very Early Bird Tickets!


follow us:
twitter.com/JAXconf JAXConf

Arquillian

Testable development of CDI

Arquillian Makes Testing a Breeze


Its our opinion that testing is development; were not doing our job as programmers if we cannot ensure that our code is working as advertised. To that end, CDI has been a tremendous step forward for Java EE as a simplified POJO-based component model. Of course, CDI beans become such only within the context of a CDI Container, and that infers both starting a server and deploying into it. Until now, that work has been the responsibility of the developer; with the introduction of the Arquillian testing framework, these concerns can safely be put aside.
by Dan Allen, Aslak Knutsen, and Andrew L. Rubinger
Arquillian is a platform that simplifies integration testing for Java middleware. It deals with all the plumbing of container management, deployment and framework initialization so you can focus on the task at hand, writing your tests. Real tests. Arquillian minimizes the burden on you the developer by covering aspects surrounding test execution, including: Managing the lifecycle of the container (start/stop), Bundling the test class with dependent classes and resources into a deployable archive, Enhancing the test class (e.g., resolving @Inject, @EJB and @Resource injections), Deploying the archive to test (deploy/undeploy) and Capturing results and failures. To avoid introducing unnecessary complexity into the developers build environment, Arquillian integrates seamlessly with familiar testing frameworks (e.g., JUnit 4, TestNG 5), allowing tests to be launched using existing IDE, Ant and Maven test plug-ins without any add-ons. This guide introduces you to Arquillian. After reading this guide, you will be able to: Add the Arquillian infrastructure to a Maven-based Java project Write an Arquillian test case to assert the behaviour of a CDI bean Execute the Arquillian test case in multiple compatible containers Youll learn all of these skills by incorporating Arquillian into the test suite of a Java EE application with a Maven build. Weve designed this guide to be a fast read to get you started quickly! this category is Apache Maven. This guide will navigate you to your first green bar using a sample Maven project. Arquillian does not depend on Maven, or any specific build tool for that matter. It works just as well if not better when used in a project with an Ant or Gradle build. Ideally, the build tool should offer dependency management as it simplifies the task of including the Arquillian libraries since they are distributed in the Maven Central repository This guide assumes you have Maven available, either in your command shell or your IDE. If you dont, please install Maven now [1]. You will also need JDK 1.6 [2] or better installed on your machine.

Create a new project


There are two ways we recommend you create a new Maven project: 1. Generate a project from a Maven archetype [3] 2. Create and customize a project using JBoss Forge [4] If you already have a Maven project, you can use this section as review to ensure you have the proper dependencies before moving on. By far, JBoss Forge is the simpler approach, but this guide will offer both options in the event you arent ready to adopt JBoss Forge. Select from one of the two options above to jump to the instructions.

Generate a project from a Maven archetype


First, create a Maven-based Java project using the command below. Copy the text after the $ and paste it into your command shell.
$ mvn archetype:generate -DarchetypeGroupId=net.avh4.mvn.archetype \ -DarchetypeArtifactId=java-1.6-archetype

Assumptions
The easiest way to get started with Arquillian is to incorporate it into the test suite of a project build that offers dependency management. Today, the most widely-used build tool in

Respond to the prompts by entering the value shown after each double colon below. Hit the Enter key after each line (as indicated by <ENTER>).

www.JAXenter.com | March 2012

18

Arquillian

Define value for property groupId: : org.arquillian.example <ENTER> Define value for property artifactId: : arquillian-tutorial <ENTER> Define value for property version: : <ENTER> Define value for property package: : <ENTER> Confirm properties configuration: groupId: org.arquillian.example artifactId: arquillian-tutorial version: 1.0-SNAPSHOT package: org.arquillian.example Y: : <ENTER> This command generated a Maven-based Java project inside a new folder named arquillian-tutorial under the current directory. The file structure of the project is shown below:

src/ main/ java/ Place all application Java source files here (under Java package) resources/ Place all application configuration files here test/ java/ Place all test Java source files heres (under Java package) resources/ Place all test configuration files here (e.g., arquillian.xml) pom.xml The Maven build file. Tells Maven how your project should be built. The project is preconfigured to use Java 6 and JUnit 4.8, the minimum required versions of Java and JUnit for using Arquillian, respectively. The generator also created a Java package named org. arquillian.example underneath the two java folders. You should put your Java source files in this package rather than at the root of the java folder. Arquillian also supports TestNG 5. However, we will be using JUnit throughout this guide. Go ahead and open up the pom.xml in your editor. You should see an XML file containing basic project information, a build section and a dependencies section. You can remove all the elements below the JUnit dependency as they arent required. After making the change, you should end up with the contents seen in listing 1 (trimmed for brevity). Were going to be writing Java EE 6 components. Therefore, we also need to add the Java EE 6 API to the classpath so we can compile these components. Open up the pom.xml file once again and add the following XML fragment directly inside the <dependencies> element. Listing 2 shows how the section should look once youre done. We strongly recommend that you do not use the Java EE API artifact with coordinatesjavax:javaee-api. That bundle contains classes with stripped method bodies, which will cause your application to throw strange Absent Code errors if left on the classpath at runtime (even when running tests). Read the FAQ under [5] if you want more background. The foundation of your project is now ready! Skip to the next section to open the project in Eclipse [6] so we can start writing some code!

Listing 1
pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.arquillian.example</groupId> <artifactId>arquillian-tutorial</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>arquillian-tutorial</name> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <conguration> <source>1.6</source> <target>1.6</target> </conguration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>

Create a project using Forge


JBoss Forge [7] is a command shell for rapid-application development in a standards-based environment. Another way to think of it is that its like Maven Archetypes on steroids. Installing Forge is a relatively short process, and this guide will take you through the fundamentals. Follow these simple steps to get it installed: 1.  Download Forge and unzip it into a folder on your harddrive, which well call $FORGE_HOME 2.  Well assume you extracted the distribution to a folder named forge in your home directory 3.  Add $FORGE_HOME/bin to your path (Windows, Linux or Mac OSX)

www.JAXenter.com | March 2012

19

Arquillian

Fig. 1: Starting Forge

On Unix-based operating systems, adding Forge to your path typically means editing your $HOME/.bashrc or $HOME/.profile; you will need to set the following environment variables:

$ export FORGE_HOME=$HOME/forge/ $ export PATH=$PATH:$FORGE_HOME/bin On Windows, you will need to right-click on Control Panel, then click System Properties, open the Advanced tab, then click Environment Variables and add these two entries visually. We recommended setting User variables for Forge, unless you have placed the unzipped distribution in a folder where all users can access it. Now that Forge is installed (i.e., extracted), open a command prompt (a shell) and run the forge command (figure 1):
$ forge [no project] ~ $

src/ main/  java/ Place all application Java source files here (under Java package)  resources/ Place all application configuration files here META-INF/ forge.xml An empty Forge settings file test/  java/ Place all test Java source files heres (under Java package)  resources/ Place all test configuration files here (e.g., arquillian.xml) pom.xml The Maven build file. Tells Maven how your project should be built. Forge also makes the project folder your current directory within the Forge shell.
[arquillian-tutorial] arquillian-tutorial $

Thats it! Youve got Forge up and running. Now its time to create the project. Inside the Forge shell, execute the following command to create a blank project, much like we created a project using the Maven Archetype above:
$ new-project --named arquillian-tutorial --topLevelPackage org.arquillian.example

By default, Forge sets up the project to use Java 1.6, the minimum required version of Java to use Arquillian, a nice convenience. What we need to add now is the Java EE APIs. Thats done using the project add-dependency command below:
$ project add-dependency org.jboss.spec:jboss-javaee-6.0:1.0.0.Final:pom:provided

You will also need to add JUnit 4.8, the minimum required version of JUnit to use Arquillian, as a test-scoped dependency:
$ project add-dependency junit:junit:4.8.1:test

This command generates a Maven-based Java project inside a new folder named arquillian-tutorial under the current directory. The file structure of the project Forge generates is shown below:

Listing 2
pom.xml <!-- clip --> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>1.0.0.Final</version> <type>pom</type> <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency> </dependencies> <!-- clip -->

The result of the pom.xml that Forge generates is shown in Listing 3. Arquillian is now distributed in the Maven Central repository, so the JBoss Public repository declaration in the pom.xml is unnecessary and can be removed. Keep in mind, though, you may need it to retrieve other JBoss software not available in Maven Central. If you follow the camp that consider repositories explicitly defined in your projects pom.xml to be an antipattern, then read the instructions under [8] to enable the repository globally in your settings.xml file. The foundation of your project is now ready! Lets now open the project in Eclipse so we can start writing some code!

Open the project in Eclipse


When developing a Java project, youll likely use an IDE, such as Eclipse. Thats why Arquillian has been designed to be IDE friendly, meaning you can run Arquillian tests from the IDE without making unconventional changes. So lets start taking advantage of the IDE immediately. Begin by launching Eclipse. Now, since this is a Maven project, you need the Maven Integration for Eclipse(m2e) plug-in [9] installed to open the project. If you dont already have the integration installed, the simplest way to get it is to install JBoss Tools [10]. Follow these steps to install it from the Eclipse Marketplace (sort of like the app store for Eclipse).

www.JAXenter.com | March 2012

20

Arquillian

1. Select Help | Eclipse Marketplace... from the main menu 2.  Type jboss tools in the Find input field (no quotes) and press Enter 3.  Click the Install button next to JBoss Tools (Indigo) 4.  Complete the install wizard, then restart Eclipse if prompted JBoss Tools provides a nice environment for developing Java EE applications, including excellent CDI support. Dont worry, its not a heavyweight plugin.

However, if you just want the Maven integration without the extras that JBoss Tools brings, you can follow these steps instead: 1. Select Help | Eclipse Marketplace... from the main menu 2.   Type maven in the Find Fig. 2: Eclipse will recognize and open the Maven project in the input field (no quotes) and Project Navigator view. press Enter 3. Click the Install button next to Maven Integration for Eclipse 4.   Complete the install wizard, then restart Eclipse if prompted 5.   Repeat the steps to install the Maven Integration for Eclipse WTP Once you have the Maven Integration plugin installed, follow these steps to open the project: 1. Select File | Import... from the main menu 2.  Type existing maven in the input source field 3. Select the option Existing Maven Projects, then click the Next button 4.  Click the Browse button 5.   Navigate the project folder on your filesystem, then click the OK button 6.  Click the Finish button to open the project Eclipse will recognize the Maven project and open it in the Project Navigator view. If you expand the project, it should look similar to figure 2. Now we can really get down to business!

Listing 3
pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>org.arquillian.example</groupId> <artifactId>arquillian-tutorial</artifactId> <version>1.0.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>1.0.0.Final</version> <type>provided</type> <scope>pom</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency> </dependencies> <repositories> <repository> <id>JBOSS_NEXUS</id> <url>http://repository.jboss.org/nexus/content/groups/public</url> </repository> </repositories> <build> <nalName>arquillian-tutorial</nalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <conguration> <source>1.6</source> <target>1.6</target> </conguration> </plugin> </plugins> </build> </project>

Create a component
In order to write an Arquillian test, we need to have a component for it to test. Lets begin by creating a basic component so that you can learn how to execute an Arquillian test without other distractions. Well gradually move to more complex scenarios. In your IDE, create a new Java class named Greeter in the org.arquillian.example package. Replace the contents of the file with this greeter logic (Listing 4). We want to verify that this class behaves properly when invoked as a CDI bean. Of course, we could simply write a unit test. But lets pretend that the bean uses enterprise services such as dependency injection and messaging and must be used inside a container. (Besides, that way we give it room to grow). To use the class as a CDI bean, well be injecting it into the test using the @Inject annotation. That calls for an Arquillian test, which means its time to add the Arquillian API to the project!

Add the Arquillian APIs


Once again open up the pom.xml file, located in the root folder of the project, in your editor. We need to instruct Maven which versions of the artifacts to use. Insert the following

www.JAXenter.com | March 2012

21

Arquillian

XML fragment directly above the <build> element to import the BOM, or version matrix, for Arquillians transitive dependencies.
pom.xml <!-- clip --> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-bom</artifactId> <version>1.0.0.CR7</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <!-- clip -->

can download the file from the gist [11]. Youre all set to write your first Arquillian test!

Write an Arquillian test


An Arquillian test looks just like a unit test, just with some extra flair. Lets return to the IDE. If you get the message Project configuration is out of date with pom.xml, then right click and select Project | Maven | Update Project Configuration to resync the project. Begin by creating a new JUnit test case in src/test/java under the org.arquillian.example package and name it GreeterTest. You wont need the typical setup and teardown methods since Arquillian is doing most of the heavy lifting. Heres what we have so far:
src/test/java/org/arquillian/example/GreeterTest.java package org.arquillian.example; import org.junit.Assert; import org.junit.Test; public class GreeterTest { @Test public void should_create_greeting() { Assert.fail("Not yet implemented"); } }

Next, append the following XML fragment directly under the last <dependency> element to add the Arquillian JUnit integration:
pom.xml <!-- clip --> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> <!-- clip -->

Now, about that flair. An Arquillian test case must have three things: 1. A @RunWith(Arquillian.class) annotation on the class 2.   A static method annotated with @Deployment that returns a ShrinkWrap archive 3.  At least one method annotated with @Test The @RunWith annotation tells JUnit to use Arquillian as the test controller. Arquillian then looks for a static method annotated with the @Deployment annotation to retrieve the test archive (i.e., micro-deployment). Then some magic happens and each @Test method is run inside the container environment.

The Arquillian JUnit integration artifact also adds the Arquillian and ShrinkWrap APIs to the test classpath. You need all of these libraries to write and compile a JUnit Arquillian test. To use TestNG instead of JUnit, substitute the Arquillian JUnit integration with the Arquillian TestNG integration. If youre having trouble with the pom.xml up to this point, you

Listing 4
src/main/java/org/arquillian/example/Greeter.java package org.arquillian.example; import java.io.PrintStream; /** * A component for creating personal greetings. */ public class Greeter { public void greet(PrintStream to, String name) { to.println(createGreeting(name)); } public String createGreeting(String name) { return "Hello, " + name + "!"; } }

Whats a test archive?


The purpose of the test archive is to isolate the classes and resources which are needed by the test from the remainder of the classpath. Unlike a normal unit test, Arquillian does not simply dip into the entire classpath. Instead, you include only what the test needs (which may be the entire classpath, if thats what you decide). The archive is defined using ShrinkWrap [12], which is a Java API for creating archives (e.g., jar, war, ear) in Java. The micro-deployment strategy lets you focus on precisely the classes you want to test and, as a result, the test remains very lean. ShrinkWrap also supports resolving artifacts (libraries) and create configuration files programmatically, which can then be added to the test archive. For a more thorough introduction to ShrinkWrap, see the ShrinkWrap introduction guide [13]. Lets add that Arquillian flair to the test (listing 5).

www.JAXenter.com | March 2012

22

Arquillian

Using ShrinkWrap, weve defined a Java archive (jar) as the deployment that includes the Greeter class that the test will invoke and an empty beans.xml in the META-INF directory to activate CDI in this archive. Now all we need to do is inject the Greeter instance into a field directly above the test method and replace the unimplemented test method with one that asserts the behavior of the bean. To give you that warm fuzzy feeling, well also print the greeting to the console.
src/test/java/org/arquillian/example/GreeterTest.java // clip @Inject Greeter greeter; @Test public void should_create_greeting() { Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling")); greeter.greet(System.out, "Earthling"); }

Add a container adapter


Weve been talking a lot about testing in a container, but so far we have not mentioned which one. Thats because its a runtime decision. Arquillian selects the target container based on which container adapter is available on the test classpath. That means well be adding more libraries to the project. An Arquillian test can be executed in any container that is compatible with the programming model used in the test (as long as the container has an Arquillian adapter). Our test is using the CDI programming model, so we need to use any container to supports CDI. We want fast turnaround during development, so well start with the Weld EE embedded container. Open the pom.xml file again and add the following group of dependencies directly below the other<dependency> elements (listing 7). To summarize, here are the three libraries you need to use Arquillian (with JUnit): 1.  Arquillian JUnit integration 2.  Arquillian container adapter for the target container 3.   Container runtime (embedded container) or container client (remote container)

Listing 6 shows how the test should look when youre done. Youve written your first Arquillian test! Ah, but youre probably wondering how to run it. If youre thinking, Just like a unit test youre correct! However, we first need to add a container adapter to the classpath.

Listing 6
src/test/java/org/arquillian/example/GreeterTest.java package org.arquillian.example; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.junit.Test; import org.junit.Assert; import org.junit.runner.RunWith; @RunWith(Arquillian.class) public class GreeterTest { @Deployment public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Greeter.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } @Inject Greeter greeter; @Test public void should_create_greeting() { Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling")); greeter.greet(System.out, "Earthling"); } }

Listing 5
src/test/java/org/arquillian/example/GreeterTest.java package org.arquillian.example; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(Arquillian.class) public class GreeterTest { @Deployment public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Greeter.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } @Test public void should_create_greeting() { Assert.fail("Not yet implemented"); } }

www.JAXenter.com | March 2012

23

Arquillian

When you run the test, you should see the following lines printed to the console:
26 [main] INFO org.jboss.weld.Version WELD-000900 1.1.1 (Final) Hello, Earthling! You should then see the JUnit view appear, revealing a green bar (g. 4)!

You can also run the test on the commandline using Maven:
$ mvn test

You should see the following lines printed to the console:


Fig. 3: Starting the test

------------------------------------------------------TESTS ------------------------------------------------------Running org.arquillian.example.GreeterTest 21 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.1 (Final) Hello, Earthling! Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.858 sec Congratulations! Youve earned your rst green bar with Arquillian!
Fig. 4: JUnit view revealing a green bar

A closer look
How do you know that CDI really worked? For all you know, Arquillian created a new instance of theGreeter class and injected it into the test without any involvement from CDI. Lets prove its there. Create a new CDI bean named PhraseBuilder in the org.arquillian.example package that can create phrases from templates. Next, open up the Greeter class and create a new constructor that will inject PhraseBuilder using constructor injection. Then, delegate the task of creating the greeting to the injected bean (listing 9) Now, in order for the test to work, an instance of PhraseBuilder must be created, its @PostConstructmethod invoked

Were using an embedded container in this example, so we need the container runtime, Weld. Now back to the test.

Run the Arquillian test


Once you add all the necessary Arquillian libraries to the classpath, you can run an Arquillian test just like a unit test, whether you are running it from the IDE, the build script or any other test plugin. Lets run the test in Eclipse. From the IDE window, right click on the GreeterTest.java file in the Package Explorer (or in the editor) and select Run As | JUnit Test from the context menu (see fig. 3)

Listing 7
pom.xml <!-- clip --> <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-weld-ee-embedded-1.1</artifactId> <version>1.0.0.CR3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-core</artifactId> <version>1.1.1.Final</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.5.10</version> <scope>test</scope> </dependency> <!-- clip -->

Listing 8
src/main/java/org/arquillian/example/PhraseBuilder.java package org.arquillian.example; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; public class PhraseBuilder { private Map<String, String> templates; public String buildPhrase(String id, Object... args) { return MessageFormat.format(templates.get(id), args); } @PostConstruct public void initialize() { templates = new HashMap<String, String>(); templates.put("hello", "Hello, {0}!"); } }

www.JAXenter.com | March 2012

24

Arquillian

and must be injected into the constructor of Greeter when an instance of Greeter is created. We can be certain CDI is at work if all that comes together. One last step. Because we created a new class, we must be sure that its getting added to the archive returned by the @ Deployment method in the test. Simply change the line:
.addClass(Greeter.class) ...to read: .addClasses(Greeter.class, PhraseBuilder.class)

Run the test again. You should get another green bar! Feels good, doesnt it?

Debug the test


This is going to be a short chapter. Why? Because an Arquillian test is so straightforward that you debug it exactly how you debug a unit test. Just add a breakpoint anywhere either in the test or in the application code. Then right-click on the file and select Debug As | JUnit Test (figure 5).Youre now debugging in the container! Have fun poking around! If you are using a remote container, Debug As does not cause breakpoints to be activated. Instead, you need to start the container in debug mode and attach the debugger. Thats because the test is run in a different JVM than the original test runner. As youve just witnessed, Arquillian is the ideal tool for testing CDI applications. It takes care of loading the CDI environment and injecting beans directly into the test. Best of all, when using an embedded CDI container, the test runs just as quickly as a unit test. If thats all you need, then you can exit the tutorial now and start writing tests.
Fig. 5: Debugging the container

But! Is the embedded container telling the whole story? Will the component work if running inside a full container? One of the perks of Arquillian is that you can run the same test in different compatible containers, whether its another embedded container or a standalone container. If you intend to use multiple containers, read on.

Add more containers


As you learned earlier, Arquillian selects the container based on which container adapter is on the classpath. To switch to another container, you just change which container adapter is on the classpath before you run the test. There can only be one container adapter on the classpath at a given time. One way to swap the libraries on the classpath is to manually edit the dependencies defined in the pom.xml each time. But thats just crazy. Theres a much better way. We can use Maven profiles to partition the dependencies into groups, one group for each container adapter and its related artifacts. When running the tests, you activate one of those groups to select the container using either a commandline flag (-P) or a preference in the IDE. Open up the pom.xml and create a new profile for Weld EE embedded by inserting the following XML directly under the <dependencies> element (listing 10). Next, remove the jboss-javaee-6.0 dependency and the dependencies for the Weld EE embedded container adapter from the main <dependencies> section. Listing 11 shows how the <dependencies> and <profiles> sections should look when youre done. The Java EE API dependency has been moved to the profile since some containers, like Embedded GlassFish, already provide these libraries. Having both on the classpath at the same time would result in conflicts. So we have to play this classpath dance. Well now include two additional profiles in the pom.xml inside the <profiles> element, the first for Embedded GlassFish ([14], listing 12). Now you have the choice of running the tests in one of three containers. If youre having trouble with the pom.xml up to this point, you can download the file from the gist [15].

Listing 9
src/main/java/org/arquillian/example/Greeter.java package org.arquillian.example; import java.io.PrintStream; import javax.inject.Inject; public class Greeter { private PhraseBuilder phraseBuilder; @Inject public Greeter(PhraseBuilder phraseBuilder) { this.phraseBuilder = phraseBuilder; } public void greet(PrintStream to, String name) { to.println(createGreeting(name)); } public String createGreeting(String name) { return phraseBuilder.buildPhrase("hello", name); } }

www.JAXenter.com | March 2012

25

Arquillian

Test across containers


When you refresh the project in Eclipse, youll notice that it no longer builds. Thats because you need to activate one of the container profiles. Lets activate the Weld EE embedded profile to restore the previous state. There are two ways to activate a Maven profile in Eclipse: 1. Manual configuration (standard approach) 2. Maven profile selector (JBoss Tools)

Set active Maven profile: Maven profile selector


If you have JBoss Tools installed, selecting the active profile becomes much easier: 1.   Right click on the project and select Maven | Select Active Profiles 2.  (alternatively, you can use the keybinding Ctrl+Shift+P or the button in the toolbar) 3.   Check the box next to the profile you want to activate (e.g., arquillian-weld-ee-embedded) 4.  Click the OK button

Set active Maven profile: manual configuration


To set the active profile manually, follow these steps: 1.  Right click on the project and select Properties 2.  Select the Maven properties tab 3.   Enter the profile id in the Active Maven Profiles field (e.g., arquillian-weld-ee-embedded) 4.  Click the OK button and accept the project changes Figure 6 displays the Maven properties screen showing the profile weve activated.

Listing 11
pom.xml <!-- clip --> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> </dependencies> <proles> <prole> <id>arquillian-weld-ee-embedded</id> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>1.0.0.Final</version> <type>pom</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-weld-ee-embedded-1.1</artifactId> <version>1.0.0.CR3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-core</artifactId> <version>1.1.1.Final</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.5.10</version> <scope>test</scope> </dependency> </dependencies> </prole> </proles> <!-- clip -->

Listing 10
pom.xml <!-- clip --> <proles> <prole> <id>arquillian-weld-ee-embedded</id> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>1.0.0.Final</version> <type>pom</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-weld-ee-embedded-1.1</artifactId> <version>1.0.0.CR3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-core</artifactId> <version>1.1.1.Final</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.5.10</version> <scope>test</scope> </dependency> </dependencies> </prole> </proles> <!-- clip -->

www.JAXenter.com | March 2012

26

Arquillian

Fig. 6: Maven properties screen showing the profile we have activated

Listing 12
pom.xml
<!-- clip --> <prole> <id>arquillian-glasssh-embedded</id> <dependencies> <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-glasssh-embedded-3.1</artifactId> <version>1.0.0.CR2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.glasssh.extras</groupId> <artifactId>glasssh-embedded-all</artifactId> <version>3.1</version> <scope>provided</scope> </dependency> </dependencies> </prole> <!-- clip -->
Fig. 7: Maven profile selector dialog showing the profile we have activated

Figure 7 displays the Maven profile selector dialog showing the profile weve activated. Once you have activated the profile, you should be able to run the test again successfully. You already know the test works in Weld EE Embedded. Lets switch to GlassFish Embedded by repeating the steps above, this time activating only the arquillian-glassfish-embedded profile. Run the test again. You should see GlassFish start in the consoleand another green bar! Youve now run the same test on two different embedded containers, a CDI container (Weld) and a Java EE container (GlassFish). Both of these executions are in process. To really be sure the component works in a pure environment, we need to use a standalone container. Lets switch to using JBoss AS. To run the test on a standalone instance of JBoss AS, you first need to set it up. You can either: 1.  download and unpack it in a location outside the project or 2.   you can have Maven download and unpack it during a build. Follow these steps to setup JBoss AS 7 outside the project: 1.  Download JBoss AS 7 [16] 2.   (be sure the version you select matches the version youve defined in your pom.xml for <artifactId>jboss-as-arquillian-container-managed</artifactId>) 3.  Extract the archive 4. (optional) Set the JBOSS_HOME environment variable to the path of the extracted directory To have Maven handle this task for you instead, add the following XML fragment under the <id> element of the arqjbossas-managed profile (listing 13). To target a managed JBoss AS 7 instance, you also need a small bit of Arquillian configuration. Create the following configuration file and assign the value of the jbossHome property to the location where JBoss AS 7 is installed. If youre using the Maven dependency plug-in, the location is target/ jboss-as-7.0.2.Final (listing 14).

and the other for JBoss AS managed:


pom.xml <!-- clip --> <prole> <id>arquillian-jbossas-managed</id> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>1.0.0.Final</version> <type>pom</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-arquillian-container-managed</artifactId> <version>7.1.0.Final</version> <scope>test</scope> </dependency> </dependencies> </prole> <!-- clip -->

www.JAXenter.com | March 2012

27

Arquillian

Now change the active Maven profile to arquillian-jbossasmanaged, then run the test again. You should see JBoss AS starting in the consoleand yet another green bar! The message printed to System.out gets written to the server log instead of the console. Thats the same test, this time running in a standard (nonembedded) Java EE container. Arquillian packages the test, deploys to the container as a Java EE archive, executes the

tests remotely, captures the results and feeds them back to the Eclipse JUnit result view (or in the Maven surefire results). You can read more about how this lifecycle works in the Arquillian reference guide [17].
Andrew L. Rubinger is an advocate for and speaker on testable enterprise Java development and author of Enterprise JavaBeans 3.1 from O'Reilly Media. He is a member of the JBoss Application Server development team and technical lead of the ShrinkWrap project. Andrew is proudly employed by JBoss/Red Hat. Dan is an open source advocate and community catalyst, author and speaker. He's currently pursuing these interests as a Principal Software Engineer at Red Hat. In that role, he serves as a JBoss Community liaison, contributes to several JBoss Community projects, including Arquillian, ShrinkWrap, Seam 3 / DeltaSpike and JBoss Forge, and participates in the JCP on behalf of Red Hat. Dan is the author Seam in Action (Manning, 2008), writes for IBM developerWorks, NFJS magazine and JAXenter and is an internationally recognized speaker. He's presented at major software conference series including JavaOne, Devoxx, NFJS, JAX and Jazoon. After a long conference day, you'll likely find Dan enjoying tech talk with fellow community members while savoring a Belgian Trappist beer. JBoss, Red Hat Arquillian project lead Aslak Knutsen is currently a Senior Software Engineer at JBoss, by Red Hat where he is working on projects such as Arquillian, ShrinkWrap, Weld and Seam 3, one of the founders of the JBoss Testing initiative and a speaker at major industry conferences including Devoxx, Jazoon, JFokus, Geecon, JUDCon and JBoss World. Previously, Aslak was a Senior Consultant at Conduct AS (working with JBoss related technologies) and Senior Developer at EDB ASA (working with electronic billing/banking systems).

Listing 13
pom.xml
<!-- clip --> <build> <plugins> <plugin> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack</id> <phase>process-test-classes</phase> <goals> <goal>unpack</goal> </goals> <conguration> <artifactItems> <artifactItem> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-dist</artifactId> <version>7.1.0.Final</version> <type>zip</type> <overWrite>false</overWrite> <outputDirectory>target</outputDirectory> </artifactItem> </artifactItems> </conguration> </execution> </executions> </plugin> </plugins> </build> <!-- clip -->

References & Additional Resources


[1] Maven download: http://maven.apache.org/download.html [2]  JDK download: http://www.oracle.com/technetwork/java/javase/downloads/ jdk-6u29-download-513648.html [3] http://arqpreview-alrubinger.rhcloud.com/guides/getting_started/index. html#generate_project_from_archetype [4] http://arqpreview-alrubinger.rhcloud.com/guides/getting_started/index. html#create_project_using_forge [5] FAQs: https://community.jboss.org/wiki/ WhatsTheCauseOfThisExceptionJavalangClassFormatErrorAbsentCode?_sscc=t

Listing 14
src/test/resources/arquillian.xml <arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd"> <container qualier="jbossas-7-managed" default="true"> <conguration> <property name="jbossHome">target/jboss-as-7.1.0.Final</property> </conguration> </container> </arquillian>

[6] http://arqpreview-alrubinger.rhcloud.com/guides/getting_started/index. html#open_project_in_eclipse [7] https://docs.jboss.org/author/display/FORGE/Home [8] https://community.jboss.org/wiki/MavenGettingStarted-Users [9] http://eclipse.org/m2e/ [10] http://www.jboss.org/tools [11] https://gist.github.com/1263892 [12] http://www.jboss.org/shrinkwrap [13] http://arqpreview-alrubinger.rhcloud.com/guides/shrinkwrap_introduction [14] http://embedded-glassfish.java.net/ [15] https://gist.github.com/1263934 [16] http://www.jboss.org/jbossas/downloads [17] https://docs.jboss.org/author/display/ARQ/Negotiating+test+execution

www.JAXenter.com | March 2012

28

Вам также может понравиться