Weld Reference
Weld Reference
JSR-299: The new Java standard for dependency injection and contextual lifecycle management
Gavin King Pete Muir Dan Allen David Allen Italian Translation: Nicola Benaglia, Francesco Milesi Spanish Translation: Gladys Guerrero Korean Translation: Eun-Ju Ki, Traditional Chinese Translation: Terry Chuang Simplified Chinese Translation: Sean Wu
A note about naming and nomenclature ...................................................................................... vii I. Beans ............................................................................................................................... 1 1. Introduction .............................................................................................................. 3 1.1. What is a bean? ............................................................................................... 3 1.2. Getting our feet wet .......................................................................................... 3 2. More about beans ..................................................................................................... 7 2.1. The anatomy of a bean ...................................................................................... 7 2.1.1. 2.1.2. 2.1.3. 2.1.4. Bean types, qualifiers and dependency injection .............................................. 8 Scope ................................................................................................ 10 EL name ............................................................................................ 10 Alternatives ......................................................................................... 11
2.1.5. Interceptor binding types ......................................................................... 11 2.2. What kinds of classes are beans? ....................................................................... 12 2.2.1. Managed beans .................................................................................... 12 2.2.2. Session beans ..................................................................................... 13 2.2.3. Producer methods ................................................................................. 14 2.2.4. Producer fields ..................................................................................... 16 3. JSF web application example ..................................................................................... 17 4. Dependency injection and programmatic lookup ............................................................ 21 4.1. Injection points ............................................................................................... 21 4.2. What gets injected ........................................................................................... 23 4.3. Qualifier annotations ........................................................................................ 23 4.4. The built-in qualifiers @Default and @Any ............................................................. 25 4.5. Qualifiers with members .................................................................................... 25 4.6. Multiple qualifiers ............................................................................................ 26 4.7. Alternatives .................................................................................................... 26 4.8. Fixing unsatisfied and ambiguous dependencies ...................................................... 27 4.9. Client proxies ................................................................................................. 27 4.10. Obtaining a contextual instance by programmatic lookup ........................................... 28 4.11. The InjectionPoint object .................................................................................. 30 5. Scopes and contexts ................................................................................................ 33 5.1. Scope types .................................................................................................. 33 5.2. Built-in scopes ................................................................................................ 33 5.3. The conversation scope .................................................................................... 34 5.3.1. Conversation demarcation ....................................................................... 35 5.3.2. Conversation propagation ........................................................................ 35 5.3.3. Conversation timeout ............................................................................. 36 5.4. The singleton pseudo-scope ............................................................................... 36 5.5. The dependent pseudo-scope ............................................................................. 37 5.6. The @New qualifier ......................................................................................... 37 II. Weld, the CDI Reference Implementation ................................................................................. 39 6. Getting started with Weld .......................................................................................... 41 6.1. Prerequisites .................................................................................................. 41 6.2. Deploying to JBoss AS ..................................................................................... 41 6.3. Deploying to GlassFish ..................................................................................... 43 6.4. Deploying to Apache Tomcat .............................................................................. 44 6.4.1. Deploying with Ant ................................................................................ 44 6.4.2. Deploying with Maven ............................................................................ 45 6.5. Deploying to Jetty ........................................................................................... 46 7. Diving into the Weld examples ................................................................................... 49 7.1. The numberguess example in depth ..................................................................... 49 7.1.1. The numberguess example in Apache Tomcat or Jetty .................................... 54 7.2. The numberguess example for Apache Wicket ........................................................ 54
iii
7.2.1. Creating the Eclipse project ..................................................................... 55 7.2.2. Running the example from Eclipse ............................................................. 57 7.2.3. Running the example from the command line in JBoss AS or Tomcat ................... 57 7.2.4. Understanding the code .......................................................................... 57 7.3. The numberguess example for Java SE with Swing .................................................. 59 7.4. The translator example in depth .......................................................................... 64 III. Loose coupling with strong typing ......................................................................................... 69 8. Producer methods ................................................................................................... 8.1. Scope of a producer method .............................................................................. 8.2. Injection into producer methods ........................................................................... 8.3. Use of @New with producer methods ................................................................... 71 72 72 73
8.4. Disposer methods ........................................................................................... 73 9. Interceptors ............................................................................................................ 75 9.1. Interceptor bindings ......................................................................................... 75 9.2. Implementing interceptors .................................................................................. 76 9.3. Enabling interceptors ........................................................................................ 76 9.4. Interceptor bindings with members ....................................................................... 77 9.5. Multiple interceptor binding annotations ................................................................. 78 9.6. Interceptor binding type inheritance ...................................................................... 79 9.7. Use of @Interceptors ....................................................................................... 79 10. Decorators ............................................................................................................ 81 10.1. Delegate object ............................................................................................. 82 10.2. Enabling decorators ........................................................................................ 83 11. Events .................................................................................................................. 85 11.1. Event payload ............................................................................................... 85 11.2. Event observers ............................................................................................ 85 11.3. Event producers ............................................................................................ 86 11.4. Conditional observer methods ........................................................................... 87 11.5. Event qualifiers with members ........................................................................... 87 11.6. Multiple event qualifiers ................................................................................... 88 11.7. Transactional observers ................................................................................... 88 12. Stereotypes ........................................................................................................... 91 12.1. Default scope for a stereotype ........................................................................... 91 12.2. Interceptor bindings for stereotypes .................................................................... 92 12.3. Name defaulting with stereotypes ....................................................................... 92 12.4. Alternative stereotypes .................................................................................... 92 12.5. Stereotype stacking ........................................................................................ 93 12.6. Built-in stereotypes ......................................................................................... 93 13. Specialization, inheritance and alternatives ................................................................. 95 13.1. Using alternative stereotypes ............................................................................ 95 13.2. A minor problem with alternatives ....................................................................... 96 13.3. Using specialization ........................................................................................ 97 14. Java EE component environment resources ................................................................ 99 14.1. Defining a resource ........................................................................................ 99 14.2. Typesafe resource injection ............................................................................. 100 IV. CDI and the Java EE ecosystem ........................................................................................ 103 15. Java EE integration ............................................................................................... 105 15.1. Built-in beans .............................................................................................. 105 15.2. Injecting Java EE resources into a bean ............................................................. 105 15.3. Calling a bean from a servlet .......................................................................... 106 15.4. Calling a bean from a message-driven bean ........................................................ 106 15.5. JMS endpoints ............................................................................................ 107 15.6. Packaging and deployment ............................................................................. 108
iv
16. Portable extensions ............................................................................................... 109 16.1. Creating an Extension ................................................................................... 109 16.2. Container lifecycle events ............................................................................... 110 16.3. The BeanManager object ............................................................................... 111 16.4. The InjectionTarget interface ........................................................................... 111 16.5. The Bean interface ....................................................................................... 112 16.6. Registering a Bean ....................................................................................... 113 16.7. Wrapping an AnnotatedType ........................................................................... 16.8. Wrapping an InjectionTarget ............................................................................ 16.9. The Context interface .................................................................................... 17. Next steps ................................................................................................................... 114 117 119 121
V. Weld reference ............................................................................................................... 123 18. Application servers and environments supported by Weld ............................................ 125 18.1. Using Weld with JBoss AS ............................................................................. 125 18.2. GlassFish ................................................................................................... 125 18.3. Servlet containers (such as Tomcat or Jetty) ........................................................ 125 18.3.1. Tomcat ........................................................................................... 126 18.3.2. Jetty ............................................................................................... 127 18.4. Java SE .................................................................................................... 127 18.4.1. CDI SE Module ................................................................................. 128 18.4.2. Bootstrapping CDI SE ......................................................................... 128 18.4.3. Thread Context ................................................................................. 130 18.4.4. Setting the Classpath .......................................................................... 130 19. CDI extensions available as part of Weld ................................................................... 131 19.1. Weld Logger ............................................................................................... 131 20. Alternative view layers ........................................................................................... 133 20.1. Wicket CDI integration ................................................................................... 133 20.1.1. The WebApplication class .................................................................... 133 20.1.2. Conversations with Wicket .................................................................... 133 A. Integrating Weld into other environments ........................................................................ 135 A.1. The Weld SPI .............................................................................................. 135 A.1.1. Deployment structure ........................................................................... 135 A.1.2. EJB descriptors .................................................................................. 136 A.1.3. EE resource injection and resolution services .............................................. 137 A.1.4. EJB services ...................................................................................... 137 A.1.5. JPA services ...................................................................................... 137 A.1.6. Transaction Services ............................................................................ 138 A.1.7. Resource Services .............................................................................. 138 A.1.8. Injection Services ................................................................................ 138 A.1.9. Security Services ................................................................................ 138 A.1.10. Bean Validation Services ..................................................................... 138 A.1.11. Identifying the BDA being addressed ....................................................... 138 A.1.12. The bean store ................................................................................. 139 A.1.13. The application context ....................................................................... 139 A.1.14. Initialization and shutdown ................................................................... 139 A.1.15. Resource loading .............................................................................. 139 A.2. The contract with the container ......................................................................... 139
vi
vii
viii
Part I. Beans
The JSR-299 [http://jcp.org/en/jsr/detail?id=299] specification (CDI) defines a set of complementary services that help improve the structure of application code. CDI layers an enhanced lifecycle and interaction model over existing Java component types, including managed beans and Enterprise Java Beans. The CDI services provide:
an improved lifecycle for stateful objects, bound to well-defined contexts, a typesafe approach to dependency injection, object interaction via an event notification facility, a better approach to binding interceptors to objects, along with a new kind of interceptor, called a decorator, that is more appropriate for use in solving business problems, and an SPI for developing portable extensions to the container. The CDI services are a core aspect of the Java EE platform and include full support for Java EE modularity and the Java EE component architecture. But the specification does not limit the use of CDI to the Java EE environment. In the Java SE environment, the services might be provided by a standalone CDI implementation like Weld (see Section 18.4.1, CDI SE Module), or even by a container that also implements the subset of EJB defined for embedded usage by the EJB 3.1 specification. CDI is especially useful in the context of web application development, but the problems it solves are general development concerns and it is therefore applicable to a wide variety of application. An object bound to a lifecycle context is called a bean. CDI includes built-in support for several different kinds of bean, including the following Java EE component types:
managed beans, and EJB session beans. Both managed beans and EJB session beans may inject other beans. But some other objects, which are not themselves beans in the sense used here, may also have beans injected via CDI. In the Java EE platform, the following kinds of component may have beans injected:
message-driven beans, interceptors, servlets, servlet filters and servlet event listeners, JAX-WS service endpoints and handlers, and JSP tag handlers and tag library event listeners. CDI relieves the user of an unfamiliar API of the need to answer the following questions:
What is the lifecycle of this object? How many simultaneous clients can it have? Is it multithreaded? How do I get access to it from a client?
Part I. Beans
Do I need to explicitly destroy it? Where should I keep the reference to it when I'm not currently using it? How can I define an alternative implementation, so that the implementation can vary at deployment time? How should I go about sharing this object between other objects? CDI is more than a framework. It's a whole, rich programming model. The theme of CDI is loose-coupling with strong typing. Let's study what that phrase means. A bean specifies only the type and semantics of other beans it depends upon. It need not be aware of the actual lifecycle, concrete implementation, threading model or other clients of any bean it interacts with. Even better, the concrete implementation, lifecycle and threading model of a bean may vary according to the deployment scenario, without affecting any client. This loose-coupling makes your code easier to maintain. Events, interceptors and decorators enhance the loose-coupling inherent in this model:
event notifications decouple event producers from event consumers, interceptors decouple technical concerns from business logic, and decorators allow business concerns to be compartmentalized. What's even more powerful (and comforting) is that CDI provides all these facilities in a typesafe way. CDI never relies on string-based identifiers to determine how collaborating objects fit together. Instead, CDI uses the typing information that is already available in the Java object model, augmented using a new programming pattern, called qualifier annotations, to wire together beans, their dependencies, their interceptors and decorators, and their event consumers. Usage of XML descriptors is minimized to truly deployment-specific information. But CDI isn't a restrictive programming model. It doesn't tell you how you should to structure your application into layers, how you should handle persistence, or what web framework you have to use. You'll have to decide those kinds of things for yourself. CDI even provides a comprehensive SPI, allowing other kinds of object defined by future Java EE specifications or by third-party frameworks to be cleanly integrated with CDI, take advantage of the CDI services, and interact with any other kind of bean. CDI was influenced by a number of existing Java frameworks, including Seam, Guice and Spring. However, CDI has its own, very distinct, character: more typesafe than Seam, more stateful and less XML-centric than Spring, more web and enterprise-application capable than Guice. But it couldn't have been any of these without inspiration from the frameworks mentioned and lots of collaboration and hard work by the JSR-299 Expert Group (EG). Finally, CDI is a Java Community Process [http://jcp.org] (JCP) standard. Java EE 6 requires that all compliant application servers provide support for JSR-299 (even in the web profile).
Chapter 1.
Introduction
So you're keen to get started writing your first bean? Or perhaps you're skeptical, wondering what kinds of hoops the CDI specification will make you jump through! The good news is that you've probably already written and used hundreds, perhaps thousands of beans. CDI just makes it easier to actually use them to build an application!
The second existing class is a stateless session bean front-end for an external system that is able to translate sentences from one language to another:
Chapter 1. Introduction
Unfortunately, we don't have a class that translates whole text documents. So let's write a bean for this job:
public class TextTranslator { private SentenceParser sentenceParser; private Translator sentenceTranslator; @Inject TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) { this.sentenceParser = sentenceParser; this.sentenceTranslator = sentenceTranslator; } public String translate(String text) { StringBuilder sb = new StringBuilder(); for (String sentence: sentenceParser.parse(text)) { sb.append(sentenceTranslator.translate(sentence)); } return sb.toString(); } }
But wait! TextTranslator does not have a constructor with no parameters! Is it still a bean? If you remember, a class that does not have a constructor with no parameters can still be a bean if it has a constructor annotated
@Inject.
As you've guessed, the @Inject annotation has something to do with dependency injection! @Inject may be applied to a constructor or method of a bean, and tells the container to call that constructor or method when instantiating the bean. The container will inject other beans into the parameters of the constructor or method. We may obtain an instance of TextTranslator by injecting it into a constructor, method or field of a bean, or a field or method of a Java EE component class such as a servlet. The container chooses the object to be injected based on the type of the injection point, not the name of the field, method or parameter. Let's create a UI controller bean that uses field injection to obtain an instance of the TextTranslator, translating the text entered by a user:
@Named @RequestScoped public class TranslateController { @Inject TextTranslator textTranslator; private String inputText;
private String translation; // JSF action method, perhaps public void translate() { translation = textTranslator.translate(inputText); } public String getInputText() { return inputText; } public void setInputText(String text) { this.inputText = text; } public String getTranslation() { return translation; } }
Tip
Notice the controller bean is request-scoped and named. Since this combination is so common in web applications, there's a built-in annotation for it in CDI that we could have used as a shorthand. When the (stereotype) annotation @Model is declared on a class, it creates a request-scoped and named bean.
Notice that it isn't necessary to create a getter or setter method to inject one bean into another. CDI can access an injected field directly (even if it's private!), which sometimes helps eliminate some wasteful code. The name of the field is arbitrary. It's the field's type that determines what is injected. At system initialization time, the container must validate that exactly one bean exists which satisfies each injection point. In our example, if no implementation of Translator is availableif the SentenceTranslator EJB was not deployedthe container would inform us of an unsatisfied dependency. If more than one implementation of
Translator were available, the container would inform us of the ambiguous dependency.
Before we get too deep in the details, let's pause and examine a bean's anatomy. What aspects of the bean are significant, and what gives it its identity? Instead of just giving examples of beans, we're going to define what makes something a bean.
Chapter 2.
A bean implementation Furthermore, a bean may or may not be an alternative. Let's see what all this new terminology means.
The bean types are BookShop, Business and Shop<Book>, as well as the implicit type java.lang.Object. (Notice that a parameterized type is a legal bean type). Meanwhile, this session bean has only the local interfaces BookShop, Auditable and java.lang.Object as bean types, since the bean class, BookShopBean is not a client-visible type.
@Stateful public class BookShopBean extends Business implements BookShop, Auditable { ... }
Note
The bean types of a session bean include local interfaces and the bean class local view (if any). EJB remote interfaces are not considered bean types of a session bean. You can't inject an EJB using its remote interface unless you define a resource, which we'll meet in Chapter 14, Java EE component environment resources.
Bean types may be restricted to an explicit set by annotating the bean with the @Typed annotation and listing the classes that should be bean types. For instance, the bean types of this bean have been restricted to Shop<Book>, together with java.lang.Object:
@Typed(Shop.class)
Sometimes, a bean type alone does not provide enough information for the container to know which bean to inject. For instance, suppose we have two implementations of the PaymentProcessor interface: CreditCardPaymentProcessor and DebitPaymentProcessor. Injecting a field of type PaymentProcessor introduces an ambiguous condition. In these cases, the client must specify some additional quality of the implementation it is interested in. We model this kind of "quality" using a qualifier. A qualifier is a user-defined annotation that is itself annotated @Qualifer. A qualifier annotation is an extension of the type system. It lets us disambiguate a type without having to fall back to string-based names. Here's an example of a qualifier annotation:
You may not be used to seeing the definition of an annotation. In fact, this might be the first time you've encountered one. With CDI, annotation definitions will become a familiar artifact as you'll be creating them from time to time.
Tip
Pay attention to the names of the built-in annotations in CDI and EJB. You'll notice that they are often adjectives. We encourage you to follow this convention when creating your custom annotations, since they serve to describe the behaviors and roles of the class.
Now that we have defined a qualifier annotation, we can use it to disambiguate an injection point. The following injection point has the bean type PaymentProcessor and qualifier @CreditCard:
Note
If an injection point does not explicitly specify a qualifier, it has the default qualifier, @Default.
For each injection point, the container searches for a bean which satisfies the contract, one which has the bean type and all the qualifiers. If it finds exactly one matching bean, it injects an instance of that bean. If it doesn't, it reports an error to the user. How do we specify that qualifiers of a bean? By annotating the bean class, of course! The following bean has the qualifier @CreditCard and implements the bean type PaymentProcessor. Therefore, it satisfies our qualified injection point:
Note
If a bean does not explicitly specify a qualifier, it has the default qualifier, @Default.
That's not quite the end of the story. CDI also defines a simple resolution rule that helps the container decide what to do if there is more than one bean that satisfies a particular contract. We'll get into the details in Chapter 4, Dependency injection and programmatic lookup.
2.1.2. Scope
The scope of a bean defines the lifecycle and visibility of its instances. The CDI context model is extensible, accommodating arbitrary scopes. However, certain important scopes are built into the specification, and provided by the container. Each scope is represented by an annotation type. For example, any web application may have session scoped bean:
An instance of a session-scoped bean is bound to a user session and is shared by all requests that execute in the context of that session.
Note
Keep in mind that once a bean is bound to a context, it remains in that context until the context is destroyed. There is no way to manually remove a bean from a context. If you don't want the bean to sit in the session indefinitely, consider using another scope with a shorted lifespan, such as the request or conversation scope.
If a scope is not explicitly specified, then the bean belongs to a special scope called the dependent pseudo-scope. Beans with this scope live to serve the object into which they were injected, which means their lifecycle is bound to the lifecycle of that object. We'll talk more about scopes in Chapter 5, Scopes and contexts.
2.1.3. EL name
If you want to reference a bean in non-Java code that supports Unified EL expressions, for example, in a JSP or JSF page, you must assign the bean an EL name. The EL name is specified using the @Named annotation, as shown here:
10
Alternatives
Now we can easily use the bean in any JSF or JSP page:
Note
The @Named annotation is not what makes the class a bean. Most classes in a bean archive are already recognized as beans. The @Named annotation just makes it possible to reference the bean from the EL, most commonly from a JSF view.
We can let CDI choose a name for us by leaving off the value of the @Named annotation:
The name defaults to the unqualified class name, decapitalized; in this case, shoppingCart.
2.1.4. Alternatives
We've already seen how qualifiers let us choose between multiple implementations of an interface at development time. But sometimes we have an interface (or other bean type) whose implementation varies depending upon the deployment environment. For example, we may want to use a mock implementation in a testing environment. An alternative may be declared by annotating the bean class with the @Alternative annotation.
We normally annotate a bean @Alternative only when there is some other implementation of an interface it implements (or of any of its bean types). We can choose between alternatives at deployment time by selecting an alternative in the CDI deployment descriptor META-INF/beans.xml of the jar or Java EE module that uses it. Different modules can specify that they use different alternatives. We cover alternatives in more detail in Section 4.7, Alternatives.
11
annotation or in the XML descriptor. You might as well just put the interceptor code in the implementation! Second, the order in which the interceptors are applied is taken from the order in which they are declared in the annotation or the XML descriptor. Perhaps this isn't so bad if you're applying the interceptors to a single bean. But, if you are applying them repeatedly, then there's a good chance that you'll inadvertently define a different order for different beans. Now that's a problem. CDI provides a new approach to binding interceptors to beans that introduces a level of indirection (and thus control). We must define an interceptor binding type to describe the behavior implemented by the interceptor. An interceptor binding type is a user-defined annotation that is itself annotated @InterceptorBinding. It lets us bind interceptor classes to bean classes with no direct dependency between the two classes.
We can apply the interceptor to a bean by annotating the bean class with the same interceptor binding type:
Notice that ShoppingCart and TransactionInterceptor don't know anything about each other. Interceptors are deployment-specific. (We don't need a TransactionInterceptor in our unit tests!) By default, an interceptor is disabled. We can enable an interceptor using the CDI deployment descriptor META-INF/ beans.xml of the jar or Java EE module. This is also where we specify the interceptor ordering. We'll discuss interceptors, and their cousins, decorators, in Chapter 9, Interceptors and Chapter 10, Decorators.
12
Session beans
It is a concrete class, or is annotated @Decorator. It is not annotated with an EJB component-defining annotation or declared as an EJB bean class in ejb-jar.xml. It does not implement javax.enterprise.inject.spi.Extension. It has an appropriate constructoreither: the class has a constructor with no parameters, or the class declares a constructor annotated @Inject.
Note
According to this definition, JPA entities are technically managed beans. However, entities have their own special lifecycle, state and identity model and are usually instantiated by JPA or using new. Therefore we don't recommend directly injecting an entity class. We especially recommend against assigning a scope other than @Dependent to an entity class, since JPA is not able to persist injected CDI proxies.
The unrestricted set of bean types for a managed bean contains the bean class, every superclass and all interfaces it implements directly or indirectly. If a managed bean has a public field, it must have the default scope @Dependent. Managed beans support the @PostConstruct and @PreDestroy lifecycle callbacks. Session beans are also, technically, managed beans. However, since they have their own special lifecycle and take advantage of additional enterprise services, the CDI specification considers them to be a different kind of bean.
Note
Message-driven and entity beans are by nature non-contextual objects and may not be injected into other objects. However, message-driven beans can take advantage of some CDI functionality, such as dependency injection, interceptors and decorators. In fact, CDI will perform injection into any session or message-driven bean, even those which are not contextual instances.
The unrestricted set of bean types for a session bean contains all local interfaces of the bean and their superinterfaces. If the session bean has a bean class local view, the unrestricted set of bean types contains the bean class and all superclasses. In addition, java.lang.Object is a bean type of every session bean. But remote interfaces are not included in the set of bean types. There's no reason to explicitly declare the scope of a stateless session bean or singleton session bean. The EJB container controls the lifecycle of these beans, according to the semantics of the @Stateless or @Singleton declaration. On the other hand, a stateful session bean may have any scope.
13
Stateful session beans may define a remove method, annotated @Remove, that is used by the application to indicate that an instance should be destroyed. However, for a contextual instance of the beanan instance under the control of CDIthis method may only be called by the application if the bean has scope @Dependent. For beans with other scopes, the application must let the container destroy the bean. So, when should we use a session bean instead of a plain managed bean? Whenever we need the advanced enterprise services offered by EJB, such as:
method-level transaction management and security, concurrency management, instance-level passivation for stateful session beans and instance-pooling for stateless session beans, remote or web service invocation, or timers and asynchronous methods, When we don't need any of these things, an ordinary managed bean will serve just fine. Many beans (including any @SessionScoped or @ApplicationScoped beans) are available for concurrent access. Therefore, the concurrency management provided by EJB 3.1 is especially useful. Most session and application scoped beans should be EJBs. Beans which hold references to heavy-weight resources, or hold a lot of internal state benefit from the advanced container-managed lifecycle defined by the EJB stateless/stateful/singleton model, with its support for passivation and instance pooling. Finally, it's usually obvious when method-level transaction management, method-level security, timers, remote methods or asynchronous methods are needed. The point we're trying to make is: use a session bean when you need the services it provides, not just because you want to use dependency injection, lifecycle management, or interceptors. Java EE 6 provides a graduated programming model. It's usually easy to start with an ordinary managed bean, and later turn it into an EJB just by adding one of the following annotations: @Stateless, @Stateful or @Singleton. On the other hand, don't be scared to use session beans just because you've heard your friends say they're "heavyweight". It's nothing more than superstition to think that something is "heavier" just because it's hosted natively within the Java EE container, instead of by a proprietary bean container or dependency injection framework that runs as an additional layer of obfuscation. And as a general principle, you should be skeptical of folks who use vaguely defined terminology like "heavyweight".
new. There are plenty of cases where we need additional control. What if we need to decide at runtime which
implementation of a type to instantiate and inject? What if we need to inject an object that is obtained by querying a service or transactional resource, for example by executing a JPA query? A producer method is a method that acts as a source of bean instances. The method declaration itself describes the bean and the container invokes the method to obtain an instance of the bean when no instance exists in the specified context. A producer method lets the application take full control of the bean instantiation process. A producer method is declared by annotating a method of a bean class with the @Produces annotation.
@ApplicationScoped
14
Producer methods
public class RandomNumberGenerator { private Random random = new Random(System.currentTimeMillis()); @Produces @Named @Random int getRandomNumber() { return random.nextInt(100); } }
We can't write a bean class that is itself a random number. But we can certainly write a method that returns a random number. By making the method a producer method, we allow the return value of the methodin this case an Integerto be injected. We can even specify a qualifierin this case @Random, a scopewhich in this case defaults to @Dependent, and an EL namewhich in this case defaults to randomNumber according to the JavaBeans property name convention. Now we can get a random number anywhere:
A producer method must be a non-abstract method of a managed bean class or session bean class. A producer method may be either static or non-static. If the bean is a session bean, the producer method must be either a business method of the EJB or a static method of the bean class. The bean types of a producer method depend upon the method return type:
If the return type is an interface, the unrestricted set of bean types contains the return type, all interfaces it extends directly or indirectly and java.lang.Object. If a return type is primitive or is a Java array type, the unrestricted set of bean types contains exactly two types: the method return type and java.lang.Object. If the return type is a class, the unrestricted set of bean types contains the return type, every superclass and all interfaces it implements directly or indirectly.
Note
Producer methods and fields may have a primitive bean type. For the purpose of resolving dependencies, primitive types are considered to be identical to their corresponding wrapper types in java.lang.
If the producer method has method parameters, the container will look for a bean that satisfies the type and qualifiers of each parameter and pass it to the method automaticallyanother form of dependency injection.
15
We'll talk much more about producer methods in Chapter 8, Producer methods.
public class Shop { @Produces PaymentProcessor paymentProcessor = ....; @Produces @Catalog List<Product> products = ....; }
The rules for determining the bean types of a producer field parallel the rules for producer methods. A producer field is really just a shortcut that lets us avoid writing a useless getter method. However, in addition to convenience, producer fields serve a specific purpose as an adaptor for Java EE component environment injection, but to learn more about that, you'll have to wait until Chapter 14, Java EE component environment resources. Because we can't wait to get to work on some examples.
16
Chapter 3.
@Named @RequestScoped public class Credentials { private String username; private String password; @NotNull @Length(min=3, max=25) public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @NotNull @Length(min=6, max=20) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
This bean is bound to the login prompt in the following JSF form:
<h:form> <h:panelGrid columns="2" rendered="#{!login.loggedIn}"> <f:validateBean> <h:outputLabel for="username">Username:</h:outputLabel> <h:inputText id="username" value="#{credentials.username}"/> <h:outputLabel for="password">Password:</h:outputLabel> <h:inputSecret id="password" value="#{credentials.password}"/> </f:validateBean> </h:panelGrid> <h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/> <h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/> </h:form>
@Entity public class User { private @NotNull @Length(min=3, max=25) @Id String username; private @NotNull @Length(min=6, max=20) String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String setPassword(String password) { this.password = password; } }
(Note that we're also going to need a persistence.xml file to configure the JPA persistence unit containing
User.)
17
The actual work is done by a session-scoped bean that maintains information about the currently logged-in user and exposes the User entity to other beans:
@SessionScoped @Named public class Login implements Serializable { @Inject Credentials credentials; @Inject @UserDatabase EntityManager userDatabase; private User user; public void login() { List<User> results = userDatabase.createQuery( "select u from User u where u.username = :username and u.password = :password") .setParameter("username", credentials.getUsername()) .setParameter("password", credentials.getPassword()) .getResultList(); if (!results.isEmpty()) { user = results.get(0); } else { // perhaps add code here to report a failed login } } public void logout() { user = null; } public boolean isLoggedIn() { return user != null; } @Produces @LoggedIn User getCurrentUser() { return user; } }
18
Now DocumentEditor, or any other bean, can easily inject the current user:
public class DocumentEditor { @Inject Document document; @Inject @LoggedIn User currentUser; @Inject @DocumentDatabase EntityManager docDatabase; public void save() { document.setCreatedBy(currentUser); docDatabase.persist(document); } }
Hopefully, this example gave you a taste of the CDI programming model. In the next chapter, we'll explore dependency injection in greater depth.
19
20
Chapter 4.
public class Checkout { private final ShoppingCart cart; @Inject public Checkout(ShoppingCart cart) { this.cart = cart; } }
Note
A bean can only have one injectable constructor.
public class Checkout { private ShoppingCart cart; @Inject void setShoppingCart(ShoppingCart cart) { this.cart = cart; } }
21
Note
A bean can have multiple initializer methods. If the bean is a session bean, the initializer method is not required to be a business method of the session bean.
Note
Getter and setter methods are not required for field injection to work (unlike with JSF managed beans).
Dependency injection always occurs when the bean instance is first instantiated by the container. Simplifying just a little, things happen in this order:
First, the container calls the bean constructor (the default constructor or the one annotated @Inject), to obtain an instance of the bean. Next, the container initializes the values of all injected fields of the bean. Next, the container calls all initializer methods of bean (the call order is not portable, don't rely on it). Finally, the @PostConstruct method, if any, is called. (The only complication is that the container might call initializer methods declared by a superclass before initializing injected fields declared by a subclass.)
Tip
One major advantage of constructor injection is that it allows the bean to be immutable.
CDI also supports parameter injection for some other methods that are invoked by the container. For instance, parameter injection is supported for producer methods:
This is a case where the @Inject annotation is not required at the injection point. The same is true for observer methods (which we'll meet in Chapter 11, Events) and disposer methods.
22
allow the client to select which implementation it requires using a qualifier or allow the application deployer to select which implementation is appropriate for a particular deployment, without changes to the client, by enabling or disabling an alternative, or allow the beans to be isolated into separate modules. Obviously, if you have exactly one bean of a given type, and an injection point with that same type, then bean A is going to go into slot A. That's the simplest possible scenario. When you first start your application, you'll likely have lots of those. But then, things start to get complicated. Let's explore how the container determines which bean to inject in more advanced cases. We'll start by taking a closer look at qualifiers.
PaymentProcessor:
@Synchronous public class SynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
@Asynchronous public class AsynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
@Qualifier
23
A client bean developer uses the qualifier annotation to specify exactly which bean should be injected. Using field injection:
@Inject public void setPaymentProcessors(@Synchronous PaymentProcessor syncPaymentProcessor, @Asynchronous PaymentProcessor asyncPaymentProcessor) { this.syncPaymentProcessor = syncPaymentProcessor; this.asyncPaymentProcessor = asyncPaymentProcessor; }
@Inject public Checkout(@Synchronous PaymentProcessor syncPaymentProcessor, @Asynchronous PaymentProcessor asyncPaymentProcessor) { this.syncPaymentProcessor = syncPaymentProcessor; this.asyncPaymentProcessor = asyncPaymentProcessor; }
Qualifier annotations can also qualify method arguments of producer, disposer and observer methods. Combining qualified arguments with producer methods is a good way to have an implementation of a bean type selected at runtime based on the state of the system:
@Produces PaymentProcessor getPaymentProcessor(@Synchronous PaymentProcessor syncPaymentProcessor, @Asynchronous PaymentProcessor asyncPaymentProcessor) { return isSynchronous() ? syncPaymentProcessor : asyncPaymentProcessor; }
If an injected field or a parameter of a bean constructor or initializer method is not explicitly annotated with a qualifier, the default qualifier, @Default, is assumed. Now, you may be thinking, "What's the different between using a qualifier and just specifying the exact implementation class you want?" It's important to understand that a qualifier is like an extension of the interface. It does not create a direct dependency to any particular implementation. There may be multiple alterative implementations of @Asynchronous PaymentProcessor!
24
Tip
This is especially useful if you want to iterate over all beans with a certain bean type. For example:
@Inject void initServices(@Any Instance<Service> services) { for (Service service: services) { service.init(); } }
@Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface PayBy { PaymentMethod value(); }
Then we select one of the possible member values when appling the qualifier:
We can force the container to ignore a member of a qualifier type by annotating the member @Nonbinding.
@Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface PayBy { PaymentMethod value(); @Nonbinding String comment() default ""; }
25
Then only a bean which has both qualifier annotations would be eligible for injection.
@Synchronous @Reliable public class SynchronousReliablePaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
4.7. Alternatives
Alternatives are beans whose implementation is specific to a particular client module or deployment scenario. This alternative defines a mock implementation of both @Synchronous PaymentProcessor and @Asynchronous PaymentProcessor, all in one:
@Alternative @Synchronous @Asynchronous public class MockPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
By default, @Alternative beans are disabled. We need to enable an alternative in the beans.xml descriptor of a bean archive to make it available for instantiation and injection. This activation only applies to the beans in that archive.
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <class>org.mycompany.mock.MockPaymentProcessor</class> </alternatives> </beans>
When an ambiguous dependency exists at an injection point, the container attempts to resolve the ambiguity by looking for an enabled alternative among the beans that could be injected. If there is exactly one enabled alternative, that's the bean that will be injected.
26
HowDoAResolveAnAmbiguousResolutionExceptionBetweenAProducerMethodAndARawType] for step-by-step instructions for how to resolve an ambigous resolution exception between a raw bean type and a producer method that returns the same bean type.
Tip
Just remember: "There can be only one."
On the other hand, if you really do have an optional or multivalued injection point, you should change the type of your injection point to Instance, as we'll see in Section 4.10, Obtaining a contextual instance by programmatic lookup. Now there's one more issue you need to be aware of when using the dependency injection service.
27
Therefore, unless a bean has the default scope @Dependent, the container must indirect all injected references to the bean through a proxy object. This client proxy is responsible for ensuring that the bean instance that receives a method invocation is the instance that is associated with the current context. The client proxy also allows beans bound to contexts such as the session context to be serialized to disk without recursively serializing other injected beans. Unfortunately, due to limitations of the Java language, some Java types cannot be proxied by the container. If an injection point declared with one of these types resolves to a bean with any scope other than @Dependent, the container will abort deployment, informing us of the problem. The following Java types cannot be proxied by the container: classes which don't have a non-private constructor with no parameters, and classes which are declared final or have a final method, arrays and primitive types. It's usually very easy to fix an unproxyable dependency problem. If an injection point of type X results in an unproxyable dependency, simply: add a constructor with no parameters to X, change the type of the injection point to Instance<X>, introduce an interface Y, implemented by the injected bean, and change the type of the injection point to Y, or if all else fails, change the scope of the injected bean to @Dependent.
Note
A future release of Weld will likely support a non-standard workaround for this limitation, using non-portable JVM APIs: Sun, IcedTea, Mac: Unsafe.allocateInstance() (The most efficient) IBM, JRockit: ReflectionFactory.newConstructorForSerialization() But we didn't get around to implementing this yet.
28
PaymentProcessor p = paymentProcessorSource.get();
by annotating the Instance injection point, or by passing qualifiers to the select() of Event. Specifying the qualifiers at the injection point is much, much easier:
Now, the PaymentProcessor returned by get() will have the qualifier @Asynchronous. Alternatively, we can specify the qualifier dynamically. First, we add the @Any qualifier to the injection point, to suppress the default qualifier. (All beans have the qualifier @Any.)
Next, we need to obtain an instance of our qualifier type. Since annotatons are interfaces, we can't just write new
Asynchronous(). It's also quite tedious to create a concrete implementation of an annotation type from scratch. Instead, CDI lets us obtain a qualifier instance by subclassing the helper class AnnotationLiteral.
Note
We can't use an anonymous class to implement a qualifier type with members.
Now, finally, we can pass the qualifier to the select() method of Instance.
29
This clever little producer method lets you inject a JDK Logger without explicitly specifying the log category:
Not convinced? Then here's a second example. To inject HTTP parameters, we need to define a qualifier type:
@BindingType @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface HttpParam { @Nonbinding public String value(); }
30
class HttpParams @Produces @HttpParam("") String getParamValue(ServletRequest request, InjectionPoint ip) { return request.getParameter(ip.getAnnotated().getAnnotation(HttpParam.class).value()); } }
(Note that the value() member of the HttpParam annotation is ignored by the container since it is annotated @Nonbinding.) The container provides a built-in bean that implements the InjectionPoint interface:
public interface InjectionPoint { public Type getType(); public Set<Annotation> getQualifiers(); public Bean<?> getBean(); public public public public } Member getMember(); Annotated getAnnotated(); boolean isDelegate(); boolean isTransient();
31
32
Chapter 5.
When a new instance of any bean with that scope is created When an existing instance of any bean with that scope is destroyed Which injected references refer to any instance of a bean with that scope For example, if we have a session-scoped bean, CurrentUser, all beans that are called in the context of the same HttpSession will see the same instance of CurrentUser. This instance will be automatically created the first time a CurrentUser is needed in that session, and automatically destroyed when the session ends.
Tip
JPA entities aren't a great fit for this model. Entities have their whole own lifecycle and identity model which just doesn't map naturally to the model used in CDI. Therefore, we recommend against treating entities as CDI beans. You're certainly going to run into problems if you try to give an entity a scope other than the default scope @Dependent. The client proxy will get in the way if you try to pass an injected instance to the JPA EntityManager.
Of course, that's the easy part of the job. For this scope type to be useful, we will also need to define a Context object that implements the scope! Implementing a Context is usually a very technical task, intended for framework development only. You can expect an implementation of the business scope, for instance, in a future version of Seam. We can apply a scope type annotation to a bean implementation class to specify the scope of the bean:
33
@RequestScoped @SessionScoped @ApplicationScoped @ConversationScoped For a web application that uses CDI:
any servlet request has access to active request, session and application scopes, and, additionally any JSF request has access to an active conversation scope.
Note
A CDI extension can implement support for the conversation scope in other web frameworks.
during invocations of EJB remote methods, during invocations of EJB asynchronous methods, during EJB timeouts, during message delivery to a message-driven bean, during message delivery to a MessageListener, and during web service invocations. If the application tries to invoke a bean with a scope that does not have an active context, a
is demarcated explicitly by the application, and holds state associated with a particular web browser tab in a JSF application (browsers tend to share domain cookies, and hence the session cookie, between tabs, so this is not the case for the session scope). A conversation represents a taska unit of work from the point of view of the user. The conversation context holds state associated with what the user is currently working on. If the user is doing multiple things at the same time, there are multiple conversations.
34
Conversation demarcation
The conversation context is active during any JSF request. Most conversations are destroyed at the end of the request. If a conversation should hold state across multiple requests, it must be explicitly promoted to a long-running conversation.
To promote the conversation associated with the current request to a long-running conversation, call the begin() method from application code. To schedule the current long-running conversation context for destruction at the end of the current request, call end(). In the following example, a conversation-scoped bean controls the conversation with which it is associated:
@ConversationScoped @Stateful public class OrderBuilder { private Order order; private @Inject Conversation conversation; private @PersistenceContext(type = EXTENDED) EntityManager em; @Produces public Order getOrder() { return order; } public Order createOrder() { order = new Order(); conversation.begin(); return order; } public void addLineItem(Product product, int quantity) { order.add(new LineItem(product, quantity)); } public void saveOrder(Order order) { em.persist(order); conversation.end(); } @Remove public void destroy() {} }
This bean is able to control its own lifecycle through use of the Conversation API. But some other beans have a lifecycle which depends completely upon another object.
35
We can force the conversation to propagate with a non-faces request by including the unique identifier of the conversation as a request parameter. The CDI specification reserves the request parameter named cid for this use. The unique identifier of the conversation may be obtained from the Conversation object, which has the EL bean name conversation. Therefore, the following link propagates the conversation:
Tip
The conversation context propagates across redirects, making it very easy to implement the common POST-then-redirect pattern, without resort to fragile constructs such as a "flash" object. The container automatically adds the conversation id to the redirect URL as a request parameter.
conversation.setTimeout(timeoutInMillis);
Note
Unlike the other scopes, which belong to the package javax.enterprise.context, the
You can guess what "singleton" means here. It means a bean that is instantiated once. Unfortunately, there's a little problem with this pseudo-scope. Beans with scope @Singleton don't have a proxy object. Clients hold a direct
36
reference to the singleton instance. So we need to consider the case of a client that can be serialized, for example, any bean with scope @SessionScoped or @ConversationScoped, any dependent object of a bean with scope
An instance of a dependent bean is never shared between different clients or different injection points. It is strictly a dependent object of some other object. It is instantiated when the object it belongs to is created, and destroyed when the object it belongs to is destroyed. If a Unified EL expression refers to a dependent bean by EL name, an instance of the bean is instantiated every time the expression is evaluated. The instance is not reused during any other expression evaluation.
Tip
If you need to access a bean directly by EL name in a JSF page, you probably need to give it a scope other than @Dependent. Otherwise, any value that gets set to the bean by a JSF input will be lost immediately. That's why CDI features the @Model stereotype; it lets you give a bean a name, and set its scope to @RequestScoped in one stroke. If you need to access a bean that really has to have the scope @Dependent from a JSF page, inject it into a different bean, and expose it to EL via a getter method.
Beans with scope @Dependent don't need a proxy object. The client holds a direct reference to its instance. CDI makes it easy to obtain a dependent instance of a bean, even if the bean is already declared as a bean with some other scope type.
37
The class must be a valid managed bean or session bean, but need not be an enabled bean. This works even if Calculator is already declared with a different scope type, for example:
public class PaymentCalc { @Inject Calculator calculator; @Inject @New Calculator newCalculator; }
The calculator field has a conversation-scoped instance of Calculator injected. The newCalculator field has a new instance of Calculator injected, with a lifecycle that is bound to the owning PaymentCalc. This feature is particularly useful with producer methods, as we'll see in the next chapter.
38
Chapter 6.
6.1. Prerequisites
To run the examples with the provided build scripts, you'll need the following:
the latest release of Weld, which contains the examples Ant 1.7.0, to build and deploy the examples a supported runtime environment (minimum versions shown) JBoss AS 6.0.0, GlassFish 3.0, Apache Tomcat 6.0.x (war example only), or Jetty 6.1.x (war example only) (optionally) Maven 2.x, to run the examples in an embedded servlet container
Note
You'll need a full install of Ant 1.7.0. Some linux distributions only supply a partial installation of Ant which cause the build to fail. If you encounter problems, verify that ant-nodeps.jar is on the classpath.
In the next few sections, you'll be using the Ant command (ant) to invoke the Ant build script in each example to compile, assemble and deploy the example to JBoss AS and, for the war example, Apache Tomcat. You can also deploy the generated artifact (war or ear) to any other container that supports Java EE 6, such as GlassFish 3. If you have Maven installed, you can use the Maven command (mvn) to compile and assemble the standalone artifact (war or ear) and, for the war example, run it in an embedded container. The sections below cover the steps for deploying with both Ant and Maven in detail. Let's start with JBoss AS.
41
that has both CDI and Bean Validation support built-in, making it close enough to Java EE 6 to run the examples. The good news is that there are no additional modifications you have to make to the server. It's ready to go! After you have downloaded JBoss AS, extract it. (We recommended renaming the folder to include the as qualifier so it's clear that it's the application server). You can move the extracted folder anywhere you like. Wherever it lays to rest, that's what we'll call the JBoss AS installation directory, or JBOSS_HOME.
In order for the build scripts to know where to deploy the example, you have to tell them where to find your JBoss AS installation (i.e., JBOSS_HOME). Create a new file named local.build.properties in the examples directory of the Weld distribution and assign the path of your JBoss AS installation to the property key jboss.home, as follows:
jboss.home=/path/to/jboss-as-6.0
You're now ready to deploy your first example! Switch to the examples/jsf/numberguess directory and execute the Ant deploy target:
If you haven't already, start JBoss AS. You can either start JBoss AS from a Linux shell:
Note
If you are using Eclipse, you should seriously consider installing the JBoss Tools [http:// www.jboss.org/tools] add-ons, which include a wide variety of tooling for JSR-299 and Java EE development, as well as an enhanced JBoss AS server view.
Wait a few seconds for the application to deploy (or the application server to start) and see if you can determine the most efficient approach to pinpoint the random number at the local URL http://localhost:8080/weld-numberguess.
42
Deploying to GlassFish
Tip
The Ant build script includes additional targets for JBoss AS to deploy and undeploy the archive in either exploded or packaged format and to tidy things up. ant restart - deploy the example in exploded format to JBoss AS ant explode - update an exploded example, without restarting the deployment ant deploy - deploy the example in compressed jar format to JBoss AS ant undeploy - remove the example from JBoss AS ant clean - clean the example
The second starter example, weld-translator, will translate your text into Latin. (Well, not really, but the stub is there for you to implement, at least. Good luck!) To try it out, switch to the translator example directory and execute the deploy target:
Note
The translator uses session beans, which are packaged in an EJB module within an ear. Java EE 6 will allow session beans to be deployed in war modules, but that's a topic for a later chapter.
Again, wait a few seconds for the application to deploy (if you're really bored, read the log messages), and visit http:// localhost:8080/weld-translator to begin pseudo-translating.
On Windows you can just click on the executable. Follow the instructions in the installer. It will create a single domain named domain1. You'll use that domain to deploy the example. We recommend that you choose 7070 as the main HTTP port to avoid conflicts with a running instance of JBoss AS (or Apache Tomcat).
43
If you've deployed either of the starter examples, weld-numberguess or weld-translator, to JBoss AS, then you already have the deployable artifact you need. If not, switch to either of the two directories and build it.
The deployable archive for the weld-numberguess, named weld-numberguess.war, ends up in the example's target directory. The archive for the weld-translator example, named weldtranslator.ear, ends up in the example's ear/target directory. All you need to do now is deploy them to GlassFish. You deploy applications to GlassFish using the GlassFish Admin Console [http://localhost:4848]. To get the Admin Console running, you need to start a GlassFish domain, in our case domain1. Switch to the bin folder in the directory where you installed GlassFish and execute the following command:
After a few seconds you can visit the Admin Console in the browser at the URL http://localhost:4848. In the tree on the left-hand side of the page, click on "Applications", then click on the "Deploy..." button under the heading "Applications" and select the deployable artifact for either of the two examples. The deployer should recognize that you have selected a Java EE artifact and allow you to start it. You can see the examples running at either http://localhost:7070/ weld-numberguess or http://localhost:7070/weld-translator, depending on which example you deployed. The reason the same artifact can be deployed to both JBoss AS and GlassFish, without any modifications, is because all of the features being used are part of the standard platform. And what a capable platform it has become!
You have two choices for how you can deploy the application to Tomcat. You can deploy it by pushing the artifact to the hot deploy directory using Ant or you can deploy to the server across HTTP using a Maven plugin. The Ant approach doesn't require that you have Maven installed, so we'll start there. If you want to use Maven, you can just skip ahead.
44
the Weld distribution. If you haven't yet created this file, do so now. Then assign the path of your Tomcat installation to the property key tomcat.home.
tomcat.home=/path/to/apache-tomcat-6
Now you're ready to deploy the numberguess example to Tomcat! Change to the examples/jsf/numberguess directory again and run the Ant deploy target for Tomcat:
Tip
The Ant build script includes additional targets for Tomcat to deploy and undeploy the archive in either exploded or packaged format. They are the same target names used for JBoss AS, prefixed with "tomcat.". ant tomcat.restart - deploy the example in exploded format to Tomcat ant tomcat.explode - update an exploded example, without restarting the deployment ant tomcat.deploy - deploy the example in compressed jar format to Tomcat ant tomcat.undeploy - remove the example from Tomcat
If you haven't already, start Tomcat. You can either start Tomcat from a Linux shell:
or you can start the server using an IDE, like Eclipse. Wait a few seconds for the application to deploy (or the application server to start) and see if you can figure out the most efficient approach to pinpoint the random number at the local URL http://localhost:8080/weld-numberguess!
45
The Maven plugin communicates with Tomcat over HTTP, so it doesn't care where you have installed Tomcat. However, the plugin configuration assumes you are running Tomcat in its default configuration, with a hostname of localhost and port 8080. The readme.txt file in the example directory has information about how to modify the Maven settings to accommodate a different setup. To allow Maven to communicate with Tomcat over HTTP, edit the conf/tomcat-users.xml file in your Tomcat installation and add the following line:
Restart Tomcat. You can now deploy the application to Tomcat with Maven using this command:
Once the application is deployed, you can redeploy it using this command:
The -Ptomcat argument activates the tomcat profile defined in the Maven POM (pom.xml). Among other things, this profile activates the Tomcat plugin. Rather than shipping the container off to a standalone Tomcat installation, you can also execute the application in an embedded Tomcat 6 container:
The advantage of using the embedded server is that changes to assets in src/main/webapp take effect immediately. If a change to a webapp configuration file is made, the application may automatically redeploy (depending on the plugin configuration). If you make a change to a classpath resource, you need to execute a build:
There are several other Maven goals that you can use if you are hacking on the example, which are documented in the example's readme.txt file.
46
Deploying to Jetty
The Maven POM (pom.xml) includes a profile named jetty that activates the Maven Jetty plugin, which you can use to start Jetty in embedded mode and deploy the application in place. You don't need anything else installed except to have the Maven command (mvn) on your path. The rest will be downloaded from the internet when the build is run. To run the weld-numberguess example on Jetty, switch to the example directory and execute the inplace goal of the Maven war plugin followed by the run goal of the Maven Jetty plugin with the jetty profile enabled, as follows:
The log output of Jetty will be shown in the console. Once Jetty reports that the application has deployed, you can access it at the following local URL: http://localhost:9090/weld-numberguess. The port is defined in the Maven Jetty plugin configuration within the jetty profile. Any changes to assets in src/main/webapp take effect immediately. If a change to a webapp configuration file is made, the application may automatically redeploy. The redeploy behavior can be fined-tuned in the plugin configuration. If you make a change to a classpath resource, you need to execute a build and the inplace goal of the Maven war plugin, again with the jetty profile enabled.
The war:inplace goal copies the compiled classes and jars inside src/main/webapp, under WEB-INF/ classes and WEB-INF/lib, respectively, mixing source and compiled files. However, the build does work around these temporary files by excluding them from the packaged war and cleaning them during the Maven clean phase. You have two options if you want to run the example on Jetty from the IDE. You can either install the m2eclispe[link] plugin and run the goals as described above. Your other option is to start the Jetty container from a Java application. First, initialize the Eclipse project:
Now, you are ready to run the server in Eclipse. Import the project into your Eclipse workspace using "Import Existing Project into Workspace. Then, find the start class in src/jetty/java and run its main method as a Java Application. Jetty will launch. You can view the application at the following local URL: http://localhost:8080. Pay particular attention to the port in the URL and the lack of a trailing context path. Now that you have gotten the starter applications deployed on the server of your choice, you probably want to know a little bit about how they actually work.
47
48
Chapter 7.
There's also an empty beans.xml file, which tells the container to look for beans in this application and to activate the CDI services. Finally, there's the familiar web.xml:
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>weld-jsf-numberguess-war</display-name> <description>Weld JSF numberguess example (war)</description>
49
Enable and initialize the JSF servlet Configure requests for URLs ending in .jsf to be handled by JSF Tell JSF that we will be giving our JSF views (Facelets templates) an extension of .xhtml Configure a session timeout of 10 minutes
Note
This demo uses JSF 2 as the view framework, but you can use Weld with any servlet-based web framework, such as JSF 1.2 or Wicket.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<ui:composition template="/template.xhtml"> <ui:define name="content"> <h1>Guess a number...</h1> <h:form id="numberGuess"> <div style="color: red"> <h:messages id="messages" globalOnly="false"/> <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}"/> <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}"/> </div>
<div> I'm thinking of a number between #{game.smallest} and #{game.biggest}. You have #{game.remainingGuesses} guesses remaining. </div> <div> Your guess:
50
<h:inputText id="inputGuess" value="#{game.guess}" size="3" required="true" disabled="#{game.number eq game.guess}" validator="#{game.validateNumberRange}"/> <h:commandButton id="guessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/> </div> <div> <h:commandButton id="restartButton" value="Reset" action="#{game.reset}" immediate="true"/> </div> </h:form> </ui:define> </ui:composition> </html>
Facelets is the built-in templating language for JSF. Here we are wrapping our page in a template which defines the layout. There are a number of messages which can be sent to the user, "Higher!", "Lower!" and "Correct!" As the user guesses, the range of numbers they can guess gets smaller - this sentence changes to make sure they know the number range of a valid guess. This input field is bound to a bean property using a value expression. A validator binding is used to make sure the user doesn't accidentally input a number outside of the range in which they can guess - if the validator wasn't here, the user might use up a guess on an out of bounds number. And, of course, there must be a way for the user to send their guess to the server. Here we bind to an action method on the bean. The example exists of 4 classes, the first two of which are qualifiers. First, there is the @Random qualifier, used for injecting a random number:
@Qualifier @Target( { TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) public @interface Random {}
There is also the @MaxNumber qualifier, used for injecting the maximum number that can be injected:
@Qualifier @Target( { TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) public @interface MaxNumber {}
The application-scoped Generator class is responsible for creating the random number, via a producer method. It also exposes the maximum possible number via a producer method:
@ApplicationScoped public class Generator implements Serializable { private java.util.Random random = new java.util.Random(System.currentTimeMillis());
51
private int maxNumber = 100; java.util.Random getRandom() { return random; } @Produces @Random int next() { return getRandom().nextInt(maxNumber); } @Produces @MaxNumber int getMaxNumber() { return maxNumber; } }
The Generator is application scoped, so we don't get a different random each time.
Note
The package declaration and imports have been excluded from these listings. The complete listing is available in the example source code.
The final bean in the application is the session-scoped Game class. This is the primary entry point of the application. It's responsible for setting up or resetting the game, capturing and validating the user's guess and providing feedback to the user with a FacesMessage. We've used the post-construct lifecycle method to initialize the game by retrieving a random number from the @Random Instance<Integer> bean. You'll notice that we've also added the @Named annotation to this class. This annotation is only required when you want to make the bean accessible to a JSF view via EL (i.e., #{game}).
@Named @SessionScoped public class Game implements Serializable { private private private private private int int int int int number; guess; smallest; biggest; remainingGuesses;
@Inject @MaxNumber private int maxNumber; @Inject @Random Instance<Integer> randomNumber; public Game() {} public void check() { if (guess > number) { biggest = guess - 1; } else if (guess < number) { smallest = guess + 1; }
52
else if (guess == number) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!")); } remainingGuesses--; } @PostConstruct public void reset() { this.smallest = 0; this.guess = 0; this.remainingGuesses = 10; this.biggest = maxNumber; this.number = randomNumber.get(); } public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) { if (remainingGuesses <= 0) { FacesMessage message = new FacesMessage("No guesses left!"); context.addMessage(toValidate.getClientId(context), message); ((UIInput) toValidate).setValid(false); return; } int input = (Integer) value; if (input < smallest || input > biggest) { ((UIInput) toValidate).setValid(false); FacesMessage message = new FacesMessage("Invalid guess"); context.addMessage(toValidate.getClientId(context), message); } } public int getNumber() { return number; } public int getGuess() { return guess; } public void setGuess(int guess) { this.guess = guess; } public int getSmallest() { return smallest; } public int getBiggest() { return biggest; } public int getRemainingGuesses() { return remainingGuesses; } }
53
Tip
You must also include the jars for JSF, EL, and the common annotations (jsr250-api.jar), all of which are provided by the Java EE platform (a Java EE application server). Are you starting to appreciate why a Java EE platform is worth using?
Second, we need to explicitly specify the servlet listener in web.xml, again because the container isn't doing this stuff for you. The servlet listener boots Weld and controls it's interaction with requests.
When Weld boots, it places the javax.enterprise.inject.spi.BeanManager, the portable SPI for obtaining bean instances, in the ServletContext under a variable name equal to the fully-qualified interface name. You generally don't need to access this interface, but Weld makes use of it.
Tip
You may want to review the Wicket documentation at http://wicket.apache.org/ before reading this section, if you aren't already familiar with the framework.
Wicket is another environment that relies on the Weld servlet extension. The use of Jetty [http://jetty.mortbay.org] is common in the Wicket community, and is thus chosen here as the runtime container. You've seen already that Jetty is perfectly capable of running CDI applications with Weld add-ons, and this environment is no different.
Note
We'll also be using the Eclipse IDE in these examples. Instructions are provided later for running the example from the command line, but since you'll likely need to do more than just deploy examples, we'll get setup in this full development environment.
54
55
You'll notice after importing, the project has a build error. That's because we need to enable a Maven profile. Rightclick on the project and select Properties, then select the Maven tab in the window that appears. In the form field labeled "Active Maven Profiles (comma separated):", type jetty. That will enable some extra dependencies that allow the project to compile. Additionally, uncheck the box labeled "Skip Maven compile plugin when processing resources (recommended)". That solves an incompatiblity between the m2eclipse plugin and the Maven enforcer plugin that we use for the Weld project. Now, you're ready to develop!
Note
Be sure to uncheck the box "Skip Maven compile plugin when processing resources (recommended)" in the Maven properties screen or else the example might not run in Eclipse because beans.xml will be missing from the classpath! See the MNGECLIPSE-768 [https:// issues.sonatype.org/browse/MNGECLIPSE-768] issue report for details.
If you are not using the m2eclipse plugin, you have to follow different steps to import the project. First, switch into the Wicket numberguess example, then execute the Maven Eclipse plugin with the jetty profile activated, as follows:
Then, from Eclipse, choose File -> Import... -> General -> Existing Projects into Workspace, select the root directory of the numberguess example, and click Finish. This will create a project in your workspace called weld-wicket-
numberguess.
56
7.2.3. Running the example from the command line in JBoss AS or Tomcat
This example can also be deployed from the command line in a (similar to the other examples). Assuming you have set up the local.build.properties file in the examples directory to specify the location of JBoss AS or Tomcat, as previously described, you can run:
to deploy the example to Tomcat. You can then access application at http://localhost:8080/weld-numberguesswicket. Alternatively, you can run the application in place on an embedded Jetty container using the following Maven command:
NumberGuessApplication:
57
This class specifies which page Wicket should treat as our home page, in our case, HomePage.class In HomePage, we see typical Wicket code to set up page elements. The bit that is interesting is the injection of the Game bean:
The Game bean is can then be used, for example, by the code for submitting a guess:
final Component guessButton = new AjaxButton("GuessButton") { protected void onSubmit(AjaxRequestTarget target, Form form) { if (game.check()) { info("Correct!"); setVisible(false); prompt.setVisible(false); guessLabel.setVisible(false); inputGuess.setVisible(false); } else if (game.getRemainingGuesses() == 0) { info("Sorry, the answer was " + game.getNumber()); setVisible(false); guessLabel.setVisible(false); inputGuess.setVisible(false); } else if (game.getNumber() > game.getGuess()) { info("Higher!"); } else if (game.getNumber() < game.getGuess()) { info("Lower"); } target.addComponent(form); } };
Note
All injections may be serialized; actual storage of the bean is managed by JSR-299. Note that Wicket components, like the HomePage and it subcomponents, are not JSR-299 beans. Wicket components allow injection, but they cannot use interceptors, decorators or lifecycle callbacks such as @PostConstruct or methods. The components would need to delegate to actual beans to leverage these features.
The example uses AJAX for processing of button events, and dynamically hides buttons that are no longer relevant, for example when the user has won the game.
58
In order to activate Wicket for this webapp, the Wicket filter is added to web.xml, and our application class is specified in web.xml:
<filter> <filter-name>Wicket Filter</filter-name> <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> <init-param> <param-name>applicationClassName</param-name> <param-value>org.jboss.weld.examples.wicket.NumberGuessApplication</param-value> </init-param> </filter> <filter-mapping> <filter-name>Wicket Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
The servlet listener is still required, as in the Tomcat example, to bootstrap CDI when Jetty starts and to hook CDI into the Jetty servlet request and session lifecycles. However, rather than putting it into the web.xml, it is placed into an override file, src/main/webapp/WEB-INF/jetty-additions-to-web.xml, that is passed to Jetty as an extra descriptor to be appended to the web.xml configuration.
mvn -Drun
Let's have a look at the significant code and configuration files that make up this example. As usual, there is an empty beans.xml file in the root package (src/main/resources/beans.xml), which marks this application as a CDI application. The game's main logic is located in Game.java. Here is the code for that class, highlighting the ways in which this differs from the web application version:
59
@ApplicationScoped public class Game { public static final int MAX_NUM_GUESSES = 10; private Integer number; private int guess = 0; private int smallest = 0; @Inject @MaxNumber private int maxNumber; private int biggest; private int remainingGuesses = MAX_NUM_GUESSES; private boolean validNumberRange = true; @Inject Generator rndGenerator; public Game() { }
... public boolean isValidNumberRange() { return validNumberRange; } public boolean isGameWon() { return guess == number; } public boolean isGameLost() { return guess != number && remainingGuesses <= 0; } public boolean check() { boolean result = false; if (checkNewNumberRangeIsValid()) { if (guess > number) { biggest = guess - 1; } if (guess < number) { smallest = guess + 1;
60
} if (guess == number) { result = true; } remainingGuesses--; } return result; } private boolean checkNewNumberRangeIsValid() { return validNumberRange = ((guess >= smallest) && (guess <= biggest)); } @PostConstruct public void reset() { this.smallest = 0; this.guess = 0; this.remainingGuesses = 10; this.biggest = maxNumber; this.number = rndGenerator.next(); } }
The bean is application scoped rather than session scoped, since an instance of a Swing application typically represents a single 'session'. Notice that the bean is not named, since it doesn't need to be accessed via EL. In Java SE there is no JSF FacesContext to which messages can be added. Instead the Game class provides additional information about the state of the current game including:
If the game has been won or lost If the most recent guess was invalid This allows the Swing UI to query the state of the game, which it does indirectly via a class called
MessageGenerator, in order to determine the appropriate messages to display to the user during the game. Since there is no dedicated validation phase, validation of user input is performed during the check() method.
The reset() method makes a call to the injected rndGenerator in order to get the random number at the start of each game. Note that it can't use Instance.get() like the JSF example does because there will not be any active contexts like there are during a JSF request. The MessageGenerator class depends on the current instance of Game and queries its state in order to determine the appropriate messages to provide as the prompt for the user's next guess and the response to the previous guess. The code for MessageGenerator is as follows:
61
public String getChallengeMessage() { StringBuilder challengeMsg = new StringBuilder("I'm thinking of a number between "); challengeMsg.append(game.getSmallest()); challengeMsg.append(" and "); challengeMsg.append(game.getBiggest()); challengeMsg.append(". Can you guess what it is?"); return challengeMsg.toString(); }
public String getResultMessage() { if (game.isGameWon()) { return "You guessed it! The number was " + game.getNumber(); } else if (game.isGameLost()) { return "You are fail! The number was " + game.getNumber(); } else if (!game.isValidNumberRange()) { return "Invalid number range!"; } else if (game.getRemainingGuesses() == Game.MAX_NUM_GUESSES) { return "What is your first guess?"; } else { String direction = null; if (game.getGuess() < game.getNumber()) { direction = "Higher"; } else { direction = "Lower"; } return direction + "! You have " + game.getRemainingGuesses() + " guesses left."; } } }
The instance of Game for the application is injected here. The Game's state is interrogated to determine the appropriate challenge message ... ... and again to determine whether to congratulate, console or encourage the user to continue. Finally we come to the NumberGuessFrame class which provides the Swing front end to our guessing game.
62
public void start(@Observes ContainerInitialized event) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { initComponents(); setVisible(true); } }); }
private void initComponents() { buttonPanel = new javax.swing.JPanel(); mainMsgPanel = new javax.swing.JPanel(); mainLabel = new javax.swing.JLabel(); messageLabel = new javax.swing.JLabel(); guessText = new javax.swing.JTextField(); ... mainLabel.setText(msgGenerator.getChallengeMessage()); mainMsgPanel.add(mainLabel); messageLabel.setText(msgGenerator.getResultMessage()); mainMsgPanel.add(messageLabel); ... }
private void guessButtonActionPerformed( java.awt.event.ActionEvent evt ) { int guess = Integer.parseInt(guessText.getText()); game.setGuess( guess ); game.check(); refreshUI(); } private void replayBtnActionPerformed(java.awt.event.ActionEvent evt) { game.reset(); refreshUI(); } private void refreshUI() { mainLabel.setText( msgGenerator.getChallengeMessage() ); messageLabel.setText( msgGenerator.getResultMessage() ); guessText.setText( "" );
63
guessesLeftBar.setValue( game.getRemainingGuesses() ); guessText.requestFocus(); } // swing components private javax.swing.JPanel borderPanel; ... private javax.swing.JButton replayBtn; }
The injected instance of the game (logic and state). The injected message generator for UI messages. This application is started in the prescribed Weld SE way, by observing the ContainerInitialized event. This method initializes all of the Swing components. Note the use of the msgGenerator here.
guessButtonActionPerformed is called when the 'Guess' button is clicked, and it does the following:
Gets the guess entered by the user and sets it as the current guess in the Game Calls game.check() to validate and perform one 'turn' of the game Calls refreshUI. If there were validation errors with the input, this will have been captured during
game.check() and as such will be reflected in the messages returned by MessageGenerator and
subsequently presented to the user. If there are no validation errors then the user will be told to guess again (higher or lower) or that the game has ended either in a win (correct guess) or a loss (ran out of guesses).
replayBtnActionPerformed simply calls game.reset() to start a new game and refreshes the
messages in the UI.
Note
Java EE 6, which bundles EJB 3.1, allows you to package EJBs in a war, which will make this structure much simpler! Still, there are other advantages of using an ear.
First, let's take a look at the ear aggregator, which is located in the example's ear directory. Maven automatically generates the application.xml for us from this plugin configuration:
64
This configuration overrides the web context path, resulting in this application URL: http://localhost:8080/weldtranslator.
Tip
If you weren't using Maven to generate these files, you would need META-INF/
application.xml:
<application version="5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd"> <display-name>weld-jsf-translator-ear</display-name> <description>The Weld JSF translator example (ear)</description> <module> <web> <web-uri>weld-translator.war</web-uri> <context-root>/weld-translator</context-root> </web> </module> <module> <ejb>weld-translator.jar</ejb> </module> </application>
Next, lets look at the war, which is located in the example's war directory. Just as in the numberguess example, we have a faces-config.xml for JSF 2.0 and a web.xml (to activate JSF) under WEB-INF, both sourced from
src/main/webapp/WEB-INF.
More interesting is the JSF view used to translate text. Just as in the numberguess example we have a template, which surrounds the form (ommitted here for brevity):
<h:form id="translator"> <table> <tr align="center" style="font-weight: bold"> <td> Your text </td> <td> Translation
65
</td> </tr> <tr> <td> <h:inputTextarea id="text" value="#{translator.text}" required="true" rows="5" cols="80"/> </td> <td> <h:outputText value="#{translator.translatedText}"/> </td> </tr> </table> <div> <h:commandButton id="button" value="Translate" action="#{translator.translate}"/> </div> </h:form>
The user can enter some text in the left-hand textarea, and hit the translate button to see the result to the right. Finally, let's look at the EJB module, which is located in the example's ejb directory. In src/main/resources/
META-INF there is just an empty beans.xml, used to mark the archive as containing beans.
We've saved the most interesting bit to last, the code! The project has two simple beans, SentenceParser and
public class TextTranslator implements Serializable { private SentenceParser sentenceParser; @EJB private Translator translator; @Inject public TextTranslator(SentenceParser sentenceParser) { this.sentenceParser = sentenceParser; } public String translate(String text) { StringBuilder sb = new StringBuilder(); for (String sentence: sentenceParser.parse(text)) { sb.append(translator.translate(sentence)).append(". "); } return sb.toString().trim(); } }
TextTranslator uses the simple bean (really just a plain Java class!) SentenceParser to parse the sentence and then calls on the stateless bean with the local business interface Translator to perform the translation. That's
where the magic happens. Of course, we couldn't develop a full translator, but it's convincing enough to anyone who doesn't understand Latin!
66
@Stateless public class SentenceTranslator implements Translator { public String translate(String sentence) { return "Lorem ipsum dolor sit amet"; } }
Finally, there is UI orientated controller. This is a request scoped, named, stateful session bean, which injects the translator. It collects the text from the user and dispatches it to the translator. The bean also has getters and setters for all the fields on the page.
@Stateful @RequestScoped @Named("translator") public class TranslatorControllerBean implements TranslatorController { @Inject private TextTranslator translator; private String inputText; private String translatedText; public void translate() { translatedText = translator.translate(inputText); } public String getText() { return inputText; } public void setText(String text) { this.inputText = text; } public String getTranslatedText() { return translatedText; } @Remove public void remove() {} }
That concludes our short tour of the Weld starter examples. For more information on Weld, please visit http:// www.seamframework.org/Weld.
67
68
mockPaymentProcessor, SecurityInterceptor or DocumentUpdatedEvent. The annotations are reusable. They help describe common qualities of disparate parts of the system. They help us categorize and understand our code. They help us deal with common concerns in a common way. They make our code more literate and more understandable. CDI stereotypes take this idea a step further. A stereotype models a common role in your application architecture. It encapsulates various properties of the role, including scope, interceptor bindings, qualifiers, etc, into a single reusable package. (Of course, there is also the benefit of tucking some of those annotations away). We're now ready to meet some more advanced features of CDI. Bear in mind that these features exist to make our code both easier to validate and more understandable. Most of the time you don't ever really need to use these features, but if you use them wisely, you'll come to appreciate their power.
Chapter 8.
Producer methods
Producer methods let us overcome certain limitations that arise when a container, instead of the application, is responsible for instantiating objects. They're also the easiest way to integrate objects which are not beans into the CDI environment. According to the spec: A producer method acts as a source of objects to be injected, where: the objects to be injected are not required to be instances of beans, the concrete type of the objects to be injected may vary at runtime or the objects require some custom initialization that is not performed by the bean constructor For example, producer methods let us: expose a JPA entity as a bean, expose any JDK class as a bean, define multiple beans, with different scopes or initialization, for the same implementation class, or vary the implementation of a bean type at runtime. In particular, producer methods let us use runtime polymorphism with CDI. As we've seen, alternative beans are one solution to the problem of deployment-time polymorphism. But once the system is deployed, the CDI implementation is fixed. A producer method has no such limitation:
@SessionScoped public class Preferences implements Serializable { private PaymentStrategyType paymentStrategy; ... @Produces @Preferred public PaymentStrategy getPaymentStrategy() { switch (paymentStrategy) { case CREDIT_CARD: return new CreditCardPaymentStrategy(); case CHECK: return new CheckPaymentStrategy(); case PAYPAL: return new PayPalPaymentStrategy(); default: return null; } } }
This injection point has the same type and qualifier annotations as the producer method, so it resolves to the producer method using the usual CDI injection rules. The producer method will be called by the container to obtain an instance to service this injection point.
71
Now, when the producer method is called, the returned PaymentStrategy will be bound to the session context. The producer method won't be called again in the same session.
Note
A producer method does not inherit the scope of the bean that declares the method. There are two different beans here: the producer method, and the bean which declares it. The scope of the producer method determines how often the method will be called, and the lifecycle of the objects returned by the method. The scope of the bean that declares the producer method determines the lifecycle of the object upon which the producer method is invoked.
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps, CheckPaymentStrategy cps, PayPalPaymentStrategy ppps) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; case PAYPAL: return ppps; default: return null; } }
Wait, what if CreditCardPaymentStrategy is a request-scoped bean? Then the producer method has the effect of "promoting" the current request scoped instance into session scope. This is almost certainly a bug! The request scoped object will be destroyed by the container before the session ends, but the reference to the object will be left "hanging" in the session scope. This error will not be detected by the container, so please take extra care when returning bean instances from producer methods!
72
There's at least three ways we could go about fixing this bug. We could change the scope of the CreditCardPaymentStrategy implementation, but this would affect other clients of that bean. A better option would be to change the scope of the producer method to @Dependent or @RequestScoped. But a more common solution is to use the special @New qualifier annotation.
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps, @New CheckPaymentStrategy cps, @New PayPalPaymentStrategy ppps) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; case PAYPAL: return ppps; default: return null; } }
Then a new dependent instance of CreditCardPaymentStrategy will be created, passed to the producer method, returned by the producer method and finally bound to the session context. The dependent object won't be destroyed until the Preferences object is destroyed, at the end of the session.
Destruction can be performed by a matching disposer method, defined by the same class as the producer method:
The disposer method must have at least one parameter, annotated @Disposes, with the same type and qualifiers as the producer method. The disposer method is called automatically when the context ends (in this case, at the end of the request), and this parameter receives the object produced by the producer method. If the disposer method has additional method parameters, the container will look for a bean that satisfies the type and qualifiers of each parameter and pass it to the method automatically.
73
74
Chapter 9.
Interceptors
Interceptor functionality is defined in the Java Interceptors specification. CDI enhances this functionality with a more sophisticated, semantic, annotation-based approach to binding interceptors to beans. The Interceptors specification defines two kinds of interception points:
business method interception, and lifecycle callback interception. In addition, the EJB specification defines timeout method interception. A business method interceptor applies to invocations of methods of the bean by clients of the bean:
public class TransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
An interceptor class may intercept both lifecycle callbacks and business methods. A timeout method interceptor applies to invocations of EJB timeout methods by the container:
public class TimeoutInterceptor { @AroundTimeout public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
75
Chapter 9. Interceptors
@Transactional @Interceptor public class TransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
@Transactional @Interceptor public class TransactionInterceptor { @Resource UserTransaction transaction; @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
76
Whoah! Why the angle bracket stew? Well, having the XML declaration is actually a good thing. It solves two problems: it enables us to specify a total ordering for all the interceptors in our system, ensuring deterministic behavior, and it lets us enable or disable interceptor classes at deployment time. For example, we could specify that our security interceptor runs before our transaction interceptor.
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <interceptors> <class>org.mycompany.myapp.SecurityInterceptor</class> <class>org.mycompany.myapp.TransactionInterceptor</class> </interceptors> </beans>
Or we could turn them both off in our test environment by simply not mentioning them in beans.xml! Ah, so simple.
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Transactional { boolean requiresNew() default false; }
CDI
will use the value of requiresNew to choose between two TransactionInterceptor and RequiresNewTransactionInterceptor.
different
interceptors,
@Transactional(requiresNew = true) @Interceptor public class RequiresNewTransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
77
Chapter 9. Interceptors
But what if we only have one interceptor and we want the container to ignore the value of requiresNew when binding interceptors? Perhaps this information is only useful for the interceptor implementation. We can use the @Nonbinding annotation:
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Secure { @Nonbinding String[] rolesAllowed() default {}; }
However, in very complex cases, an interceptor itself may specify some combination of interceptor binding types:
Then this interceptor could be bound to the checkout() method using any one of the following combinations:
@Transactional
78
Well, fortunately, CDI works around this missing feature of Java. We may annotate one interceptor binding type with other interceptor binding types (termed a meta-annotation). The interceptor bindings are transitive any bean with the first interceptor binding inherits the interceptor bindings declared as meta-annotations.
Now,
any bean annotated @Action will be bound to both TransactionInterceptor and SecurityInterceptor. (And even TransactionalSecureInterceptor, if it exists.)
However, this approach suffers the following drawbacks: the interceptor implementation is hardcoded in business code, interceptors may not be easily disabled at deployment time, and the interceptor ordering is non-global it is determined by the order in which interceptors are listed at the class level.
79
Chapter 9. Interceptors
80
Chapter 10.
Decorators
Interceptors are a powerful way to capture and separate concerns which are orthogonal to the application (and type system). Any interceptor is able to intercept invocations of any Java type. This makes them perfect for solving technical concerns such as transaction management, security and call logging. However, by nature, interceptors are unaware of the actual semantics of the events they intercept. Thus, interceptors aren't an appropriate tool for separating business-related concerns. The reverse is true of decorators. A decorator intercepts invocations only for a certain Java interface, and is therefore aware of all the semantics attached to that interface. Since decorators directly implement operations with business semantics, it makes them the perfect tool for modeling some kinds of business concerns. It also means that a decorator doesn't have the generality of an interceptor. Decorators aren't able to solve technical concerns that cut across many disparate types. Interceptors and decorators, though similar in many ways, are complementary. Let's look at some cases where decorators fit the bill. Suppose we have an interface that represents accounts:
public interface Account { public BigDecimal getBalance(); public User getOwner(); public void withdraw(BigDecimal amount); public void deposit(BigDecimal amount); }
Several different beans in our system implement the Account interface. However, we have a common legal requirement that; for any kind of account, large transactions must be recorded by the system in a special log. This is a perfect job for a decorator. A decorator is a bean (possibly even an abstract class) that implements the type it decorates and is annotated
@Decorator.
The decorator implements the methods of the decorated type that it wants to intercept.
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; @PersistenceContext EntityManager em; public void withdraw(BigDecimal amount) { ... }
81
Unlike other beans, a decorator may be an abstract class. Therefore, if there's nothing special the decorator needs to do for a particular method of the decorated interface, you don't need to implement that method. Interceptors for a method are called before decorators that apply to the method.
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; ... }
A decorator is bound to any bean which: has the type of the delegate injection point as a bean type, and has all qualifiers that are declared at the delegate injection point. This delegate injection point specifies that the decorator is bound to all beans that implement Account:
A delegate injection point may specify any number of qualifier annotations. The decorator will only be bound to beans with the same qualifiers.
The
decorator
may
invoke
the
delegate
object,
which
has
much
the
same
effect
as
calling
InvocationContext.proceed() from an interceptor. The main difference is that the decorator can invoke
any business method on the delegate object.
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; @PersistenceContext EntityManager em;
82
Enabling decorators
public void withdraw(BigDecimal amount) { account.withdraw(amount); if ( amount.compareTo(LARGE_AMOUNT)>0 ) { em.persist( new LoggedWithdrawl(amount) ); } } public void deposit(BigDecimal amount); account.deposit(amount); if ( amount.compareTo(LARGE_AMOUNT)>0 ) { em.persist( new LoggedDeposit(amount) ); } } }
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <decorators> <class>org.mycompany.myapp.LargeTransactionDecorator</class> </decorators> </beans>
This declaration serves the same purpose for decorators that the <interceptors> declaration serves for interceptors:
it enables us to specify a total ordering for all decorators in our system, ensuring deterministic behavior, and it lets us enable or disable decorator classes at deployment time.
83
84
Chapter 11.
Events
Dependency injection enables loose-coupling by allowing the implementation of the injected bean type to vary, either a deployment time or runtime. Events go one step further, allowing beans to interact with no compile time dependency at all. Event producers raise events that are delivered to event observers by the container. This basic schema might sound like the familiar observer/observable pattern, but there are a couple of twists:
not only are event producers decoupled from observers; observers are completely decoupled from producers, observers can specify a combination of "selectors" to narrow the set of event notifications they will receive, and observers can be notified immediately, or can specify that delivery of the event should be delayed until the end of the current transaction. The CDI event notification facility uses more or less the same typesafe approach that we've already seen with the dependency injection service.
The annotated parameter is called the event parameter. The type of the event parameter is the observed event type, in this case Document. The event parameter may also specify qualifiers.
An observer method need not specify any event qualifiersin this case it is interested in all events of a particular type. If it does specify qualifiers, it's only interested in events which have those qualifiers. The observer method may have additional parameters, which are injection points:
85
A producer raises events by calling the fire() method of the Event interface, passing the event object:
documentEvent.fire(document);
has an event parameter to which the event object (the Document) is assignable, and specifies no qualifiers. The container simply calls all the observer methods, passing the event object as the value of the event parameter. If any observer method throws an exception, the container stops calling observer methods, and the exception is rethrown by the fire() method. Qualifiers can be applied to an event in one of two ways:
by annotating the Event injection point, or by passing qualifiers to the select() of Event. Specifying the qualifiers at the injection point is far simpler:
Then, every event fired via this instance of Event has the event qualifier @Updated. The event is delivered to every observer method that:
has an event parameter to which the event object is assignable, and does not have any event qualifier except for the event qualifiers that match those specified at the Event injection point. The downside of annotating the injection point is that we can't specify the qualifier dynamically. CDI lets us obtain a qualifier instance by subclassing the helper class AnnotationLiteral. That way, we can pass the qualifier to the select() method of Event.
86
documentEvent.select(new AnnotationLiteral<Updated>(){}).fire(document);
Events can have multiple event qualifiers, assembled using any combination of annotations at the Event injection point and qualifier instances passed to the select() method.
A bean with scope @Dependent cannot be a conditional observer, since it would never be called!
The member value is used to narrow the messages delivered to the observer:
Event qualifier type members may be specified statically by the event producer, via annotations at the event notifier injection point:
Alternatively, the value of the event qualifier type member may be determined dynamically by the event producer. We start by writing an abstract subclass of AnnotationLiteral:
87
When this event occurs, all of the following observer methods will be notified:
AFTER_SUCCESS observers are called during the after completion phase of the transaction, but only if the
transaction completes successfully
88
Transactional observers
AFTER_FAILURE observers are called during the after completion phase of the transaction, but only if the transaction fails to complete successfully AFTER_COMPLETION observers are called during the after completion phase of the transaction BEFORE_COMPLETION observers are called during the before completion phase of the transaction Transactional observers are very important in a stateful object model because state is often held for longer than a single atomic transaction. Imagine that we have cached a JPA query result set in the application scope:
@ApplicationScoped @Singleton public class Catalog { @PersistenceContext EntityManager em; List<Product> products; @Produces @Catalog List<Product> getCatalog() { if (products==null) { products = em.createQuery("select p from Product p where p.deleted = false") .getResultList(); } return products; } }
From time to time, a Product is created or deleted. When this occurs, we need to refresh the Product catalog. But we should wait until after the transaction completes successfully before performing this refresh! The bean that creates and deletes Products could raise events, for example:
@Stateless public class ProductManager { @PersistenceContext EntityManager em; @Inject @Any Event<Product> productEvent; public void delete(Product product) { em.delete(product); productEvent.select(new AnnotationLiteral<Deleted>(){}).fire(product); } public void persist(Product product) { em.persist(product); productEvent.select(new AnnotationLiteral<Created>(){}).fire(product); } ... }
And now Catalog can observe the events after successful completion of the transaction:
89
@ApplicationScoped @Singleton public class Catalog { ... void addProduct(@Observes(during = AFTER_SUCCESS) @Created Product product) { products.add(product); } void addProduct(@Observes(during = AFTER_SUCCESS) @Deleted Product product) { products.remove(product); } }
90
Chapter 12.
Stereotypes
The CDI specification defines a stereotype as follows: In many systems, use of architectural patterns produces a set of recurring bean roles. A stereotype allows a framework developer to identify such a role and declare some common metadata for beans with that role in a central place. A stereotype encapsulates any combination of:
a default scope, and a set of interceptor bindings. A stereotype may also specify that:
all beans with the stereotype have defaulted bean EL names, or that all beans with the stereotype are alternatives. A bean may declare zero, one or multiple stereotypes. Stereotype annotations may be applied to a bean class or producer method or field. A stereotype is an annotation, annotated @Stereotype, that packages several other annotations. For instance, the following stereotype identifies action classes in some MVC framework:
Of course, we need to apply some other annotations to our stereotype or else it wouldn't be adding much value.
91
Naturally, overriding a single default isn't much use. But remember, stereotypes can define more than just the default scope.
This helps us get technical concerns, like transactions and security, even further away from the business code!
@RequestScoped @Transactional(requiresNew=true) @Secure @Named @Stereotype @Retention(RUNTIME) @Target(TYPE) public @interface Action {}
Now, the LoginAction bean will have the defaulted name loginAction.
@Alternative @Stereotype
92
Stereotype stacking
We can apply an alternative stereotype to a whole set of beans, and activate them all with one line of code in beans.xml.
Instead of using JSF managed beans, just annotate a bean @Model, and use it directly in your JSF view!
93
94
Chapter 13.
The second bean specializes the first bean in certain deployment scenarios. In these deployments, the second bean completely replaces the first, fulfilling the same role in the system. The second bean is simply reusing the Java implementation, and otherwise bears no relation to the first bean. The first bean may not even have been designed for use as a contextual object. The second case is the default assumed by CDI. It's possible to have two beans in the system with the same part bean type (interface or parent class). As you've learned, you select between the two implementations using qualifiers. The first case is the exception, and also requires more care. In any given deployment, only one bean can fulfill a given role at a time. That means one bean needs to be enabled and the other disabled. There are a two modifiers involved:
@Alternative and @Specializes. We'll start by looking at alternatives and then show the guarantees that
specialization adds.
But in our staging environment, we don't really want to submit payments to the external system, so we override that implementation of PaymentProcessor with a different bean:
or
95
We've already seen how we can enable this alternative by listing its class in the beans.xml descriptor. But suppose we have many alternatives in the staging environment. It would be much more convenient to be able to enable them all at once. So let's make @Staging an @Alternative stereotype and annotate the staging beans with this stereotype instead. You'll see how this level of indirection pays off. First, we create the stereotype:
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <stereotype>org.mycompany.myapp.Staging</stereotype> </alternatives> </beans>
Now, no matter how many staging beans we have, they will all be enabled at once.
96
Using specialization
So we haven't completely replaced the default implementation in this deployment of the system. The only way one bean can completely override a second bean at all injection points is if it implements all the bean types and declares all the qualifiers of the second bean. However, if the second bean declares a producer method or observer method, then even this is not enough to ensure that the second bean is never called! We need something extra. CDI provides a special feature, called specialization, that helps the developer avoid these traps. Specialization is a way of informing the system of your intent to completely replace and disable an implementation of a bean.
directly extend the bean class of the second bean, or directly override the producer method, in the case that the second bean is a producer method, and then explicitly declare that it specializes the second bean:
When an enabled bean specializes another bean, the other bean is never instantiated or called by the container. Even if the other bean defines a producer or observer method, the method will never be called. So why does specialization work, and what does it have to do with inheritance? Since we're informing the container that our alternative bean is meant to stand in as a replacement for the default implementation, the alternative implementation automatically inherits all qualifiers of the default implementation. Thus, in our example, MockCreditCardPaymentProcessor inherits the qualifiers @Default and @CreditCard. Furthermore, if the default implementation declares a bean EL name using @Named, the name is inherited by the specialized alternative bean.
97
98
Chapter 14.
@Produces @PersistenceUnit(unitName="CustomerDatabase")
99
The field may be static (but not final). A resource declaration really contains two pieces of information: the JNDI name, EJB link, persistence unit name, or other metadata needed to obtain a reference to the resource from the component environment, and the type and qualifiers that we will use to inject the reference into our beans.
Tip
It might feel strange to be declaring resources in Java code. Isn't this stuff that might be deployment-specific? Certainly, and that's why it makes sense to declare your resources in a class annotated @Alternative.
The bean type and qualifiers of the resource are determined by the producer field declaration. It might seem like a pain to have to write these extra producer field declarations, just to gain an additional level of indirection. You could just as well use component environment injection directly, right? But remember that you're going to be using resources like the EntityManager in several different beans. Isn't it nicer and more typesafe to write
100
instead of
@PersistenceContext(unitName="CustomerDatabase") EntityManager
101
102
Chapter 15.
Java EE integration
CDI is fully integrated into the Java EE environment. Beans have access to Java EE resources and JPA persistence contexts. They may be used in Unified EL expressions in JSF and JSP pages. They may even be injected into other platform components, such as servlets and message-driven Beans, which are not beans themselves.
Note
The CDI specification does not require the servlet context objects, HttpServletRequest,
FacesContext.getCurrentInstance().
Tip
Oh, you really want to inject the FacesContext? Alright then, try this producer method:
105
@SessionScoped public class Login implements Serializable { @Inject Credentials credentials; @PersistenceContext EntityManager userDatabase; ... }
The Java EE @PostConstruct and @PreDestroy callbacks are also supported for all managed beans. The
public class Login extends HttpServlet { @Inject Credentials credentials; @Inject Login login; @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { credentials.setUsername(request.getParameter("username")): credentials.setPassword(request.getParameter("password")): login.login(); if ( login.isLoggedIn() ) { response.sendRedirect("/home.jsp"); } else { response.sendRedirect("/loginError.jsp"); } } }
Since instances of servlets are shared across all incoming threads, the bean client proxy takes care of routing method invocations from the servlet to the correct instances of Credentials and Login for the current request and HTTP session.
106
JMS endpoints
@Transactional @MessageDriven public class ProcessOrder implements MessageListener { @Inject Inventory inventory; @PersistenceContext EntityManager em; public void onMessage(Message message) { ... } }
Please note that there is no session or conversation context available when a message is delivered to a messagedriven bean. Only @RequestScoped and @ApplicationScoped beans are available. But how about beans which send JMS messages?
TopicSession and TopicPublisher. Each of these objects has its own lifecycle and threading model that
we need to worry about. You can use producer fields and methods to prepare all of these resources for injection into a bean:
public class OrderResources { @Resource(name="jms/ConnectionFactory") private ConnectionFactory connectionFactory; @Resource(name="jms/OrderQueue") private Queue orderQueue; @Produces @OrderConnection public Connection createOrderConnection() throws JMSException { return connectionFactory.createConnection(); } public void closeOrderConnection(@Disposes @OrderConnection Connection connection) throws JMSException { connection.close(); } @Produces @OrderSession public Session createOrderSession(@OrderConnection Connection connection) throws JMSException { return connection.createSession(true, Session.AUTO_ACKNOWLEDGE); } public void closeOrderSession(@Disposes @OrderSession Session session) throws JMSException { session.close(); } @Produces @OrderMessageProducer public MessageProducer createOrderMessageProducer(@OrderSession Session session)
107
throws JMSException { return session.createProducer(orderQueue); } public void closeOrderMessageProducer(@Disposes @OrderMessageProducer MessageProducer producer) throws JMSException { producer.close(); } }
In this example, we can just inject the prepared MessageProducer, Connection or QueueSession:
@Inject Order order; @Inject @OrderMessageProducer MessageProducer producer; @Inject @OrderSession QueueSession orderSession; public void sendMessage() { MapMessage msg = orderSession.createMapMessage(); msg.setLong("orderId", order.getId()); ... producer.send(msg); }
The lifecycle of the injected JMS objects is completely controlled by the container.
108
Chapter 16.
Portable extensions
CDI is intended to be a foundation for frameworks, extensions and integration with other technologies. Therefore, CDI exposes a set of SPIs for the use of developers of portable extensions to CDI. For example, the following kinds of extensions were envisaged by the designers of CDI:
integration with Business Process Management engines, integration with third-party frameworks such as Spring, Seam, GWT or Wicket, and new technology based upon the CDI programming model. More formally, according to the spec: A portable extension may integrate with the container by:
Providing its own beans, interceptors and decorators to the container Injecting dependencies into its own objects using the dependency injection service Providing a context implementation for a custom scope Augmenting or overriding the annotation-based metadata with metadata from some other source
Next, we need to register our extension as a service provider by creating a file named META-INF/services/
org.mydomain.extension.MyExtension
An extension is not a bean, exactly, since it is instantiated by the container during the initialization process, before any beans or contexts exist. However, it can be injected into other beans once the initialization process is complete.
And, like beans, extensions can have observer methods. Usually, the observer methods observe container lifecycle events.
109
BeforeBeanDiscovery ProcessAnnotatedType ProcessInjectionTarget and ProcessProducer ProcessBean and ProcessObserverMethod AfterBeanDiscovery AfterDeploymentValidation Extensions may observe these events:
class MyExtension implements Extension { void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { Logger.global.debug("beginning the scanning process"); } <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) { Logger.global.debug("scanning type: " + pat.getAnnotatedType().getJavaClass().getName()); } void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { Logger.global.debug("finished the scanning process"); } }
In fact, the extension can do a lot more than just observe. The extension is permitted to modify the container's metamodel and more. Here's a very simple example:
class MyExtension implements Extension { <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) { //tell the container to ignore the type if it is annotated @Ignore if ( pat.getAnnotatedType().isAnnotionPresent(Ignore.class) ) pat.veto(); } }
110
public interface BeanManager { public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx); public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx); public <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual); public Set<Bean<?>> getBeans(Type beanType, Annotation... qualifiers); public Set<Bean<?>> getBeans(String name); public Bean<?> getPassivationCapableBean(String id); public public public public public public public public public public public public public public public public public public } <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans); void validate(InjectionPoint injectionPoint); void fireEvent(Object event, Annotation... qualifiers); <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, Annotation... qualifiers); List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation... qualifiers); List<Interceptor<?>> resolveInterceptors(InterceptionType type, Annotation... interceptorBindings); boolean isScope(Class<? extends Annotation> annotationType); boolean isNormalScope(Class<? extends Annotation> annotationType); boolean isPassivatingScope(Class<? extends Annotation> annotationType); boolean isQualifier(Class<? extends Annotation> annotationType); boolean isInterceptorBinding(Class<? extends Annotation> annotationType); boolean isStereotype(Class<? extends Annotation> annotationType); Set<Annotation> getInterceptorBindingDefinition(Class<? extends Annotation> bindingType); Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype); Context getContext(Class<? extends Annotation> scopeType); ELResolver getELResolver(); ExpressionFactory wrapExpressionFactory(ExpressionFactory expressionFactory); <T> AnnotatedType<T> createAnnotatedType(Class<T> type);
Any bean or other Java EE component which supports injection can obtain an instance of BeanManager via injection:
Java EE components may obtain an instance of BeanManager from JNDI by looking up the name java:comp/ BeanManager. Any operation of BeanManager may be called at any time during the execution of the application. Let's study some of the interfaces exposed by the BeanManager.
111
Tip
We recommend that frameworks let CDI take over the job of actually instantiating the frameworkcontrolled objects. That way, the framework-controlled objects can take advantage of constructor injection. However, if the framework requires use of a constructor with a special signature, the framework will need to instatiate the object itself, and so only method and field injection will be supported.
//get the BeanManager from JNDI BeanManager beanManager = (BeanManager) new InitialContext().lookup("java:comp/BeanManager"); //CDI uses an AnnotatedType object to read the annotations of a class AnnotatedType<SomeFrameworkComponent> type = beanManager.createAnnotatedType(SomeFrameworkComponent.class); //The extension uses an InjectionTarget to delegate instantiation, dependency injection //and lifecycle callbacks to the CDI container InjectionTarget<SomeFrameworkComponent> it = beanManager.createInjectionTarget(type); //each instance needs its own CDI CreationalContext CreationalContext ctx = beanManager.createCreationalContext(null); //instantiate the framework component and inject its dependencies SomeFrameworkComponent instance = it.produce(ctx); //call the constructor it.inject(instance, ctx); //call initializer methods and perform field injection it.postConstruct(instance); //call the @PostConstruct method ... //destroy the framework component instance and clean up dependent objects it.preDestroy(instance); //call the @PreDestroy method it.dispose(instance); //it is now safe to discard the instance ctx.release(); //clean up dependent objects
public interface Bean<T> extends Contextual<T> { public Set<Type> getTypes(); public Set<Annotation> getQualifiers(); public Class<? extends Annotation> getScope(); public String getName(); public Set<Class<? extends Annotation>> getStereotypes(); public Class<?> getBeanClass(); public boolean isAlternative(); public boolean isNullable(); public Set<InjectionPoint> getInjectionPoints();
112
Registering a Bean
There's an easy way to find out what beans exist in the application:
The Bean interface makes it possible for a portable extension to provide support for new kinds of beans, beyond those defined by the CDI specification. For example, we could use the Bean interface to allow objects managed by another framework to be injected into beans.
public class SecurityManagerExtension implements Extension { void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { //use this to read annotations of the class AnnotatedType<SecurityManager> at = bm.createAnnotatedType(SecurityManager.class); //use this to instantiate the class and inject dependencies final InjectionTarget<SecurityManager> it = bm.createInjectionTarget(at); abd.addBean( new Bean<SecurityManager>() { @Override public Class<?> getBeanClass() { return SecurityManager.class; } @Override public Set<InjectionPoint> getInjectionPoints() { return it.getInjectionPoints(); } @Override public String getName() { return "securityManager"; } @Override public Set<Annotation> getQualifiers() { Set<Annotation> qualifiers = new HashSet<Annotation>(); qualifiers.add( new AnnotationLiteral<Default>() {} ); qualifiers.add( new AnnotationLiteral<Any>() {} ); return qualifiers; }
113
@Override public Class<? extends Annotation> getScope() { return SessionScoped.class; } @Override public Set<Class<? extends Annotation>> getStereotypes() { return Collections.emptySet(); } @Override public Set<Type> getTypes() { Set<Type> types = new HashSet<Type>(); types.add(SecurityManager.class); types.add(Object.class); return types; } @Override public boolean isAlternative() { return false; } @Override public boolean isNullable() { return false; } @Override public SecurityManager create(CreationalContext<SecurityManager> ctx) { SecurityManager instance = it.produce(ctx); it.inject(instance, ctx); it.postConstruct(instance); return instance; } @Override public void destroy(SecurityManager instance, CreationalContext<SecurityManager> ctx) { it.preDestroy(instance); it.dispose(instance); ctx.release(); } } ); } }
But a portable extension can also mess with beans that are discovered automatically by the container.
114
Wrapping an AnnotatedType
Let's start with an example of an extension that provides support for the use of @Named at the package level. The package-level name is used to qualify the EL names of all beans defined in that package. The portable extension uses the ProcessAnnotatedType event to wrap the AnnotatedType object and override the value() of the @Named annotation.
public class QualifiedNameExtension implements Extension { <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> pat) { //wrap this to override the annotations of the class final AnnotatedType<X> at = pat.getAnnotatedType(); AnnotatedType<X> wrapped = new AnnotatedType<X>() { @Override public Set<AnnotatedConstructor<X>> getConstructors() { return at.getConstructors(); } @Override public Set<AnnotatedField<? super X>> getFields() { return at.getFields(); } @Override public Class<X> getJavaClass() { return at.getJavaClass(); } @Override public Set<AnnotatedMethod<? super X>> getMethods() { return at.getMethods(); } @Override public <T extends Annotation> T getAnnotation(final Class<T> annType) { if ( Named.class.equals(annType) ) { class NamedLiteral extends AnnotationLiteral<Named> implements Named { @Override public String value() { Package pkg = at.getClass().getPackage(); String unqualifiedName = at.getAnnotation(Named.class).value(); final String qualifiedName; if ( pkg.isAnnotationPresent(Named.class) ) { qualifiedName = pkg.getAnnotation(Named.class).value() + '.' + unqualifiedName; } else { qualifiedName = unqualifiedName; } return qualifiedName; } } return (T) new NamedLiteral(); }
115
else { return at.getAnnotation(annType); } } @Override public Set<Annotation> getAnnotations() { return at.getAnnotations(); } @Override public Type getBaseType() { return at.getBaseType(); } @Override public Set<Type> getTypeClosure() { return at.getTypeClosure(); } @Override public boolean isAnnotationPresent(Class<? extends Annotation> annType) { return at.isAnnotationPresent(annType); } }; pat.setAnnotatedType(wrapped); } }
Here's a second example, which adds the @Alternative annotation to any class which implements a certain
Service interface.
class ServiceAlternativeExtension implements Extension { <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) { final AnnotatedType<T> type = pat.getAnnotatedType(); if ( Service.class.isAssignableFrom( type.getJavaClass() ) ) { //if the class implements Service, make it an @Alternative AnnotatedType<T> wrapped = new AnnotatedType<T>() { @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { return annotationType.equals(Alternative.class) ? true : type.isAnnotationPresent(annotationType); } //remaining methods of AnnotatedType ... }
116
Wrapping an InjectionTarget
pat.setAnnotatedType(wrapped); } } }
The AnnotatedType is not the only thing that can be wrapped by an extension.
org.mydomain.blog.Blogger go in a resource named org/mydomain/blog/Blogger.properties, and the name of a property must match the name of the field to be configured. So Blogger.properties could
contain:
firstName=Gavin lastName=King
The portable extension works by wrapping the containers InjectionTarget and setting field values from the
inject() method.
public class ConfigExtension implements Extension { <X> void processInjectionTarget(@Observes ProcessInjectionTarget<X> pit) { //wrap this to intercept the component lifecycle final InjectionTarget<X> it = pit.getInjectionTarget(); final Map<Field, Object> configuredValues = new HashMap<Field, Object>(); //use this to read annotations of the class and its members AnnotatedType<X> at = pit.getAnnotatedType(); //read the properties file String propsFileName = at.getClass().getSimpleName() + ".properties"; InputStream stream = at.getJavaClass().getResourceAsStream(propsFileName); if (stream!=null) { try { Properties props = new Properties(); props.load(stream); for (Map.Entry<Object, Object> property : props.entrySet()) { String fieldName = property.getKey().toString(); Object value = property.getValue(); try { Field field = at.getJavaClass().getField(fieldName);
117
field.setAccessible(true); if ( field.getType().isAssignableFrom( value.getClass() ) ) { configuredValues.put(field, value); } else { //TODO: do type conversion automatically pit.addDefinitionError( new InjectionException( "field is not of type String: " + field ) ); } } catch (NoSuchFieldException nsfe) { pit.addDefinitionError(nsfe); } finally { stream.close(); } } } catch (IOException ioe) { pit.addDefinitionError(ioe); } } InjectionTarget<X> wrapped = new InjectionTarget<X>() { @Override public void inject(X instance, CreationalContext<X> ctx) { it.inject(instance, ctx); //set the values onto the new instance of the component for (Map.Entry<Field, Object> configuredValue: configuredValues.entrySet()) { try { configuredValue.getKey().set(instance, configuredValue.getValue()); } catch (Exception e) { throw new InjectionException(e); } } } @Override public void postConstruct(X instance) { it.postConstruct(instance); } @Override public void preDestroy(X instance) { it.dispose(instance); } @Override public void dispose(X instance) { it.dispose(instance); } @Override public Set<InjectionPoint> getInjectionPoints() { return it.getInjectionPoints(); }
118
There's a lot more to the portable extension SPI than what we've discussed here. Check out the CDI spec or Javadoc for more information. For now, we'll just mention one more extension point.
public interface Context { public Class<? extends Annotation> getScope(); public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext); public <T> T get(Contextual<T> contextual); boolean isActive(); }
For example, we might implement Context to add a business process scope to CDI, or to add support for the conversation scope to an application that uses Wicket.
119
120
Chapter 17.
Next steps
Because CDI is so new, there's not yet a lot of information available online. That will change over time. Regardless, the CDI specification remains the authority for information on CDI. The spec is less than 100 pages and is quite readable (don't worry, it's not like your Blu-ray player manual). Of course, it covers many details we've skipped over here. The spec is available on the JSR-299 page [http://jcp.org/en/jsr/detail?id=299] at the JCP website. The CDI reference implementation, Weld, is being developed at the Seam project [http://seamframework.org/Weld]. The RI development team and the CDI spec lead blog at in.relation.to [http://in.relation.to]. This guide was originally based on a series of blog entries published there while the specification was being developed. It's probably the best source of information about the future of CDI, Weld and Seam. We encourage you to follow the weld-dev [https://lists.jboss.org/mailman/listinfo/weld-dev] mailing list and to get involved in development [http://seamframework.org/Weld/Development]. If you are reading this guide, you likely have something to offer. We are eager to find volunteers to help revise, proofread or translate this guide. The first step is getting the source of this guide checked out. To build against the trunk (latest source), follow these steps:
Edit the pom.xml file in the root of the checkout and remove the "-SNAPSHOT" from the version element (so you don't have to build other Weld modules). Build using Maven 2
$> mvn
Note
If you experience an out of memory error, try setting this environment variable: MAVEN_OPTS=-
Xmx1024m
The PDF version of the reference guide will appear the current directory. You can find the HTML version in target/docbook/publish/en-US/html. We look forward to your participation!
121
122
Chapter 18.
local.build.properties in the examples directory of the Weld distribution and assign the path of your JBoss AS installation to the property key jboss.home, as follows:
jboss.home=/path/to/jboss-as-5.x
Now we can install the Weld deployer from the jboss-as directory of the Weld distribution:
Note
A new deployer, weld.deployer is added to JBoss AS. This adds supports for JSR-299 deployments to JBoss AS, and allows Weld to query the EJB 3 container and discover which EJBs are installed in your application. It also performs an upgrade of the Javassist library, if necessary.
18.2. GlassFish
Weld is also built into GlassFish from V3 onwards. Since GlassFish V3 is the Java EE 6 reference implementation, it must support all features of CDI. What better way for GlassFish to support these features than to use Weld, the JSR-299 reference implementation? Just package up your CDI application and deploy.
125
Note
There is a major limitation to using a servlet container. Weld doesn't support deploying session beans, injection using @EJB or @PersistenceContext, or using transactional events in servlet containers. For enterprise features such as these, you should really be looking at a Java EE application server.
Weld should be used as a web application library in a servlet container. You should place weld-servlet.jar in WEB-INF/lib in the web root. weld-servlet.jar is an "uber-jar", meaning it bundles all the bits of Weld and CDI required for running in a servlet container, provided for your convenience. Alternatively, you could use its component jars:
jsr299-api.jar weld-api.jar weld-spi.jar weld-core.jar weld-logging.jar weld-servlet-int.jar javassist.jar dom4j.jar google-collections.jar You also need to explicitly specify the servlet listener (used to boot Weld, and control its interaction with requests) in WEB-INF/web.xml in the web root:
18.3.1. Tomcat
Tomcat has a read-only JNDI, so Weld can't automatically bind the BeanManager extension SPI. To bind the BeanManager into JNDI, you should populate META-INF/context.xml in the web root with the following contents:
and make it available to your deployment by adding this to the bottom of web.xml:
126
Jetty
Tomcat only allows you to bind entries to java:comp/env, so the BeanManager will be available at java:comp/
env/BeanManager
Weld also supports Servlet injection in Tomcat. To enable this, place the weld-tomcat-support.jar in
<Listener className="org.jboss.weld.environment.tomcat.WeldLifecycleListener"/>
18.3.2. Jetty
Like Tomcat, Jetty has a read-only JNDI, so Weld can't automatically bind the Manager. To bind the Manager to JNDI, you should populate WEB-INF/jetty-env.xml with the following contents:
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> <Configure id="webAppCtx" class="org.mortbay.jetty.webapp.WebAppContext"> <New id="BeanManager" class="org.mortbay.jetty.plus.naming.Resource"> <Arg><Ref id="webAppCtx"/></Arg> <Arg>BeanManager</Arg> <Arg> <New class="javax.naming.Reference"> <Arg>javax.enterprise.inject.spi.BeanManager</Arg> <Arg>org.jboss.weld.resources.ManagerObjectFactory</Arg> <Arg/> </New> </Arg> </New> </Configure>
Notice that Jetty doesn't not have built-in support for an javax.naming.spi.ObjectFactory like Tomcat, so it's necessary to manually create the javax.naming.Reference to wrap around it. Jetty only allows you to bind entries to java:comp/env, so the BeanManager will be available at java:comp/
env/BeanManager
Weld does not currently support Servlet injection in Jetty.
18.4. Java SE
In addition to improved integration of the Enterprise Java stack, the "Contexts and Dependency Injection for the Java EE platform" specification also defines a state of the art typesafe, stateful dependency injection framework, which can prove useful in a wide range of application types. To help developers take advantage of this, Weld provides a simple means for being executed in the Java Standard Edition (SE) environment independently of any Java EE APIs.
127
When executing in the SE environment the following features of Weld are available: Managed beans with @PostConstruct and @PreDestroy lifecycle callbacks Dependency injection with qualifiers and alternatives @Application, @Dependent and @Singleton scopes Interceptors and decorators Stereotypes Events Portable extension support EJB beans are not supported.
Note
The command line parameters do not become available for injection until the
ContainerInitialized event is fired. If you need access to the parameters during initialization you can do so via the public static String[] getParameters() method in StartMain.
@Singleton public class HelloWorld { public void printHello(@Observes ContainerInitialized event, @Parameters List<String> parameters) { System.out.println("Hello " + parameters.get(0)); } }
128
Bootstrapping CDI SE
public class Weld { /** Boots Weld and creates and returns a WeldContainer instance, through which * beans and events can be accesed. */ public WeldContainer initialize() {...} /** Convenience method for shutting down the container. */ public void shutdown() {...} }
public class WeldContainer { /** Provides access to all beans within the application. */ public Instance<Object> instance() {...} /** Provides access to all events within the application. */ public Event<Object> event() {...} /** Provides direct access to the BeanManager. */ public BeanManager getBeanManager() {...} }
Here's an example application main method which uses this API to initialize a bean of type MyApplicationBean.
public static void main(String[] args) { WeldContainer weld = new Weld().initialize(); weld.instance().select(MyApplicationBean.class).get(); weld.shutdown();
129
Alternatively the application could be started by firing a custom event which would then be observed by another simple bean. The following example fires MyEvent on startup.
public static void main(String[] args) { WeldContainer weld = new Weld().initialize(); weld.event().select(MyEvent.class).fire( new MyEvent() ); weld.shutdown(); }
Note
It is not necessary to use @ThreadScoped in all multithreaded applications. The thread context is not intended as a replacement for defining your own application-specific contexts. It is generally only useful in situtations where you would otherwise have used ThreadLocal directly, which are typically rare.
130
Chapter 19.
import org.slf4j.Logger; import javax.inject.Inject; public class Checkout { private @Inject Logger log; public void invoiceItems() { ShoppingCart cart; ... log.debug("Items invoiced for {}", cart); } }
The example shows how objects can be interpolated into a message. If you use this approach, you do not need to surround a call to the logger with a condition like if ( log.isDebugEnabled() ) to avoid string concatenation.
Note
You can add Weld logging to your project by including weld-logger.jar, sl4j-api.jar and sl4j-jdk14.jar to your project. Alternatively, express a dependency on the org.jboss.weld:weld-logger Maven artifact. If you are using Weld as your JSR-299 implementation, there's no need to include sl4j as it's already included (and used internally).
131
132
Chapter 20.
weld-wicket extension module, which naturally must be on the classpath of the Wicket application.
This section describes some of the utilities provided by the Wicket extension module to support the CDI integration.
WebApplication
up the Wicket
subclass; Weld provides, for your CDI integration. You should subclass
org.jboss.weld.wicket.WeldApplication.
Note
If you would prefer not to subclass WeldApplication, you can manually add a (small!) number of overrides and listeners to your own WebApplication subclass. The JavaDocs of WeldApplicationdetail this.
For example:
public class SampleApplication extends WeldApplication { @Override public Class getHomePage() { return HomePage.class; } }
Setting up the conversation context at the beginning of a Wicket request, and tearing it down afterwards Storing the id of any long-running conversation in Wicket's metadata when the page response is complete Activating the correct long-running conversation based upon which page is being accessed Propagating the conversation context for any long-running conversation to new pages
133
private @Inject Conversation conversation; ... // begin a conversation conversation.begin(); ... // end a conversation conversation.end();
134
Enterprise Services
If you just want to use managed beans, and not take advantage of enterprise services (EE resource injection, CDI injection into EE component classes, transactional events, support for CDI services in EJBs) and non-flat deployments, then the generic servlet support provided by the "Weld: Servlets" extension will be sufficient, and will work in any container supporting the Servlet API.
All SPIs and APIs described have extensive JavaDoc, which spell out the detailed contract between the container and Weld.
135
bean deployment. These beans may, or may not, be in an existing BDA. For this reason, Weld will call Deployment.loadBeanDeploymentArchive(Class clazz) for each programmatically described bean. As programmatically described beans may result in additional BDAs being added to the graph, Weld will discover the BDA structure every time an unknown BDA is returned by Deployment.loadBeanDeploymentArchive.
Virtual BDAs
In a strict container, each BDA might have to explicitly specify which other BDAs it can access. However many containers will allow an easy mechanism to make BDAs bi-directionally accessible (such as a library directory). In this case, it is allowable (and reasonable) to describe all such archives as a single, 'virtual' BeanDeploymentArchive. A container, might, for example, use a flat accessibility structure for the application. In this case, a single BeanDeploymentArchive would be attached to the Deployment.
BeanDeploymentArchive provides three methods which allow it's contents to be discovered by WeldBeanDeploymentArchive.getBeanClasses() must return all the classes in the BDA, BeanDeploymentArchive.getBeansXml() must return all the deployment descriptors in the archive, and BeanDeploymentArchive.getEjbs() must provide an EJB descriptor for every EJB in the BDA, or an empty
list if it is not an EJB archive. BDA X may also reference another BDA Y whose beans can be resolved by, and injected into, any bean in BDA X. These are the accessible BDAs, and every BDA that is directly accessible by BDA X should be returned. A BDA will also have BDAs which are accessible transitively, and the transitive closure of the sub-graph of BDA X describes all the beans resolvable by BDA X.
To
specify
the
directly
accessible
BDAs,
the
container
should
provide
an
implementation
of
BeanDeploymentArchive.getBeanDeploymentArchives().
Tip
Weld allows the container to describe a circular graph, and will convert a graph to a tree as part of the deployment process.
Certain services are provided for the whole deployment, whilst some are provided per-BDA. BDA services are provided using BeanDeploymentArchive.getServices() and only apply to the BDA on which they are provided.
136
The EjbDescriptor should return the relevant metadata as defined in the EJB specification. Each business interface of a session bean should be described using a BusinessInterfaceDescriptor.
Important
CDI only provides annotation-based EE resource injection; if you wish to provide deployment descriptor (e.g. ejb-jar.xml) injection, you must use Section A.1.8, Injection Services.
If the container performs EE resource injection, the injected resources must be serializable. If EE resource injection is provided by Weld, the resolved resource must be serializable.
Tip
If you use a non-EE environment then you may implement any of the EE service SPIs, and Weld will provide the associated functionality. There is no need to implement those services you don't need!
EJBServices is used to resolve local EJBs used to back session beans, and must always be provided in an EE environment. EJBServices.resolveEjb(EjbDescriptor ejbDescriptor) returns a wrapper SessionObjectReferencearound the EJB reference. This wrapper allows Weld to request a reference
that implements the given business interface, and, in the case of SFSBs, both request the removal of the EJB from the container and query whether the EJB has been previously removed.
EJBResolutionServices.resolveEjb(InjectionPoint
injection into managed beans). This service is not required if the implementation of Section A.1.8, Injection Services takes care of @EJB injection.
137
javax.transaction.Synchronization implementation may be passed to the registerSynchronization() method and the SPI implementation should immediately register the
synchronization with the JTA transaction manager used for the EJBs. To make it easier to determine whether or not a transaction is currently active for the requesting thread, the isTransactionActive() method can be used. The SPI implementation should query the same JTA transaction manager used for the EJBs.
simple
contract,
the
instance that CDI injects, whether it is a contextual instance, or a non-contextual instance injected by InjectionTarget.inject(). The InjectionContext can be used to discover additional information about the injection being performed, including the target being injected. ic.proceed() should be called to perform CDI-style injection, and call initializer methods.
Tip
Most Servlet contains use a classloader-per-war, this may provide a good way to identify the BDA in use for web requests.
138
When Weld needs to identify the BDA, it will use one of these services, depending on what is servicing the request:
ServletServices.getBeanDeploymentArchive(ServletContext ctx) Identify the war in use. The ServletContext is provided for additional context.
Weld, you must create an instance of org.jboss.weld.bootstrap.WeldBeansBootstrap (which implements Boostrap), tell it about the services in use, and then request the container start. The bootstrap is split into phases, container initialization, bean deployment, bean validation and shutdown. Initialization will create a manager, and add the built-in contexts, and examine the deployment structure. Bean deployment will deploy any beans (defined using annotations, programtically, or built in). Bean validation will validate all beans. To initialize the container, you call Bootstrap.startInitialization(). Before calling startInitialization(), you must register any services required by the environment. You can do this by calling, for example, bootstrap.getServices().add(JpaServices.class, new MyJpaServices()). You must also provide the application context bean store. Having called startInitialization(), the Manager for each BDA can be obtained by calling
Bootstrap.getManager(BeanDeploymentArchive bda).
To deploy the discovered beans, call Bootstrap.deployBeans(). To validate the deployed beans, call Bootstrap.validateBeans(). To place the container into a state where it can service requests, call Bootstrap.endInitialization() To shutdown the container you call Bootstrap.shutdown(). This allows the container to perform any cleanup operations needed.
org.jboss.weld.spi.ResourceLoader.
139
Classloader isolation If you are integrating Weld into an environment that supports deployment of multiple applications, you must enable, automatically, or through user configuation, classloader isolation for each CDI application. Servlet If you are integrating Weld into a Servlet environment you must register
Tip
There are a number of ways you can obtain the bean manager for the module. You could call
Bootstrap.getManager(), passing in the BDA for this module. Alternatively, you could
use the injection into Java EE component classes, or look up the bean manager in JNDI.
If
you
are
integrating
Weld
into
JSF
environment
you
must
register
Note
Weld only supports JSF 1.2 and above.
JSP If you are integrating Weld into a JSP environment you must register
140
Tip
There are a number of ways you can obtain the bean manager for the module. You could call
Bootstrap.getManager(), passing in the BDA for this module. Alternatively, you could
use the injection into Java EE component classes, or look up the bean manager in JNDI.
Session Bean Interceptor If you are integrating Weld into an EJB environment you must register the aroundInvoke method of org.jboss.weld.ejb.SessionBeanInterceptor as a EJB around-invoke interceptor for all EJBs in the application, either automatically, or through user configuration, for each CDI application which uses enterprise beans. If you are running in a EJB 3.1 environment, you should register this as an around-timeout interceptor as well.
Important
You must register the SessionBeanInterceptor as the inner most interceptor in the stack for all EJBs.
The weld-core.jar Weld can reside on an isolated classloader, or on a shared classloader. If you choose to use an isolated classloader, the default SingletonProvider, IsolatedStaticSingletonProvider, can be used. If you choose to use a shared classloader, then you will need to choose another strategy. You can provide your own implementation of Singleton and SingletonProvider and register it for use using SingletonProvider.initialize(SingletonProvider provider). Weld also provides an implementation of Thread Context Classloader per application strategy, via the
TCCLSingletonProvider.
Binding the manager in JNDI You To should obtain bind the the bean bean manager manager for for the the bean bean deployment deployment archive archive, into you JNDI may at call
bootstrap.getBeanManager(beanDeploymentArchive)
Performing CDI injection on Java EE component classes The CDI specification requires the container to provide injection into non-contextual resources for all Java EE component classes. Weld delegates this responsibility to the container. This can be achieved using the CDI defined InjectionTarget SPI. Furthermore, you must perform this operation on the correct bean manager for the bean deployment archive containing the EE component class. The fired CDI for specification every Java also EE requires that a component class.
ProcessInjectionTarget
Furthermore, if an
141
To help the integrator, Weld provides WeldManager.fireProcessInjectionTarget() which returns the InjectionTarget to use.
// Fire ProcessInjectionTarget, returning the InjectionTarget // to use InjectionTarget it = weldBeanManager.fireProcessInjectionTarget(clazz); // Per instance required, create the creational context CreationalContext<?> cc = beanManager.createCreationalContext(null); // Produce the instance, performing any constructor injection required Object instance = it.produce(); // Perform injection and call initializers it.inject(instance, cc); // Call the post-construct callback it.postConstruct(instance); // Call the pre-destroy callback it.preDestroy(instance); // Clean up the instance it.dispose(); cc.release();
The container may intersperse other operations between these calls. Further, the integrator may choose to implement any of these calls in another manner, assuming the contract is fulfilled. When performing injections on EJBs you must use the Weld-defined SPI, WeldManager. Furthermore, you must perform this operation on the correct bean manager for the bean deployment archive containing the EJB.
// Obtain the EjbDescriptor for the EJB // You may choose to use this utility method to get the descriptor EjbDescriptor<?> ejbDescriptor = beanManager.getEjbDescriptor(ejbName); // Get an the Bean object Bean<?> bean = beanManager.getBean(ejbDescriptor); // Create the injection target InjectionTarget it = deploymentBeanManager.createInjectionTarget(ejbDescriptor); // Per instance required, create the creational context CreationalContext<?> cc = deploymentBeanManager.createCreationalContext(bean); // Perform injection and call initializers it.inject(instance, cc); // You may choose to have CDI call the post construct and pre destroy // lifecycle callbacks // Call the post-construct callback it.postConstruct(instance); // Call the pre-destroy callback
142
143
144