CDI"

From Documentation
m ((via JWB))
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{ZKDevelopersReferencePageHeader}}
 
{{ZKDevelopersReferencePageHeader}}
  
CDI ([http://jcp.org/en/jsr/detail?id=299 JSR-299]) is an emerging standard for contexts and dependency injection for Java EE.
 
  
Here we discuss how to use CDI with ZK, especially the use of <javadoc>org.zkoss.zkplus.cdi.DelegatingVariableResolver</javadoc>. It provides the basic support of CDI which allow a ZUML document to access variables defined in CDI. For more comprehensive support, please refer to another product: [http://code.google.com/p/zkcdi/ ZK CDI].
 
  
For more information, please refer to the following blogs:
+
= Overview =
  
* [http://blog.zkoss.org/index.php/2010/01/07/integrate-zk-and-jsr-299weld/ Integrate ZK and JSR-299]
+
Contexts and Dependency Injection (CDI) is one of Java EE 6 features and is composed of a set of services designed for using with stateful objects. It also allows developers to integrate various kinds of objects in a loosely coupled and type safe way. We will talk about several ways of integration including injecting and accessing CDI beans under different conditions. We assume that readers have knowledge in basic CDI configuration and concept such as bean scope, we will therefore not cover those topics here. Please refer to [http://docs.oracle.com/javaee/6/tutorial/doc/gjbnr.html Oracle's CDI tutorial].
* [http://blog.zkoss.org/index.php/2010/02/11/handling-zk-events-using-cdi-event-notification-model/ Handling ZK Events using CDI event notification model]
 
  
=Example=
 
  
Here is a ''Hello World'' example. Suppose we have a Java class called HelloWorld as shown below.
+
= Access a CDI Bean in a ZUL =
  
<source lang="java">
+
ZUL provides a feature called [[ZK Developer's Reference/UI Composing/ZUML/EL Expressions#Variable Resolver| variable resolver]] that allows users to access CDI bean using EL expression. To do this, simply put the below directive on top of a ZUML page:
@Named
+
 
@SessionScoped
+
'''<code>&lt;?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver" ?&gt;</code> '''
public class HelloWorld implements Serializable {
+
 
    private final String text = "Hello World";
+
Then, in the rest of your page, you can access a CDI bean which has <code>@Named</code> directly using its '''bean EL name'''.
    public String getText() {
+
 
        return text;
+
'''Session scoped bean'''
    }
+
<source lang="java" highlight="1">
 +
@SessionScoped @Named
 +
public class UserPreference implements Serializable{
 +
...
 +
}
 +
</source>
 +
* User preference should be distinct for each user but shared among multiple requests. It is suitable to be a session scoped bean.
 +
 
 +
 
 +
'''Application scoped bean'''
 +
<source lang="java" highlight="1">
 +
@ApplicationScoped @Named
 +
public class SystemConfiguration implements Serializable{
 +
...
 +
}
 +
 
 +
</source>
 +
* As system configuration should be shared within the whole application, it should be an application scoped bean.
 +
 
 +
 
 +
'''Access bean using EL in a ZUL'''
 +
<source lang="xml" highlight="1,5, 9">
 +
<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
 +
...
 +
<hlayout>
 +
User Preference :
 +
<label id="sessionValue">${userPreference.value}</label>
 +
</hlayout>
 +
<hlayout>
 +
System Configuration :
 +
<label id="applicationValue">${systemConfiguration.value}</label>
 +
</hlayout>
 +
...
 +
</source>
 +
 
 +
= Wire CDI beans =
 +
==  Wire a CDI bean in a Composer ==
 +
 
 +
It is likely that we need to use a CDI bean in a composer, for example calling a service layer object to perform business logic. If a composer is a CDI bean, we can simply use <code>@Inject</code> to inject all collaborators. However, we do not recommend this approach as explained in previously.
 +
 
 +
ZK provides another approach to wire a CDI bean in a composer which is not a CDI bean. With help of <code>org.zkoss.zkplus.spring.DelegatingVariableResolver</code> and <code>@WireVairable</code>,  we can inject CDI beans into a composer. There are two ways to apply a variable resolver to a composer. We can
 +
 
 +
<ol>
 +
<li>Put it in a zul with directive mentioned in the previous section or,</li>
 +
<li>In a Java class with annotation, <code>@VariableResolver</code> then apply the annotation, <code>@WireVariable</code> on the variables which we want to inject CDI beans to.</li>
 +
</ol>
 +
 
 +
Example code are as follow:
 +
 
 +
 
 +
'''A composer injected with a CDI bean'''
 +
<source lang="java" highlight="3">
 +
 
 +
public class ResolverComposer extends SelectorComposer<Window> {
 +
 
 +
@WireVariable("normalOrderService")
 +
NormalOrderService orderService;
 +
 +
@Wire("#number")
 +
private Label label;
 +
 +
 +
@Override
 +
public void doAfterCompose(Window comp) throws Exception {
 +
super.doAfterCompose(comp);
 +
label.setValue(Integer.toString(orderService.findAll().size()));
 +
}
 +
 +
}
 +
</source>
 +
 
 +
'''A ZUL with CDI variable resolver'''
 +
<source lang="xml" highlight="1">
 +
 
 +
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
 +
<window title="Access Bean with different scopes" border="normal" width="700px"
 +
apply="org.zkoss.reference.developer.spring.composer.ResolverComposer">
 +
...
 +
</window>
 +
</source>
 +
 
 +
== Wire a CDI bean in a ViewModel ==
 +
 
 +
Like wiring in a composer, we apply CDI variable resolver with directive and <code>@WireVariable</code> to inject CDI beans.
 +
 
 +
<source lang="java" highlight="3,5">
 +
 
 +
public class MyViewModel{
 +
 
 +
@WireVariable
 +
private UserPreference userPreference;
 +
@WireVariable
 +
private ProductService productService;
 +
 +
private List<String> productList;
 +
 +
@Init
 +
public void doAfterCompose(Window comp) throws Exception {
 +
productList = productService.findAll();
 +
}
 +
 
 +
public UserPreference getUserPreference() {
 +
return userPreference;
 +
}
 +
 
}
 
}
 +
 
</source>
 
</source>
  
Then, we could access it by specifying the variable resolver: <javadoc>org.zkoss.zkplus.cdi.DelegatingVariableResolver</javadoc> as shown below:
+
<source lang="xml" highlight="1,4">
  
<source lang="xml" high="1">
 
 
<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
 
<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
<window title="ZK + CDI: Hello World" width="300px">
+
<window border="normal" width="500px"
    My weld-injected bean says: ${helloWorld.text}
+
apply="org.zkoss.bind.BindComposer"
 +
viewModel="@id('vm')@init('org.zkoss.reference.developer.composer.MyViewModel')">
 +
...
 
</window>
 
</window>
 +
 
</source>
 
</source>
  
<javadoc>org.zkoss.zkplus.cdi.DelegatingVariableResolver</javadoc> resolves all variables defined by CDI (with Java annotations). In other words, it makes them visible to the ZUML document, including EL expressions, data binding and zscript.
+
== Adding Variable Resolver to a Composer (or ViewModel) ==
 +
 
 +
Adding a variable resolver to a ZUL will make it available to all composers on the ZUL. If you only want to add a variable resolver to a specific composer (or ViewModel), you should apply the annotation
 +
 
 +
'''<code>@VariableResolver(org.zkoss.zkplus.cdi.DelegatingVariableResolver.class)</code>'''
 +
 
 +
on '''the class that inherits <code>SelectorComposer</code> or a ViewModel''', then, apply <code>@WireVariable</code> on variables like shown in the previous section.  
  
=Setup Tomcat + Weld=
+
Example code are as follows:
[http://docs.jboss.org/weld/reference/1.0.0/en-US/html/ Weld] is an implementation of CDI. Here is a brief installation instructions:
 
  
* Copy <tt>weld-servlet.jar</tt> to your application's <tt>WEB-INF/lib</tt> folder. You can find the jar file in [[https://sourceforge.net/projects/jboss/files/Weld/1.0.0.SP1/weld-1.0.0.SP1.zip/download  Weld 1.0 SP1].
+
<source lang="java" highlight="1,4">
 +
@VariableResolver(org.zkoss.zkplus.cdi.DelegatingVariableResolver.class)
 +
public class MyComposer extends SelectorComposer<Window> {
  
* Add in your application's <tt>WEB-INF/web.xml</tt> the following listener. This makes Weld bind with Tomcat.
+
@WireVariable
<source lang="xml">
+
private UserPreference userPreference;
<listener>
+
...
    <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
+
}
</listener>
 
 
</source>
 
</source>
  
* In your application's <tt>META-INF</tt> folder, creates a <tt>context.xml</tt> file with following contents. This provides a JNDI reference <tt>java:comp/env/BeanManager</tt> for the accessing to the Weld bean manager. The ZK CDI variable resolver will need this.  
+
 
<source lang="xml">
+
= Warning: Declare a Composer (or ViewModel) as a CDI bean =
<Context>
+
 
    <Resource name="BeanManager" auth="Container"
+
Developers might tend to make a composer (or a ViewModel) as a CDI bean, but we don't recommend this approach. Because none of CDI's copes matches correctly with the life cycle of the composers. The scope of a composer is "desktop" scope. It is shorter than "session" and longer than "prototype". Only ZK knows when to create composers (or ViewModel), so it's better to let composers be managed by ZK.
        type="javax.enterprise.inject.spi.BeanManager"
+
 
        factory="org.jboss.weld.resources.ManagerObjectFactory"/>
+
If you insist on making composers (or ViewModel) as CDI beans, <code>@Dependent</code> scope could be a feasible scope but you need to use with care; each time you try to resolve a composer bean, you will get a new instance of a composer. If the composer stores some states, it would cause inconsistency states among multiple composers.
</Context></source>
+
 
 +
 
 +
= Example Source Code =
 +
 
 +
All source code of examples used in this chapter can be found [https://github.com/zkoss/zkbooks/tree/master/developersreference/integration.cdi here].
  
 
=Version History=
 
=Version History=
{{LastUpdated}}
+
 
{| border='1px' | width="100%"
+
{| class='wikitable' | width="100%"
 
! Version !! Date !! Content
 
! Version !! Date !! Content
 
|-
 
|-
| &nbsp;
+
| 6.5.0
| &nbsp;
+
| November 2012
| &nbsp;
+
| Rewrite for improvement.
 
|}
 
|}
  
 
{{ZKDevelopersReferencePageFooter}}
 
{{ZKDevelopersReferencePageFooter}}

Latest revision as of 07:33, 8 July 2022


Overview

Contexts and Dependency Injection (CDI) is one of Java EE 6 features and is composed of a set of services designed for using with stateful objects. It also allows developers to integrate various kinds of objects in a loosely coupled and type safe way. We will talk about several ways of integration including injecting and accessing CDI beans under different conditions. We assume that readers have knowledge in basic CDI configuration and concept such as bean scope, we will therefore not cover those topics here. Please refer to Oracle's CDI tutorial.


Access a CDI Bean in a ZUL

ZUL provides a feature called variable resolver that allows users to access CDI bean using EL expression. To do this, simply put the below directive on top of a ZUML page:

<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver" ?>

Then, in the rest of your page, you can access a CDI bean which has @Named directly using its bean EL name.

Session scoped bean

@SessionScoped @Named
public class UserPreference implements Serializable{
...
}
  • User preference should be distinct for each user but shared among multiple requests. It is suitable to be a session scoped bean.


Application scoped bean

@ApplicationScoped @Named
public class SystemConfiguration implements Serializable{
...
}
  • As system configuration should be shared within the whole application, it should be an application scoped bean.


Access bean using EL in a ZUL

<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
...
			<hlayout>
				User Preference :
				<label id="sessionValue">${userPreference.value}</label>
			</hlayout>
			<hlayout>
				System Configuration :
				<label id="applicationValue">${systemConfiguration.value}</label>
			</hlayout>
...

Wire CDI beans

Wire a CDI bean in a Composer

It is likely that we need to use a CDI bean in a composer, for example calling a service layer object to perform business logic. If a composer is a CDI bean, we can simply use @Inject to inject all collaborators. However, we do not recommend this approach as explained in previously.

ZK provides another approach to wire a CDI bean in a composer which is not a CDI bean. With help of org.zkoss.zkplus.spring.DelegatingVariableResolver and @WireVairable, we can inject CDI beans into a composer. There are two ways to apply a variable resolver to a composer. We can

  1. Put it in a zul with directive mentioned in the previous section or,
  2. In a Java class with annotation, @VariableResolver then apply the annotation, @WireVariable on the variables which we want to inject CDI beans to.

Example code are as follow:


A composer injected with a CDI bean

public class ResolverComposer extends SelectorComposer<Window> {

	@WireVariable("normalOrderService")
	NormalOrderService orderService;
	
	@Wire("#number")
	private Label label;
	
	
	@Override
	public void doAfterCompose(Window comp) throws Exception {
		super.doAfterCompose(comp);
		label.setValue(Integer.toString(orderService.findAll().size()));
	}
	
}

A ZUL with CDI variable resolver

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="Access Bean with different scopes" border="normal" width="700px"
	apply="org.zkoss.reference.developer.spring.composer.ResolverComposer">
...
</window>

Wire a CDI bean in a ViewModel

Like wiring in a composer, we apply CDI variable resolver with directive and @WireVariable to inject CDI beans.

public class MyViewModel{

	@WireVariable
	private UserPreference userPreference;
	@WireVariable
	private ProductService productService;
	
	private List<String> productList;
	
	@Init
	public void doAfterCompose(Window comp) throws Exception {
		productList = productService.findAll();
	}

	public UserPreference getUserPreference() {
		return userPreference;
	}
	
}
<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
<window border="normal" width="500px"
	apply="org.zkoss.bind.BindComposer" 
	viewModel="@id('vm')@init('org.zkoss.reference.developer.composer.MyViewModel')">
...
</window>

Adding Variable Resolver to a Composer (or ViewModel)

Adding a variable resolver to a ZUL will make it available to all composers on the ZUL. If you only want to add a variable resolver to a specific composer (or ViewModel), you should apply the annotation

@VariableResolver(org.zkoss.zkplus.cdi.DelegatingVariableResolver.class)

on the class that inherits SelectorComposer or a ViewModel, then, apply @WireVariable on variables like shown in the previous section.

Example code are as follows:

@VariableResolver(org.zkoss.zkplus.cdi.DelegatingVariableResolver.class)
public class MyComposer extends SelectorComposer<Window> {

	@WireVariable
	private UserPreference userPreference;
...
}


Warning: Declare a Composer (or ViewModel) as a CDI bean

Developers might tend to make a composer (or a ViewModel) as a CDI bean, but we don't recommend this approach. Because none of CDI's copes matches correctly with the life cycle of the composers. The scope of a composer is "desktop" scope. It is shorter than "session" and longer than "prototype". Only ZK knows when to create composers (or ViewModel), so it's better to let composers be managed by ZK.

If you insist on making composers (or ViewModel) as CDI beans, @Dependent scope could be a feasible scope but you need to use with care; each time you try to resolve a composer bean, you will get a new instance of a composer. If the composer stores some states, it would cause inconsistency states among multiple composers.


Example Source Code

All source code of examples used in this chapter can be found here.

Version History

Version Date Content
6.5.0 November 2012 Rewrite for improvement.



Last Update : 2022/07/08

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.