CDI Extensions JTJ 2012 02
Transcript of CDI Extensions JTJ 2012 02
-
8/13/2019 CDI Extensions JTJ 2012 02
1/28
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 cur-
rently 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.
www.jaxenter.comIssue March 2012 |presented by
#16
TM
CDI IntroductionA Hollywood Story
Extension ProgrammingImplementing AdditionalFunctionality with CDI
Apache DeltaSpikeCreating a CDI Extension
ArquillianTestable Development of CDI
-
8/13/2019 CDI Extensions JTJ 2012 02
2/28
2www.JAXenter.com |March2012
Editorial
Putting together a JavaTechJournal issue about CDI is ahard task, one might think. But it was actually completelyeasy to get all those busy people on board helping out witharticles.
There are multiple reasons for this. The first one is that CDIwas a community-driven technology from the very beginning.The Java Expert Group for CDI was open from the verystart and continues to do so. It is one of the prototypes forJSR.next and formed a great community because of this
openness. And this community gives back 100 times the effortyou put into it.
The other reason is that its really fun to work with thistechnology. CDI is not some freaky artificial phantasm thathas no common ground with any real business. Nor is it along-time-grown monster that has tons of historical burdento carry with it. If you look at a project using CDI, you get thefeeling that its really done right. Most of the things you dowith 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
CDI much morethan a hype!
it serves more than 40,000 concurrent users, easily getting fivemillion page hits per day. And I do know of big banks andinsurance companies who handle even more throughput withCDI-based projects!
In this JavaTechJournal, we will cover CDI full circle. Inour introductory article, we will lay out the basics of thedependency injection core itself: its historical background,basic mechanisms, and key features. A second article willprovide the fundamentals of CDI Extension programming,
demonstrating how the CDI extension mechanism can beused to implement additional functionality in a portable,vendor-independent way. Another article will explain theCDI Ecosystem, showing how the popular projects Seam3and MyFaces CODI became Apache DeltaSpike. Last but notleast, we will shed a light on testing CDI applications with theJBoss Arquillian framework.
Please allow me to finally thank all the authors and allthose people who helped us reviewing and editing the contentand providing ideas, like Shane Bryzak (JBoss), Matt Benson(ASF) and many more.
Mark Struberg
A Hollywood Story 3Contexts and Dependency Injection for Java EE (JSR-299)Mark Struberg and Pete Muir
CDI Extension Programming 9Implementing additional functionality in a portable, vendor-independent wayRonald Steininger, Arne Limburg, and Mark Struberg
Apache DeltaSpike Closes the Gaps 14Creating a stable, reliable and truly portable CDI extensionGerhard Petracek and Jason Porter
Arquillian Makes Testing a Breeze 18Testable development of CDI
Dan Allen, Aslak Knutsen, and Andrew L. Rubinger
Index
-
8/13/2019 CDI Extensions JTJ 2012 02
3/28
CDI Introduction
www.JAXenter.com |March 2012 3
by Mark Struberg and Pete Muir
One of the most exciting features of CDI is to allow any-one to write powerful extensions to the core Java EE plat-form, even change core behaviour itself. These extensionsare fully portable across any environment which supportsCDI. Several libraries already provide CDI extensions, suchas Apache DeltaSpike, JBoss Seam 3, and Apache MyFacesCODI.
A little bit of historyOriginally developed under the name Web Beans, the CDIspecification 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 EnterpriseEdition (Java EE), but during the creation of the specification
it became obvious that most features were very useful for anyJava environment, including Java SE.
At the same time, both Guice and Spring communities hadbegun 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 de-pendency injection container without collaborating on theactual injection API, the AtInject and CDI expert groupsworked closely together to ensure a common solution acrossdependency injection frameworks. As a result, CDI uses theannotations from the AtInject specification, meaning that eve-ry CDI implementation fully implements the AtInject specifi-
cation, just like Guice and Spring. CDI and AtInject are bothincluded in Java Enterprise Edition 6 (JSR-316) and thus anintegral part of almost every Java Enterprise Edition server.
Contexts and Dependency Injection for Java EE (JSR-299)
A Hollywood StoryCDI 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.
-
8/13/2019 CDI Extensions JTJ 2012 02
4/28
CDI Introduction
www.JAXenter.com |March 2012 4
Essential CDIBefore we go on to dive into some code, lets take a quick lookat 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. Thisallows the compiler to easily detect errors, and provideseasy refactoring.
POJOs: Almost every Java object can be injected by CDI!This includes EJBs, JNDI resources, Persistence Units andPersistence Contexts, as well as any object which previ-ously would have been created by a factory method.
Extensibility: Every CDI container can enhance its func-tionality by using portable Extensions. The attributeportable means that those CDI Extensions can runon every CDI container and Java EE 6 server, no matterwhich vendor. This is accomplished by a well-specified SPI
(Service Provider Interface) which is part of the JSR-299specification.
Interceptors: It has never been easier to write your own In-terceptors. Because of the portable behaviour of JSR-299,they now also run on every EE 6-certified server and on allstandalone CDI containers.
Decorators: These allow to dynamically extend existinginterface implementations with business aspects.
Events: CDI specifies a type-safe mechanism to send andreceive events with loose coupling.
Unified EL integration: EL-2.2 opens a new horizon inregard of flexibility and functionality. CDI provides out-
of-the-box support for it!
Diving into CDILets start by exploring a sample web application. The ap-plication allows you to send e-mail via a web form fairlysimple. We only provide code fragments, but they should beenough to get the gist of how CDI is used. After showing eachpart of the application, we will discuss the details in the nextchapter.
For our mail application, we need an application-scopedMailService. Application-scoped objects are essentially sin-gletons the container will ensure you always get the sameinstance whenever you inject it into your application. The re-
plyToaddress is taken from the ConfigurationServicewhich
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 @Injectannotation tells CDI toperform the injection (listing 1).
Our application also identifies the current user (note that itdoesnt try to perform any authentication or authorization,we simply trust everyone!), and the current user is scopedto the HTTP session. CDI provides the session scope, whichensures that you will get the same instance of an object perHTTP Session (in a web application).
By default, CDI beans are not available for use in JSF viathe Unified Expression Language. In order to expose it for useby JSF and EL, we add the @Namedannotation (listing 2).
Now that we have a working application, lets exploresome of the CDI features we are using.
Listing 1
@ApplicationScoped
public class MyMailService implements MailService {
private @Inject ConfigurationService configuration;
public send(String from, String to, String body) {
String replyTo = configuration.getReplyToAddress();
...// send the email
}
}
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
}
}
The only missing part now is the JSF page itself, sendMail.xhtml:
-
8/13/2019 CDI Extensions JTJ 2012 02
5/28
CDI Introduction
www.JAXenter.com |March 2012 5
Basic mechanisms
Sometimes it's very helpful to look behind the scenes of aframework 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 theHollywood Principle don't call us, we call you. It meansthat we let the container manage the creation of instancesand inject it instead of creating them ourselves with the newoperator. Of course, even in DI containers, nothing happenswithout anyone triggering this process. For a JSR-299 con-tainer, this trigger is a call to one of the method
T BeanManager#getReference(Bean type, Qualifier... qualifiers);
which returns an instance of the given type T. By doing so, itwill not only create the returned instance, but also all of its@Inject-annotated children in a recursive way.
Usually the getReference(Bean)method is not called
manually, but internally by the Expression Language Resolv-er. By writing something like
the ELResolver will look for the Bean with the namemailForm and resolve the instance.
Scopes, contexts, singletons: Each of a CDI containersmanaged objects is a singleton in the original sense specifiedby Ward Cunningham, who invented not only the Wiki butalso, together with Kent Beck, introduced design patterns intocomputer science in 1987. A singleton in this sense means
that there is exactly one instance in a well-specified con-text. In a comment on Refactoring to Patterns by JoshuaKerievsky, Ward noted:
There is a proper context for every computation. So muchof object-oriented programming is about establishing con-text, about balancing the lifetimes of variables, causing themto live the right length of time and then die gracefully.
CDI is all about creating singletons in a well-specified con-text. In our case, the lifecycle of instances is defined by theirscopes. A @SessionScoped-annotated bean exists exactly onceper session. We could also name it a session singleton. If auser accesses our @SessionScopedbean for the first time, itwill get created and stored inside the session. Every subse-
quent access will return exactly this same instance. When thesession ends, all the CDI-managed instances stored inside itwill also be properly destroyed.
If we have a @RequestScopedbean, we could call it a re-quest singleton, a @ConversationScopedbean is a conversa-tion singleton, etc.
Terminus Managed Bean: There are a few terms used in theCDI specification which need a short explanation. The termBean in Java is already pretty well-established and means aPOJO (Plain Old Java Object) with getters and setters. Theterminus technicus Managed Bean now means somethingcompletely 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 Beanand will be gatheredon container startup via classpath scanning.
Terminus Contextual Instance: Contextual Instances are ex-actly our singleton instances per scope, our session singletons,request singletons, etc. Usually a user never uses a ContextualInstance directly, but only via its Contextual Reference
Terminus Contextual Reference: By default, a CDI con-tainer wraps all Contextual Instances via a proxy and onlyinjects those proxies instead of the real instances. In the CDIspecification 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 onlyneed to serialise the proxy. On de-serialisation, it willautomatically connect to the right Contextual Instanceagain.
Scope differences: With proxies, it is possible to inject a@SessionScopedUserSettings into an @ApplicationScopedMailServicebecause the Proxy will connect to the rightUserSettings itself.
Interceptors and Decorators: a proxy is the perfect way toimplement interceptors and decorators in a non-intrusiveway.
The lifecycle of a CDI container
Let's look at an easy scenario with a CDI container inside aplain Servlet engine such as Apache Tomcat. If a WebApplica-tiongets started, a ServletFilter will automatically also startyour CDI container which will firstly register all CDI-Exten-sions available on the ClassPathand then start with the classscanning. All ClassPathentries with a META-INF/beans.xmlwill be scanned and all classes will be parsed and stored as
Managed Bean (interface Bean) meta-information insidethe CDI container. The reason for scanning this informationon startup is to: first. detect errors early and second, vastlyimprove the performance at runtime.
To be able to handle all the CDI Scopes correctly, a CDIcontainer simply uses standard Servlet callbacks like Servlet-RequestListenerand HttpSessionListener.
Standard scopes
JSR-299 defines the most important scopes to build classicweb applications:
@ApplicationScoped @SessionScoped @ConversationScoped
@RequestScoped
Those scopes are meta-annotated as @NormalScopewhichmeans they have a well-defined lifecycle.
Beside those, there is another non-normal scope: @De-pendent. If a class doesn't have any explicit CDI scope an-notation or is explicitly annotated with @Dependent, aninstance will be created for each and every InjectionPointand will share the lifecycle of the contextual instances theyget injected into.
An example: if a @Dependent MySecurityHelperis injectedin a @RequestScoped MyBackingBean, then the MySecuri-tyHelper instance will be destroyed along with the MyBack-
-
8/13/2019 CDI Extensions JTJ 2012 02
6/28
-
8/13/2019 CDI Extensions JTJ 2012 02
7/28
CDI Introduction
www.JAXenter.com |March 2012 7
public @SessionScoped class MyBackingBean {
Locale userLanguage;
...
public void refreshLanguage(@Observes UserSettingsChanged usc) {
userLanguage = getDefaultLanguageOfUser(usc.getUserName());
}
...
}
If the UserSettingsChangeevent gets fired, all observer meth-ods of beans in currently active scopes will get invoked.
Interceptors
CDI provides an easy way to create own custom interceptors,as we will show by creating our own @Transactionalinter-ceptor. Instead of having to manage the transactions manu-ally, our small interceptor will do this for us as shown in thefollowing 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 meta-annotated as @InterceptorBindingwhich marks it as an an-notation that is intended to be used for interceptors:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.TYPE, ElementType.METHOD })
@InterceptorBinding
public @interface Transactional {}
The second part is the interceptor implementation itself. Thisclass must be annotated as @Interceptor and additionallywith its intended interceptor binding. The interceptor func-tionality itself is implemented in a method which gets anno-tated as @AroundInvoke(listing 4).
Final thoughts
After two years of availability, CDI is already seeing wideadoption. It has proven itself in a broad range of projects,from providing productivity in small start-ups to offering reli-ability and scalability websites with millions of users per day.
The Expert Group is currently working actively on CDI1.1, a specification which will bring small fixes and improve-ments, including much-requested standardization of Java SEbootstrap functionality for non-web applications.
Pete leads the Seam, Weld and CDI TCK projects, is an adviser to the
RichFaces project, and is a founder of the Arquil lian 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.
Mark Strubergis 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.
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
} finally {
if(t != null && t.isActive())
t.commit();
}
}}
-
8/13/2019 CDI Extensions JTJ 2012 02
8/28
CDI Introduction
www.JAXenter.com |March 2012 8SIGN UP NOW TO RESERVE YOUR PLACE:WWW.JAXDAYS.COM
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.
2ND-3RDAPRIL 2012
LONDONVICTORIA
PARK PLAZA
p re sen t s
THE ULTIMATE HANDS-ON LEARNING EXPERIENCE
TUESDAY
3rd April, 2012
Pragmatic Architecture
with Ted Neward
Advanced Neo4j
with Ian Robinson
& Jim Webber
An Introduction to NoSQL and
the Neo4j Graph Database
with Ian Robinson & Jim Webber
Java EE Efficient, Productive and Scalable
with Adam Bien
JavaEE Essentials
with Adam Bien
Groovy from Zero to Hero
with Russel Winder
The Busy Java Developers Guide to the JVMwith Ted Neward
MONDAY
2nd April, 2012
JTJREADERS
RECEIVE
10%DISCOUNT
USINGPROMOC
ODE
JDUGA2
-
8/13/2019 CDI Extensions JTJ 2012 02
9/28
CDI Extensions
www.JAXenter.com |March 2012 9
by Ronald Steininger, Arne Limburg, and Mark Struberg
This mechanism is called portable CDI extensions becauseit is based on a well-specified SPI which must be supportedby every certified standalone CDI container and EE 6 serv-er. Thus a CDI extension written on one CDI container willalso 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 ex-tensions are implemented, they can be reused with all CDIprovider implementations. Projects like Apache MyFacesCODI and JBoss Seam 3 provide collections of important,commonly-needed extensions, letting CDI users easily aug-ment their applications with the extensions they need withoutweighing down the core CDI implementation.
How does a CDI extension work?The CDI extension mechanism provides ways to hook customcode into the lifecycle of the CDI container. To leverage thispower in our own CDI extensions we must therefore know
the very basics of the CDI container lifecycle itself. We willfirst give you a quick overview of this process and dive intothe details later in the article.
The first task a CDI container performs is to load all CDIextensions. Next, all of the classes contained within JARfiles that have a META-INF/beans.xml marker file will bescanned also. For each of these classes an AnnotatedTypewill be constructed based on the given class. This object con-tains metadata about all annotations, constructors, methods,fields, etc. for the processed class. This information can bemodified by extensions. Later the CDI container will exposethis metadata in Bean instances used to manage contex-
tual objects.The container will start all available contexts after all class-
es 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 high-light what is necessary to leverage the extension mechanism ina CDI environment. In this article, we want to go through thesteps needed to build such scheduler integration by writing aCDI extension.
Creating a CDI extension is as simple as writing a classthat implements the interfacejavax.enterprise.inject.spi.Ex-
tension. This class will contain the functionality of our exten-sion. We will see in later chapters how this class can interactwith the CDI container.
Implementing additional functionality in a portable, vendor-independent way
CDI ExtensionProgrammingIn 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 exten-
sions are already available.
-
8/13/2019 CDI Extensions JTJ 2012 02
10/28
CDI Extensions
www.JAXenter.com |March 2012 10
The Container will pick up our extension via the Java Ser-viceLoader mechanism. Simply place a file namedjavax.en-terprise.inject.spi.Extension(the same name as the interface)within the META-INF/services folder of your JAR and ensurethis file contains the fully-qualified name of the Extensionimplementation. The container will look up the name of theclass 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 willfirst look into Quartz, the scheduler we want to integratewith, and how Quartz would be used without our extension.
The classic way to schedule jobs with Quartz
Quartz is an open-source job scheduling service. The user de-fines jobs and lets Quartz know when these jobs shouldbe executed via so-called triggers. The scheduler itself willthen run these jobs following the given rules.
The easiest way to use Quartz in a servlet container is prob-
ably to use the QuartzInitializerServletQuartz provides. Thisload-on-startup servlet initializes the scheduler automaticallyand adds a second servlet which actually schedules the jobs.Listing 1 shows a typical code block in that servlet whichschedules a job named MyJob to run every ten minutes.
Thats a lot of code just to schedule one job (and the codefor that job is still missing) but will work just fine for simpleuse cases and a small number of jobs that dont change much.
As soon as the jobs get a bit more complicated, there's aproblem: the jobs will not be aware of the CDI container,which means that they cannot use the features provided byCDI. This will be no problem for very simple jobs but won't
cut it as soon as the user wants to use a simple @Injectin oneof the jobs or a service that uses CDI. Some sort of integrationis needed to make all the features provided by CDI availableto the job, and the best way to accomplish this is by writingan Extension.
Schedule jobs the CDI way
Lets see how the jobs used with our extension will look:
1. The job implements thejava.lang.Runnableinterfacerather than the Job interface provided by Quartz. Thisway, the code is not Quartz-specific and the schedulerused by our extension can easily switched later. The
scheduler will call the run()method of this Runnablebased on the schedule we define.
2. Its possible to use CDI features like injection or intercep-tors in these jobs.
3. A @Scheduledannotation will tell our extension that thisclass defines a job that must be scheduled and what itsschedule will be (Listing 2).
Thats all that is needed to convey the same information asthe code example before.
For this example, @Scheduledis a simple annotation usedto set the schedule:
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scheduled {
String value();//the jobs schedule
}
It would be trivial to change this annotation to enable moreadvanced features like setting the schedule via dynamic con-figuration rather than hard-coding it in the jobs source; theannotation needs only to hold the information necessary to letour extension decide how to configure the job. Now its timeto look at the extension itself.
Creating the CDI extension
A CDI extension class implements thejavax.enterprise.inject.spi.Extensioninterface. This is just a marker interface andthus does not define any methods itself. Instead of using afixed set of methods statically defined in an interface, the con-tainer will fire a series of CDI Events during the container life-
cycle. The Extension can interact with the CDI container bydefining observer methods for such events. An observer meth-od is a non-static non-final method which has an @Observesparameter 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);
Listing 2
@Scheduled("0 0/10 * * * ?")
public class MyJob implements Runnable {
@Inject
private MyService service;
@Override
public void run() {
service.doSomething();
}}
-
8/13/2019 CDI Extensions JTJ 2012 02
11/28
CDI Extensions
www.JAXenter.com |March 2012 11
can not only gather information from the CDI container thisway; it can also modify this information and even transmitback new information to the container. As a rule of thumb,all things possible via CDI annotations can also be performedprogrammatically in an extension. You can very easily addor modify scopes, Interceptors, Decorators, InjectionPoints,Producer methods, ObserverMethods, etc. The defined con-tainer lifecycle events are:
BeforeBeanDiscovery
ProcessAnnotatedType
ProcessInjectionTarget and ProcessProducer
ProcessBeanand ProcessObserverMethod
AfterBeanDiscovery
AfterDeploymentValidation
BeforeShutdown
The first article of this series described how to observe cus-
tom CDI events. Extensions can observe the container systemevents in exactly the same way. To find every class that hasthe @Scheduledannotation, the extension should observe theProcessAnnotatedTypeevent. This system event is fired forevery class scanned by the container during boot. A Quartzjob and Quartz trigger can be created and started after thecontainer initialization is complete for any such annotationfound (Listing 3).
An observer for the BeforeBeanDiscoveryevent which isfired before the scanning process starts can be used to initial-ize the scheduler.
public void initScheduler(@Observes BeforeBeanDiscovery event) {scheduler = StdSchedulerFactory.getDefaultScheduler();
}
The scheduler also has to be started. This can be done in anAfterDeploymentValidation event observer. That event isfired after the container has validated that there are no de-ployment problems, so all jobs will be scheduled at this point.Additionally, the BeanManagercan be stored in the Exten-sion for later use (e.g. in the CdiJobclass).
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 anobserver of the BeforeShutdownevent.
public void shutdownScheduler(@Observes BeforeShutdown event) {
try {
Listing 3public 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 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);
}
Listing 4public class CdiJob implements org.quartz.Job {
public final 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 jobClass;
try {
jobClass = Class.forName(className).asSubclass(Runnable.class); } catch (ClassNotFoundException e) {
throw new JobExecutionException(e);
}
BeanManager bm = QuartzExtension.getBeanManager();
Set jobBean = bm.resolve(jobBeans);
CreationalContext c = bm.createCreationalContext(jobBean);
Runnable job = (Runnable) bm.getReference(jobBean, Runnable.class, c);
try {
job.run();
} finally {
jobBean.destroy(job, c);
}
}
}
-
8/13/2019 CDI Extensions JTJ 2012 02
12/28
CDI Extensions
www.JAXenter.com |March 2012 12
scheduler.shutdown(true);
} catch (SchedulerException se) {
throw new RuntimeException(se);
}
}
The following class does the work needed, so that a CDI-managed instance of the Runnable (our actual job) we definedis 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, sothat all of this happens in a manner completely transparent to
the user. Keep in mind that contexts like the RequestContextand SessionContextare not active for this job (there is noactive request nor session). If the injected services need thesecontexts because they depend on beans like a RequestScopedEntityManager, the contexts can be started and stopped in@PostConstructand @PreDestroymethods of the job. Thisis container-specific at the moment, but work is underwaywithin the Apache DeltaSpike project to make this possible ina vendor-independent way.
Publisher
Software & Support Media GmbH
Editorial Office Address
Darmstdter Landstrae 108
60598 Frankfurt am Main
Germany
www.jaxenter.com
Editor in Chief: Sebastian MeyenEditors: Claudia Frhling, Diana KupferAuthors: Dan Allen, Aslak Knutsen, Arne Limburg, Pete Muir, Gerhard Petraczek,
Jason Porter, Andrew L. Rubinger, Ronald Steininger, Mark Struberg
Copy Editor: Nicole Bechtel,Lisa PychlauCreative Director:
Jens Mainz
Layout: Tobias Dorn
Sales:
Cindy Ng
+44 (0)20 7401 4837
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 po-
sition 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 informa-
tion, and is not responsible for any errors, omissions, inadequacies, misuse, or the con-
sequences of using any information provided by Publisher. Rights of disposal of rewarded
articles belong to Publisher. All mentioned trademarks and service marks are copyrightedby their respective owners.
Imprint
Summary
One of the most important features of CDI is the possibilityto create extensions. With this mechanism, CDI can be ex-tended in a portable, vendor-independent way to provide newfeatures (like custom scopes), implement application-specificfunctionality (like loading configuration from an external da-tabase) or to integrate other technologies in a CDI-like fash-ion.
Ronald Steiningeris 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 mas-
ter thesis about the software architecture of campus management systems.
Arne Limburgis Enterprise Architect at open knowledge GmbH in Olden-
burg, Germany. He is an experienced developer, architect and trainer in
the Enterprise environment and also regularly involved in Android devel-
opment. 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 Strubergis 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.
-
8/13/2019 CDI Extensions JTJ 2012 02
13/28
Announcing the
JAX Innovation Awards 2012Celebrating the Best Innovations
in the Java Ecosystem
Submissions for the JAX Innovation Awards 2012 open
on March 16th. Nominate the people, companies andtechnologies you think are innovating the most.
www.jaxconf.com
The JAX Innovation Awards will be presented to winners
at a special ceremony on July 9 in San Francisco, CA.
Most Innovative Java Technology
Most Innovative Java Company
Top Java Ambassador
-
8/13/2019 CDI Extensions JTJ 2012 02
14/28www.JAXenter.com |March 2012 14
Apache DeltaSpike
by Gerhard Petracek and Jason Porter
In 2004 the world of J2EE started to change with the rise ofan alternative framework. Version 1.0 of the Spring frame-work was released and it became easier to implement enter-prise level applications. Spring gained a lot of popularity overtime and it also influenced Java EE. With the next version,Java EE focused on Ease of Development as well techni-cal concerns of the growing technical complexities requiredin applications. Even though Java EE became much simpler,there were still some loose ends. Therefore version 1.0 ofJBoss Seam was released in 2006. It provided a toolbox to fixsome of the shortcomings. At the same time, the Spring frame-work provided its own approach for integrating several partsof Java EE in a different manner. About one year later, JBossSeam version 2.0 was released and the MyFaces communityreleased version 1.0 of a new Spring extension named ApacheMyFaces Orchestra. MyFaces Orchestra introduced scopeswhich differed a lot from what was available so far, but thebasic purpose was similar to JBoss Seam. JSF users who pre-
ferred the Spring framework got a powerful tool with My-Faces Orchestra, and JSF users who were in favor of Java EE 5could use the Seam framework as a convenient toolbox. Lateron, several dependency injection frameworks inspired a newJava EE specification with the name Contexts and Dependen-cy Injection for Java EE (aka CDI) which was released in 2009as a part of Java EE 6. In parallel also the Spring frameworkmoved in a very similar direction. Both camps solve the sameproblems, but there are still significant differences.
The rise of CDI extensionsIn contrast to the Spring framework, CDI is available out-
of-the-box in Java EE 6+ application servers and thereforeits very important to have sufficient standardized hooks foradditional frameworks to use them independent of the details
of an application server to avoid vendor lock-in. Java EE 6is the first Java EE specification which doesnt need an addi-tional framework for painless usage or for replacing manualintegrations of different parts of the platform. At least thatsa common message of some community members. Java EE6 is closer to this statement than the former versions. How-ever, it turns out the real world isnt that shiny. A lot of newinnovations still happen in the Open Source space first andsome features might even be too special to be included intoa specification. Therefore it was intended to provide a richset of extension points from the very beginning. That allowsto keep specifications in general and CDI in particular con-sistent and simple without restricting custom approaches andmechanisms.
As mentioned earlier, CDI is provided out-of-the-box byJava EE 6+ servers and therefore a very important aspect ofCDI extensions is portability which allows them to be usedseamlessly in combination with all implementations of theCDI specification. Apache OpenWebBeans and JBoss Weldare such CDI implementations and they allow to use CDI
even with plain Java SE. Therefore, neither CDI nor portableCDI extensions are restricted to Java EE. That allows to cre-ate different types of CDI extensions. Apache DeltaSpike issuch a collection of portable CDI extensions. To understandthe roots of DeltaSpike its important to look at two famousportable CDI extensions - JBoss Seam3 and Apache MyFacesExtCDI (aka MyFaces CODI).
JBoss Seam3Seam 3 started shortly after JSR 299 completed. The goal ofSeam 3 was not to be a complete migration of all things fromSeam 2, but it provides a rich toolbox for building standards-
based web applications tailored for traditional and clouddeployments. Certainly some ideas came from Seam 2, butmany more came from the community. Unlike the starting
Creating a stable, reliable and truly portable CDI extension
Apache DeltaSpikeCloses the GapsThis 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.
-
8/13/2019 CDI Extensions JTJ 2012 02
15/28www.JAXenter.com |March 2012 15
Apache DeltaSpike
of Seam 1 and 2, Seam 3 did not simply want to improve JSFsupport, but to unite many technologies with CDI.
Many of the modules developed in Seam 3 demonstrate thissuch as Mail, JMS, JCR, Reports and Spring-Integra-tion. All of these modules came from the community as a holewas discovered while using the technologies and seeking a
more unified and simpler approach for developers. Other ar-eas in developer productivity were explored in Seam 3 such astype safe logging in Solder, exception handling also in Solderthough formerly Seam Catch, XML configuration via SeamConfig, now in Solder.
Apache MyFaces CODISimilar to JBoss Seam, MyFaces Orchestra provided betterscopes for JSF applications as well as an optional integrationwith the Java Persistence API (JPA) to allow the usage of anextended persistence context. Originally MyFaces CODI wasstarted to port some concepts provided by MyFaces Orches-
tra to a portable CDI extension. However, since CDI endorsestype-safe dependency injection, MyFaces CODI was designedfrom scratch and only some of the basic and successful con-cepts of MyFaces Orchestra were used as basis for some fea-tures of MyFaces CODI.
The most important qualities of MyFaces CODI, which at-tracted several users even before the release of version 1.0,are the reality check of existing concepts in combination withinnovative new mechanisms, the support for almost all majorJava EE 5/6 application servers, an easy but powerful API andSPI as well as a fast and solid implementation, and last butnot least, a great community.
MyFaces CODI doesnt enforce a specific programmingmodel. Instead it relies on CDI concepts as much as possibleand users just use what they need in addition. They can evenreplace parts of MyFaces CODI with custom implementa-tions which get picked up by the rest of the framework ordeactivate parts completely to improve the performance evenfurther. Like CDI itself, MyFaces CODI relies on type-safetyas much as possible. This allows use of standard Java supportin existing Java IDEs without the need for special IDE Add-ons. In addition, it avoids mistakes like typos and thereforeallows an easier refactoring and maintenance process.
The future Apache DeltaSpike
Since CDI encourages the usage of portable CDI extensions,users have to look at several accredited portable CDI exten-sions like JBoss Seam3 and Apache MyFaces CODI as well asseveral smaller projects and blog entries about implementingsuch extensions with varying quality. Several communities ofCDI extensions came up with similar ideas and features. Mostof the time it is possible to mix multiple portable CDI exten-sions without problems. However, usually there is no out-of-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 useSeam3 in combination with MyFaces CODI, but both have
different security concepts which are not aware of each otherout-of-the-box. Instead of implementing and documentingthe corresponding adapters for the major extensions, a large
part of the community decided to start a shared CDI exten-sions project developed and maintained by the community.The Apache Software Foundation was chosen due to its repu-tation concerning community-driven and vendor-independ-ent projects.
Amongst many others, the project management committee
of Apache MyFaces was excited about this idea, and the leaddevelopers of MyFaces CODI helped to draft a proposal forsuch a new Apache project. The hardest part was the namefor the project. After some discussions the upcoming commu-nity agreed on the intermediate name DeltaSpike. With thisname, the community entered the Apache Incubator, which isthe entry point for all new Apache projects. Before the projectleaves the incubator and graduates to an Apache top levelproject, the community will vote a final project-name.
The initial committers of the DeltaSpike community arerepresentatives of several existing CDI communities whichjoined the effort from the very beginning. Aside from some
other important tasks, the community merges features of theparticipating extension projects, adds new features and growsa community before DeltaSpike becomes a top level projectand leaves the Apache Incubator. Before a feature gets addedto DeltaSpike it is discussed by the community.
Progressing fastTwo months after the first e-mail on the mailing list [1],DeltaSpike v0.1 incubating was announced. With this firststep, the community started to merge features of Apache My-Faces CODI-Core and JBoss Solder which is a central partof Seam3. Every DeltaSpike release is well tested on multi-ple containers and many real world projects. Nonetheless it'sexpected that even APIs will change until version 1.0 basedon the feedback of the community and new features and bugfixes will be added quickly.
In the next release, the community will add further Del-taSpike-Core features as well as new modules. Besides re-viewing, discussing and adding features to DeltaSpike, thecommunity is also working on a great documentation, ex-amples, as well as a test-suite which should ensure true andtested portability across different environments.
Join the communityThere are already several very active community members
who enjoy the great cooperation. At Apache the most impor-tant part of a project is its community. Especially users whoare not familiar with Open-Source communities in general orApache projects in particular sometimes do not know how toget involved. Therefore the DeltaSpike community is work-ing on a short overview of different types of involvement andthe corresponding steps. Everybody is very welcome to get intouch with the community and every question which is notcovered by the Wiki [2] is very welcome to improve the Wikiand therefore the experience for new users. Its important tounderstand that everybody is welcome to join the discussionsor to provide feedback to improve DeltaSpike step by step. It
makes sense to join the effort as soon as possible because thecommunity moves fast and has agreed on releasing early andoften.
-
8/13/2019 CDI Extensions JTJ 2012 02
16/28www.JAXenter.com |March 2012 16
Apache DeltaSpike
The new era DeltaSpike v1.0 and beyondAfter merging the best features and introducing new con-cepts, you can expect that the result is better than the originalparts. An example which is available since v0.1-incubatingis @Exclude. In case of @Exclude the community merged@Vetofrom Solder with @ExpressionActivatedand @Pro-jectStageActivated of MyFaces CODI. Originally, the dis-cussion was about more expressive names for all of thoseannotations, and the result was a single annotation called@Excludewith the features of the original annotations. Thismeans the final version is more expressive and easier for userswithout losing functionality. The listings 1-3 show independ-ent beans with the new annotation. The result might soundobvious, but it took some time and a lot of e-mails to findthe right name which allowed to merge the functionality andpreserve the expressiveness.
As mentioned earlier, DeltaSpike will release early and of-ten. So 0.1-incubating doesn't contain that many features for
application developers, but DeltaSpike grows rapidly and be-sides DeltaSpike-Core the community is currently working ontwo new modules which will be part of the next release.
Right now all modules can be used even in Java SE ap-plications. After finishing the most important modules likeSecurity, I18n, Exception handling which can be used in JavaSE applications as well, the community plans to start with
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
{
//...
}
Listing 3: Utility class which shouldn't
be a CDI bean
@Exclude
public class CustomUtilClass
{
//...}
several integration modules for Java EE technologies like JSF,JPA, REST, JMS as well as other frameworks like Spring andQuartz.
The goal regarding JBoss Seam3 and Apache MyFacesCODI is to add as much as the majority can agree on. Sincethe community is optimistic to add and/or merge most fea-tures in/into DeltaSpike, it is expected to be easy for usersof the original extension projects to migrate to DeltaSpike.Instead of using workarounds for the migration, users are in-vited to join the effort early and share use cases which mightnot be supported at the time they try to switch to the corre-sponding module of DeltaSpike. In the end they should see aneven better approach they can use. Version 1.0 should be fast,thoroughly tested, very stable and compatible with all majorserver platforms which support CDI. The DeltaSpike teamis already very active, and all of us are confident that it willgrow as fast as DeltaSpike itself to reach the goal of a stable,reliable and truly portable CDI extension and even more im-
portant: a great community.
Gerhard Petracek is Apache MyFaces committer and PMC chair; Apache
OpenWebBeans committer and PMC member; Apache DeltaSpike com-
mitter, PPMC member and mentor; Apache member; Bean-Validation ex-
pert group member and a founder of Apache MyFaces Extensions
Validator, Apache MyFaces CODI and Apache DeltaSpike. At IRIAN Solu-
tions Gerhard is responsible for Java-EE trainings and the development of modernweb-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 Enter-
prise 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.
References & Additional Resources
[1] http://mail-archives.apache.org/mod_mbox/incubator-deltaspike-dev/
[2] https://cwiki.apache.org/confluence/display/DeltaSpike
-
8/13/2019 CDI Extensions JTJ 2012 02
17/28
JOIN US FOR 4 DAYS CRAMMED FULL OFTHE BEST JAVA CONTENT, SPEAKERS,
DISCUSSIONS AND NETWORKING
July 9 12, San Francisco, CA
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!
www.jaxconf.com
follow us: twitter.com/JAXconf JAXConf
Continous Delivery
Open Source Tools & Framework
SpringJava EE Languages
JavaScriptBig Data & NoSQL
Agile
Cloud
Java Performance
Android
HTML5
Java Core
Web Architecture
-
8/13/2019 CDI Extensions JTJ 2012 02
18/28
Arquillian
www.JAXenter.com |March 2012 18
Testable development of CDI
Arquillian MakesTesting 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 simpli-
fied POJO-based component model. Of course, CDI beans become such only within the context of a CDI Contain-
er, 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 forJava middleware. It deals with all the plumbing of containermanagement, deployment and framework initialization soyou can focus on the task at hand, writing your tests. Realtests. 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 resourc-es 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 devel-opers build environment, Arquillian integrates seamlessly withfamiliar testing frameworks (e.g., JUnit 4, TestNG 5), allowingtests to be launched using existing IDE, Ant and Maven testplug-ins without any add-ons. This guide introduces you toArquillian. After reading this guide, you will be able to:
Add the Arquillian infrastructure to a Maven-based Javaproject
Write an Arquillian test case to assert the behaviour of aCDI bean
Execute the Arquillian test case in multiple compatiblecontainers
Youll learn all of these skills by incorporating Arquillian intothe test suite of a Java EE application with a Maven build. Wevedesigned this guide to be a fast readto get you started quickly!
Assumptions
The easiest way to get started with Arquillian is to incorpo-rate it into the test suite of a project build that offers depend-ency management. Today, the most widely-used build tool in
this category is Apache Maven. This guide will navigate youto your first green bar using a sample Maven project.
Arquillian does not depend on Maven, or any specific buildtool for that matter. It works just as well if not better whenused in a project with an Ant or Gradle build. Ideally, thebuild tool should offer dependency management as it simpli-fies the task of including the Arquillian libraries since they aredistributed in the Maven Central repository
This guide assumes you have Maven available, either inyour command shell or your IDE. If you dont, please installMaven now [1]. You will also need JDK 1.6 [2] or better in-
stalled on your machine.
Create a new project
There are two ways we recommend you create a new Mavenproject:
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 sectionas review to ensure you have the proper dependencies beforemoving on.
By far, JBoss Forge is the simpler approach, but this guide
will offer both options in the event you arent ready to adoptJBoss Forge. Select from one of the two options above tojump to the instructions.
Generate a project from a Maven archetype
First, create a Maven-based Java project using the commandbelow. Copy the text after the $ and paste it into your com-mand shell.
$ mvn archetype:generate -DarchetypeGroupId=net.avh4.mvn.archetype \
-DarchetypeArtifactId=java-1.6-archetype
Respond to the prompts by entering the value shown aftereach double colon below. Hit the Enter key after each line (asindicated by ).
-
8/13/2019 CDI Extensions JTJ 2012 02
19/28
Arquillian
www.JAXenter.com |March 2012 19
Define value for propertygroupId: : org.arquillian.example Define value for property artifactId: : arquillian-tutorial
Define value for property version: : Define value for propertypackage: :
Confirm properties configuration:groupId: org.arquillian.exampleartifactId: arquillian-tutorialversion: 1.0-SNAPSHOTpackage: org.arquillian.exampleY: :
This command generated a Maven-based Java project in-side a new folder named arquillian-tutorialunder the cur-rent directory. The file structure of the project is shownbelow:
src/ main/
java/ Place all application Java source files here(under Java package)
resources/ Place all application configuration fileshere
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, theminimum required versions of Java and JUnit for using Ar-quillian, respectively.
The generator also created a Java package named org.
arquillian.example underneath the two java folders. Youshould put your Java source files in this package rather thanat the root of the java folder. Arquillian also supports TestNG5. However, we will be using JUnit throughout this guide.
Go ahead and open up the pom.xml in your editor. Youshould see an XML file containing basic project information, abuild section and a dependencies section. You can remove all theelements below the JUnit dependency as they arent required.
After making the change, you should end up with the con-tents seen in listing 1 (trimmed for brevity).
Were going to be writing Java EE 6 components. There-fore, we also need to add the Java EE 6 API to the classpath
so we can compile these components.Open up thepom.xmlfile once again and add the follow-ing XML fragment directly inside the element.Listing 2 shows how the section should look once youre done.
We strongly recommend that you do notuse the Java EEAPI artifact with coordinatesjavax:javaee-api. That bundlecontains classes with stripped method bodies, which willcause your application to throw strange Absent Code errorsif 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 thenext section to open the project in Eclipse [6] so we can startwriting some code!
Create a project using Forge
JBoss Forge [7] is a command shell for rapid-application de-velopment in a standards-based environment. Another wayto think of it is that its like Maven Archetypes on steroids.
Installing Forge is a relatively short process, and this guidewill take you through the fundamentals. Follow these simplesteps to get it installed:
1. Download Forge and unzip it into a folder on your hard-drive, which well call $FORGE_HOME
2. Well assume you extracted the distribution to a folder
named forge in your home directory3. Add $FORGE_HOME/bin to your path (Windows, Linux
or Mac OSX)
Listing 1
pom.xml
4.0.0
org.arquillian.example
arquillian-tutorial
1.0-SNAPSHOT
jar
arquillian-tutorial
org.apache.maven.plugins
maven-compiler-plugin
2.3.2
1.6
1.6
junit
junit
4.8.1
test
-
8/13/2019 CDI Extensions JTJ 2012 02
20/28
Arquillian
www.JAXenter.com |March 2012 20
On Unix-based operating sys-tems, adding Forge to yourpath typically means edit-ing your $HOME/.bashrc or$HOME/.profile; you willneed to set the following envi-
ronment variables:
$ export FORGE_HOME=$HOME/forge/$ export PATH=$PATH:$FORGE_HOME/bin
On Windows, you will need to right-click on CP, then click S P, open the Atab, then click E V and add these twoentries visually. We recommended setting User variables forForge, unless you have placed the unzipped distribution in afolder where all users can access it.
Now that Forge is installed (i.e., extracted), open a com-
mand prompt (a shell) and run the forge command (figure 1):
$ forge
[no project] ~ $
Thats it! Youve got Forge up and running. Now its time tocreate the project.
Inside the Forge shell, execute the following command tocreate a blank project, much like we created a project usingthe Maven Archetype above:
$ new-project --named arquillian-tutorial --topLevelPackage org.arquillian.example
This command generates a Maven-based Java project inside anew folder named arquillian-tutorial under the current direc-tory. The file structure of the project Forge generates is shownbelow:
src/ main/ java/ Place all application Java source files here (un-
der 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 directorywithin the Forge shell.
[arquillian-tutorial] arquillian-tutorial $
By default, Forge sets up the project to use Java 1.6, the mini-mum required version of Java to use Arquillian, a nice con-venience. What we need to add now is the Java EE APIs. Thatsdone 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 requiredversion of JUnit to use Arquillian, as a test-scoped dependency:
$ project add-dependency junit:junit:4.8.1:test
The result of thepom.xmlthat Forge generates is shown inListing 3.
Arquillian is now distributed in the Maven Central re-pository, so the JBoss Public repository declaration in thepom.xmlis unnecessary and can be removed. Keep in mind,though, you may need it to retrieve other JBoss software notavailable in Maven Central. If you follow the camp that con-sider repositories explicitly defined in your projectspom.xmlto be an antipattern, then read the instructions under [8] toenable the repository globally in your settings.xmlfile.
The foundation of your project is now ready! Lets nowopen 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, suchas Eclipse. Thats why Arquillian has been designed to be IDEfriendly, meaning you can run Arquillian tests from the IDEwithout making unconventional changes. So lets start takingadvantage of the IDE immediately.
Begin by launching Eclipse. Now, since this is a Maven pro-ject, 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 in-stall JBoss Tools [10]. Follow these steps to install it from theEclipse Marketplace (sort of like the app store for Eclipse).
Fig. 1: Starting Forge
Listing 2
pom.xml
org.jboss.spec
jboss-javaee-6.0
1.0.0.Final
pom
provided
junit
junit
4.8.1
test
-
8/13/2019 CDI Extensions JTJ 2012 02
21/28
Arquillian
www.JAXenter.com |March 2012 21
1. Select H | E M... from the main menu2. Type jboss tools in the Find input field (no quotes) and
press Enter3. 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 JavaEE applications, including excellent CDI support. Dont wor-ry, its not a heavyweight plugin.
However, if you just wantthe Maven integration with-out the extras that JBoss Toolsbrings, you can follow thesesteps instead:
1. Select H | E M-... from the mainmenu
2. Type maven in the Findinput field (no quotes) andpress E
3. Click the I buttonnext to Maven Integration for Eclipse
4. Complete the install wizard, then restart Eclipse if prompted5. Repeat the steps to install the Maven Integration for Eclipse
WTP
Once you have the Maven Integration plugin installed, followthese steps to open the project:
1. Select F | I... from the main menu2. Type existing maven in the input source field3. Select the option E M P, then click
the N button4. Click the B button5. Navigate the project folder on your filesystem, then click
the OK button6. Click the F button to open the project
Eclipse will recognize the Maven project and open it in theProject Navigator view. If you expand the project, it shouldlook similar to figure 2. Now we can really get down to busi-ness!
Create a component
In order to write an Arquillian test, we need to have a compo-nent for it to test. Lets begin by creating a basic componentso that you can learn how to execute an Arquillian test with-out other distractions. Well gradually move to more complexscenarios.
In your IDE, create a new Java class named Greeter in theorg.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 in-
voked as a CDI bean. Of course, we could simply write a unittest. But lets pretend that the bean uses enterprise services suchas dependency injection and messaging and must be used insidea container. (Besides, that way we give it room to grow).
To use the class as a CDI bean, well be injecting it into thetest using the @Injectannotation. That calls for an Arquilliantest, which means its time to add the Arquillian API to theproject!
Add the Arquillian APIs
Once again open up the pom.xmlfile, located in the rootfolder of the project, in your editor. We need to instruct Ma-ven which versions of the artifacts to use. Insert the following
Fig. 2: Eclipse will recognize and
open the Maven project in the
Project Navigator view.
Listing 3
pom.xml
4.0.0
org.arquillian.example
arquillian-tutorial
1.0.0-SNAPSHOT
org.jboss.spec
jboss-javaee-6.0
1.0.0.Final
provided
pom
junit
junit
4.8.1
test
JBOSS_NEXUS
http://repository.jboss.org/nexus/content/groups/public
arquillian-tutorial
maven-compiler-plugin
2.3.2
1.6
1.6
-
8/13/2019 CDI Extensions JTJ 2012 02
22/28
Arquillian
www.JAXenter.com |March 2012 22
XML fragment directly above the element to importthe BOM, or version matrix, for Arquillians transitive de-pendencies.
pom.xml
org.jboss.arquillian
arquillian-bom
1.0.0.CR7
import
pom
Next, append the following XML fragment directly under thelast element to add the Arquillian JUnit inte-gration:
pom.xml
org.jboss.arquillian.junit
arquillian-junit-container
test
The Arquillian JUnit integration artifact also adds the Arquil-lian and ShrinkWrapAPIs to the test classpath. You need allof these libraries to write and compile a JUnit Arquillian test.To use TestNG instead of JUnit, substitute the ArquillianJUnit integration with the Arquillian TestNG integration. Ifyoure having trouble with thepom.xmlup to this point, you
can download the file from the gist [11]. Youre all set towrite your first Arquillian test!
Write an Arquillian test
An Arquillian test looks just like a unit test, just with someextra flair. Lets return to the IDE. If you get the message
Project configuration is out of date with pom.xml, thenright click and select P | M | U PC to resync the project.
Begin by creating a new JUnit test case in src/test/javaunderthe org.arquillian.example package and name it GreeterTest.You wont need the typical setup and teardown methods sinceArquillian is doing most of the heavy lifting. Heres what wehave 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");
}
}
Now, about that flair. An Arquillian test case must have threethings:
1. A @RunWith(Arquillian.class) annotation on the class2. A static method annotated with @Deploymentthat returns
a ShrinkWrap archive3. At least one method annotated with @Test
The @RunWithannotation tells JUnit to use Arquillian as thetest controller. Arquillian then looks for a static method anno-tated with the @Deploymentannotation to retrieve the test ar-chive (i.e., micro-deployment). Then some magic happens andeach @Testmethod is run inside the container environment.
Whats a test archive?
The purpose of the test archive is to isolate the classes andresources which are needed by the test from the remainderof the classpath. Unlike a normal unit test, Arquillian doesnot simply dip into the entire classpath. Instead, you includeonly what the test needs (which may be the entire classpath, ifthats what you decide). The archive is defined using Shrink-Wrap [12], which is a Java API for creating archives (e. g., jar,war, ear) in Java. The micro-deployment strategy lets youfocus on precisely the classes you want to test and, as a result,the test remains very lean.
ShrinkWrap also supports resolving artifacts (libraries) andcreate configuration files programmatically, which can then
be added to the test archive. For a more thorough introduc-tion to ShrinkWrap, see the ShrinkWrap introduction guide[13]. Lets add that Arquillian flair to the test (listing 5).
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 + "!";
}}
-
8/13/2019 CDI Extensions JTJ 2012 02
23/28
Arquillian
www.JAXenter.com |March 2012 23
Using ShrinkWrap, weve defined a Java archive (jar) as thedeployment that includes the Greeter class that the test willinvoke and an empty beans.xmlin the META-INF directoryto activate CDI in this archive.
Now all we need to do is inject the Greeter instance into afield directly above the test method and replace the unimple-
mented test method with one that asserts the behavior of thebean. To give you that warm fuzzy feeling, well also print thegreeting 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");
}
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, Justlike a unit test youre correct! However, we first need to adda container adapter to the classpath.
Add a container adapter
Weve been talking a lot about testing in a container, but sofar we have not mentioned which one. Thats because its aruntime decision. Arquillian selects the target container basedon 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 iscompatible with the programming model used in the test (aslong as the container has an Arquillian adapter). Our test isusing the CDI programming model, so we need to use anycontainer to supports CDI. We want fast turnaround dur-ing development, so well start with the Weld EE embeddedcontainer.
Open thepom.xmlfile again and add the following groupof dependencies directly below the other ele-ments (listing 7).
To summarize, here are the three libraries you need to useArquillian (with JUnit):
1. Arquillian JUnit integration2. Arquillian container adapter for the target container3. Container runtime (embedded container) or container
client (remote container)
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");
}}
-
8/13/2019 CDI Extensions JTJ 2012 02
24/28
Arquillian
www.JAXenter.com |March 2012 24
Were using an embedded container in this example, so weneed the container runtime, Weld.Now back to the test.
Run the Arquillian test
Once you add all the necessary Arquillian libraries to theclasspath, 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.javafile in the Package Explorer (or in the editor) and select RA | JU T from the context menu (see fig. 3)
When you run the test, you should see the following linesprinted 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 (fig. 4)!
You can also run the test on the commandline using Maven:
$ mvn test
You should see the following lines printed to the console:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
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 secCongratulations! Youve earned your first green bar with Arquill ian!
A closer look
How do you know that CDI really worked? For all you know,Arquillian created a new instance of theGreeter class and in-jected it into the test without any involvement from CDI.Lets prove its there. Create a new CDI bean named Phrase-Builderin the org.arquillian.examplepackage that can createphrases from templates.
Next, open up the Greeter class and create a new construc-tor that will inject PhraseBuilderusing constructor injection.
Then, delegate the task of creating the greeting to the injectedbean (listing 9)Now, in order for the test to work, an instance of Phrase-
Builder must be created, its @PostConstructmethod invoked
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 templates;
public String buildPhrase(String id, Object... args) {
return MessageFormat.format(templates.get(id), args);
}
@PostConstruct
public void initialize() {
templates = new HashMap();
templates.put("hello", "Hello, {0}!");
}}
Fig. 4: JUnit view revealing a green bar
Fig. 3: Starting the test
Listing 7
pom.xml
org.jboss.arquillian.container
arquillian-weld-ee-embedded-1.1
1.0.0.CR3
test
org.jboss.weld
weld-core
1.1.1.Final
test
org.slf4j
slf4j-simple
1.5.10
test
-
8/13/2019 CDI Extensions JTJ 2012 02
25/28
Arquillian
www.JAXenter.com |March 2012 25
and must be injected into the constructor of Greeter whenan instance of Greeter is created. We can be certain CDI is atwork if all that comes together.
One last step. Because we created a new class, we must besure 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! Feelsgood, doesnt it?
Debug the test
This is going to be a short chapter. Why? Because an Arquil-lian test is so straightforward that you debug it exactly howyou debug a unit test. Just add a breakpoint anywhere either
in the test or in the application code. Then right-click on thefile and select D A | JU T (figure 5).Youre nowdebugging in the container! Have fun poking around!
If you are using a remote container, D A does not causebreakpoints to be activated. Instead, you need to start the con-tainer in debug mode and attach the debugger. Thats becausethe test is run in a different JVM than the original test runner.
As youve just witnessed, Arquillian is the ideal tool fortesting CDI applications. It takes care of loading the CDI en-vironment and injecting beans directly into the test. Best ofall, when using an embedded CDI container, the test runs justas quickly as a unit test. If thats all you need, then you can
exit the tutorial now and start writing tests.
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 anotherembedded container or a standalone container. If you intendto use multiple containers, read on.
Add more containers
As you learned earlier, Arquillian selects the container basedon which container adapter is on the classpath. To switch toanother container, you just change which container adapteris on the classpath before you run the test. There can only beone container adapter on the classpath at a given time.
One way to swap the libraries on the classpath is to manu-ally edit the dependencies defined in thepom.xmleach time.But thats just crazy. Theres a much better way.
We can use Maven profiles to partition the dependenciesinto groups, one group for each container adapter and its re-lated artifacts. When running the tests, you activate one ofthose groups to select the container using either a command-line flag (-P) or a preference in the IDE.
Open up thepom.xmland create a new profile for Weld EEembedded by inserting the following XML directly under theelement (listing 10).
Next, remove the jboss-javaee-6.0 dependency and thedependencies for the Weld EE embedded container adapter
from the main section. Listing 11 shows howthe and sections should look whenyoure done.
The Java EE API dependency has been moved to the pro-file since some containers, like Embedded GlassFish, alreadyprovide these libraries. Having both on the classpath at thesame time would result in conflicts. So we have to play thisclasspath dance.
Well now include two additional profiles in the pom.xmlinside the element, the first for Embedded Glass-Fish ([14], listing 12).
Now you have the choice of running the tests in one of
three containers. If youre having trouble with thepom.xmlup 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);
}
}
Fig. 5: Debugging the container
-
8/13/2019 CDI Extensions JTJ 2012 02
26/28
Arquillian
www.JAXenter.com |March 2012 26
Test across containers
When you refresh the project in Eclipse, youll notice that itno longer builds. Thats because you need to activate one ofthe container profiles. Lets activate the Weld EE embeddedprofile to restore the previous state. There are two ways toactivate a Maven profile in Eclipse:
1. Manual configuration (standard approach)2. Maven profile selector (JBoss Tools)
Set active Maven profile: manual configuration
To set the active profile manually, follow these steps:
1. Right click on the project and select Properties2. Select the Maven properties tab3. 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 6displays the Maven properties screen showing theprofile weve activated.
Set active Maven profile: Maven profile selector
If you have JBoss Tools installed, selecting the active profilebecomes much easier:
1. Right click on the project and select M | SA P
2. (alternatively, you can use the keybinding Ctrl+Shift+P orthe 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
Listing 11
pom.xml
junit
junit
4.8.1
test
org.jboss.arquillian.junit
arquillian-junit-container
test
arquillian-weld-ee-embedded
org.jboss.spec
jboss-javaee-6.0
1.0.0.Final
pom
provided
org.jboss.arquillian.container
arquillian-weld-ee-embedded-1.1
1.0.0.CR3
test
org.jboss.weld
weld-core
1.1.1.Final
test
org.slf4j
slf4j-simple
1.5.10
test
Listing 10
pom.xml
arquillian-weld-ee-embedded
org.jboss.spec
jboss-javaee-6.0
1.0.0.Final
pom
provided
org.jboss.arquillian.container
arquillian-weld-ee-embedded-1.1
1.0.0.CR3
test
org.jboss.weld
weld-core
1.1.1.Final
test
org.slf4j
slf4j-simple
1.5.10
test
-
8/13/2019 CDI Extensions JTJ 2012 02
27/28
Arquillian
www.JAXenter.com |March 2012 27
Figure 7displays the Maven profile selector dialog showingthe profile weve activated.
Once you have activated the profile, you should be able torun the test again successfully.
You already know the test works in Weld EE Embedded.Lets switch to GlassFish Embedded by repeating the stepsabove, this time activating only the arquillian-glassfish-em-bedded profile. Run the test again. You should see GlassFishstart in the consoleand another green bar!
Youve now run the same test on two different embeddedcontainers, 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 needto 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 or2. 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 jboss-as-arquil-lian-container-managed )
3. Extract the archive4. (optional) Set theJBOSS_HOMEenvironment variable to
the path of the extracted directory
To have Maven handle this task for you instead, add the fol-lowing XML fragment under the element of the arq-jbossas-managed profile (listing 13).
To target a managed JBoss AS 7 instance, you also needa small bit of Arquillian configuration. Create the followingconfiguration file and assign the value of thejbossHomeprop-
erty to the location where JBoss AS 7 is installed. If youreusing the Maven dependency plug-in, the location is target/jboss-as-7.0.2.Final(listing 14).
Listing 12
pom.xml
arquillian-glassfish-embedded
org.jboss.arquillian.container
arquillian-glassfish-em