summaryrefslogtreecommitdiffstats
path: root/documentation/advanced/advanced-cdi.asciidoc
diff options
context:
space:
mode:
authorIlia Motornyi <elmot@vaadin.com>2015-12-03 14:59:05 +0000
committerVaadin Code Review <review@vaadin.com>2015-12-03 14:59:12 +0000
commit2af72ba9636bec70046394c41744f89ce4572e35 (patch)
treeccb3dc2d2239585f8c3f79eb5f131ff61ca9ce86 /documentation/advanced/advanced-cdi.asciidoc
parent8aa5fabe89f2967e966a64842a608eceaf80d08f (diff)
downloadvaadin-framework-2af72ba9636bec70046394c41744f89ce4572e35.tar.gz
vaadin-framework-2af72ba9636bec70046394c41744f89ce4572e35.zip
Revert "Merge branch 'documentation'"7.6.0.beta2
This reverts commit f6874bde3d945c8b2d1b5c17ab50e2d0f1f8ff00. Change-Id: I67ee1c30ba3e3bcc3c43a1dd2e73a822791514bf
Diffstat (limited to 'documentation/advanced/advanced-cdi.asciidoc')
-rw-r--r--documentation/advanced/advanced-cdi.asciidoc997
1 files changed, 0 insertions, 997 deletions
diff --git a/documentation/advanced/advanced-cdi.asciidoc b/documentation/advanced/advanced-cdi.asciidoc
deleted file mode 100644
index d5d135ca1f..0000000000
--- a/documentation/advanced/advanced-cdi.asciidoc
+++ /dev/null
@@ -1,997 +0,0 @@
----
-title: Vaadin CDI Add-on
-order: 17
-layout: page
----
-
-[[advanced.cdi]]
-= Vaadin CDI Add-on
-
-((("Contexts and Dependency Injection", id="term.advanced.cdi.cdilong", range="startofrange")))
-
-
-((("CDI", id="term.advanced.cdi.cdi", range="startofrange")))
-
-
-((("Vaadin CDI Add-on", id="term.advanced.cdi.cdiaddon", range="startofrange")))
-
-
-Vaadin CDI add-on makes it easier to use contexts and dependency injection (CDI)
-in Vaadin applications. CDI is a Java EE feature especially targeted for web
-applications, which have well-defined contextual scopes, such as sessions,
-views, requests, and so forth. The lifecycle of objects, such as beans, can be
-managed by binding their lifecycles to such contexts. Vaadin CDI enables these
-features with two additional kinds of Vaadin-specific contextual scopes: UIs and
-navigation views.
-
-To learn more about Vaadin CDI, the link:[Vaadin CDI Tutorial] gives a hands-on
-introduction. The source code of the CDI Tutorial demo is available for browsing
-or cloning at https://github.com/vaadin-samples/cdi-tutorial.
-
-[[advanced.cdi.cdi]]
-== CDI Overview
-
-Contexts and dependency injection, defined in the JSR-299 standard, is a Java EE
-feature that, through a set of services, helps in improving application
-architecture by decoupling the management of service object lifecycles from
-client objects using them. The lifecycle of objects stored in a CDI container is
-defined by a context. The managed objects or beans are accessed using dependency
-injection.
-
-CDI builds on the Java concept of beans, but with somewhat different definition
-and requirements.
-
-Regarding general CDI topics, such as use of qualifiers, interceptors,
-decorators, event notifications, and other CDI features, we refer you to CDI
-documentation.
-
-ifdef::web[]
-* link:http://jaxenter.com/tutorial-introduction-to-cdi-contexts-and-dependency-injection-for-java-ee-jsr-299-104536.html[Introduction
-to CDI]. Pete Muir and Mark Struberg, JAXenter.
-
-* link:http://docs.jboss.org/weld/reference/latest/en-US/html_single/[Weld - CDI
-Reference Implementation]
-
-* link:http://cdi-spec.org/[CDI Specification]
-
-* link:https://vaadin.com/wiki?p_p_id=36&amp;p_p_lifecycle=0&amp;p_p_state=normal&amp;p_p_mode=view&amp;p_p_col_id=row-1&amp;p_p_col_pos=1&amp;p_p_col_count=3&amp;p_r_p_185834411_title=Vaadin+CDI&amp;p_r_p_185834411_nodeName=vaadin.com+wiki&amp;_36_struts_action=%2Fwiki%2Fview[Vaadin
-CDI Tutorial]
-
-endif::web[]
-
-[[advanced.cdi.cdi.injection]]
-=== Dependency Injection
-
-__Dependency injection__ is a way to pass dependencies (service objects) to
-dependent objects (clients) by injecting them in member variables or initializer
-parameters, instead of managing the lifecycle in the clients or passing them
-explicitly as parameters. In CDI, injection of a service object to a client is
-specified by the [classname]#@Inject# annotation.
-
-For example, if we have a UI view that depends on user data, we could inject the
-data in the client as follows:
-
-
-[source, java]
-----
-public class MainView extends CustomComponent implements View {
- @Inject
- User user;
-
- ...
- @Override
- public void enter(ViewChangeEvent event) {
- greeting.setValue("Hello, " + user.getName());
- }
-}
-----
-
-In addition to injecting managed beans with the annotation, you can query for
-them from the bean manager.
-
-
-[[advanced.cdi.cdi.contexts]]
-=== Contexts and Scopes
-
-__Contexts__ in CDI are services that manage the lifecycle of objects and handle
-their injection. Generally speaking, a context is a situation in which an
-instance is used with a unique identity. Such objects are essentially
-"singletons" in the context. While conventional singletons are application-wide,
-objects managed by a CDI container can be "singletons" in a more narrow
-__scope__: a user session, a particular UI instance associated with the session,
-a view within the UI, or even just a single request. Such a context defines the
-lifecycle of the object: its creation, use, and finally its destruction.
-
-As a very typical example in a web application, you would have a user data
-object associated with a user session.
-
-
-[source, java]
-----
-@SessionScoped
-public class User {
- private String name;
-
- public void setName(String name) {this.name = name;}
- public String getName() {return name;}
-}
-----
-
-Now, when you need to refer to the user, you can use CDI injection to inject the
-session-scoped "singleton" to a member variable or a constructor parameter.
-
-
-[source, java]
-----
-public class MainView extends CustomComponent implements View {
- @Inject
- User user;
-
- ...
-
- @Override
- public void enter(ViewChangeEvent event) {
- greeting.setValue("Hello, " + user.getName());
- }
-}
-----
-
-
-
-[[advanced.cdi.installation]]
-== Installing Vaadin CDI Add-on
-
-Vaadin CDI requires a Java EE 7 compatible servlet container, such as Glassfish
-or Apache TomEE Web Profile, as mentioned for the reference toolchain in
-<<dummy/../../../framework/getting-started/getting-started-environment#getting-started.environment,"Setting
-up the Development Environment">>.
-
-To install the Vaadin CDI add-on, either define it as an Ivy or Maven dependency
-or download it from the Vaadin Directory add-on page at
-<<,vaadin.com/directory#addon/vaadin-cdi>>. See
-<<dummy/../../../framework/addons/addons-overview.asciidoc#addons.overview,"Using
-Vaadin Add-ons">> for general instructions for installing and using Vaadin
-add-ons.
-
-The Ivy dependency is as follows:
-
-[subs="normal"]
-----
- &lt;dependency org="com.vaadin" name="vaadin-cdi"
- rev="[replaceable]#latest.release#"/&gt;
-----
-The Maven dependency is as follows:
-
-[subs="normal"]
-----
- &lt;dependency&gt;
- &lt;groupId&gt;com.vaadin&lt;/groupId&gt;
- &lt;artifactId&gt;vaadin-cdi&lt;/artifactId&gt;
- &lt;version&gt;[replaceable]#LATEST#&lt;/version&gt;
- &lt;/dependency&gt;
- &lt;dependency&gt;
- &lt;groupId&gt;javax.enterprise&lt;/groupId&gt;
- &lt;artifactId&gt;cdi-api&lt;/artifactId&gt;
- &lt;version&gt;[replaceable]#1.2#&lt;/version&gt;
- &lt;/dependency&gt;
-----
-
-[[advanced.cdi.peparing]]
-== Preparing Application for CDI
-
-A Vaadin application that uses CDI must have a file named [filename]#beans.xml#
-in the [filename]#WEB-INF# directory. The file can be completely empty (it has
-content only in certain limited situations), but it must be present.
-
-The application should not have a servlet extending [classname]#VaadinServlet#,
-as Vaadin servlet has its own [classname]#VaadinCDIServlet# that is deployed
-automatically. If you need multiple servlets or need to customize the Vaadin CDI
-servlet, see <<advanced.cdi.deployment>>.
-
-
-[[advanced.cdi.cdiui]]
-== Injecting a UI with [classname]#@CDIUI#
-
-((("[classname]#@CDIUI#", id="term.advanced.cdi.cdiui", range="startofrange")))
-
-
-Vaadin CDI offers an easier way to instantiate UIs and to define the URL mapping
-for them than the usual ways described in
-<<dummy/../../../framework/application/application-environment#application.environment,"Deploying
-an Application">>. To define a UI class that should be instantiated for a given
-URL, you simply need to annotate the class with [classname]#@CDIUI#. It takes an
-optional URL path as parameter.
-
-
-[source, java]
-----
-@CDIUI("myniceui")
-@Theme("valo")
-public class MyNiceUI extends UI {
- ...
-----
-
-Giving empty UI path maps the UI to the root of the application context.
-
-
-[source, java]
-----
-@CDIUI("")
-----
-
-If the optional UI path is not given, the path is determined automatically from
-the class name by removing a possible "-UI" suffix in the class name, making it
-lower-case, and for capitalized letters, a hyphen is added. For example, a UI
-with class name [classname]#MyNiceUI# would have path [literal]#++my-nice++#.
-The URL consists of the server address, application context, and the UI path.
-For example, when running a Vaadin application in a development workstation, you
-would have URL such as http://localhost:8080/myproject/my-nice.
-
-UI path mappings are reported in the server log during deployment.
-
-See <<advanced.cdi.deployment>> for how to handle servlet URL mapping of CDI UIs
-when working with multiple servlets in the same web application.
-
-(((range="endofrange", startref="term.advanced.cdi.cdiui")))
-
-[[advanced.cdi.scopes]]
-== Scopes
-
-((("CDI", "scopes", id="term.advanced.cdi.scopes", range="startofrange")))
-
-
-As in programming languages, where a variable name refers to a unique object
-within the scope of the variable, a CDI scope is a context in which an object
-has unique identity. In CDI, objects to be injected are identified by their type
-and any qualifiers they may have. The scope can be defined as an annotation to
-the service class as follows:
-
-
-[source, java]
-----
-@SessionScoped
-public class User {
- ...
-----
-
-CDI defines a number of scopes. Note that the standard CDI scopes are defined
-under the [package]#javax.enterprise.context# package and Vaadin CDI scopes
-under [package]#com.vaadin.cdi#, while JSF scopes are defined in
-[package]#javax.faces.bean#.
-
-[[advanced.cdi.scopes.ui]]
-=== UI Scope
-
-UI-scoped beans are uniquely identified within a UI instance, that is, a browser
-window or tab.
-
-Vaadin CDI provides two annotations for the UI scope, differing in how they
-enable proxies, as explained later.
-
-[classname]#@UIScoped#([package]#com.vaadin.cdi#):: ((("[classname]#@UIScoped#", id="term.advanced.cdi.scopes.uiscoped", range="startofrange")))
-
-
-+
-Injection with this annotation will create a direct reference to the bean rather
-than a proxy. There are some limitations when not using proxies. Circular
-references (injecting A to B and B to A) will not work, and neither do CDI
-interceptors and decorators.
-
-(((range="endofrange", startref="term.advanced.cdi.scopes.uiscoped")))
-[classname]#@NormalUIScoped#([package]#com.vaadin.cdi#):: As [classname]#@UIScoped#, but injecting a managed bean having this annotation
-injects a proxy for the bean instead of a direct reference. This is the normal
-behaviour with CDI, as many CDI features utilize the proxy.
-
-
-
-Defining a CDI view (annotated with [classname]#@CDIView# as described later) as
-[classname]#@UIScoped# makes the view retain the same instance when the user
-navigates away and back to the view.
-
-
-[[advanced.cdi.scopes.view]]
-=== View Scopes
-
-The lifecycle of a view-scoped bean starts when the user navigates to a view
-referring to the object and ends when the user navigates out of the view (or
-when the UI is closed or expires).
-
-Vaadin CDI provides two annotations for the view scope, differing in how they
-enable proxies, as explained later.
-
-[classname]#@ViewScoped#([package]#com.vaadin.cdi#):: Injection with this annotation will create a direct reference to the bean rather
-than a proxy. There are some limitations when not using proxies. Circular
-references (injecting A to B and B to A) will not work, and neither do CDI
-interceptors and decorators.
-
-[classname]#@NormalViewScoped#([package]#com.vaadin.cdi#):: As [classname]#@NormalScoped#, except that injecting with this annotation will
-create a proxy for the contextual instance rather than provide the contextual
-instance itself. See the explanation of proxies below.
-
-
-
-
-[[advanced.cdi.scopes.cdi]]
-=== Standard CDI Scopes
-
-[classname]#@ApplicationScoped#:: ((("[classname]#@ApplicationScoped#", id="term.advanced.cdi.scopes.applicationscoped", range="startofrange")))
-
-
-+
-Application-scoped beans are shared by all servlets in the web application, and
-are essentially equal to singletons.//TODO This is just a guess - is it
-true?
-Note that referencing application-scoped beans is not thread-safe and access
-must be synchronized.
-
-(((range="endofrange", startref="term.advanced.cdi.scopes.applicationscoped")))
-[classname]#@SessionScoped#:: ((("[classname]#@SessionScoped#", id="term.advanced.cdi.scopes.sessionscoped", range="startofrange")))
-
-
-+
-The lifecycle and visibility of session-scoped beans is bound to a HTTP or user
-session, which in Vaadin applications is associated with the
-[classname]#VaadinSession# (see
-<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.session,"User
-Session">>). This is a very typical scope to store user data, as is done in many
-examples in this section, or database connections. The lifecycle of
-session-scoped beans starts when a user opens the page for a UI in the browser,
-and ends when the session expires after the last UI in the session is closed.
-
-(((range="endofrange", startref="term.advanced.cdi.scopes.sessionscoped")))
-
-
-
-[[advanced.cdi.scopes.proxies]]
-=== Proxies vs Direct References
-
-CDI uses proxy objects to enable many of the CDI features, by hooking into
-message-passing from client to service beans. Under the hood, a proxy is an
-instance of an automatically generated class that extends the proxied bean type,
-so communicating through a proxy occurs transparently, as it has the same
-polymorphic type as the actual bean. Whether proxying is enabled or not is
-defined in the scope: CDI scopes are either __normal scopes__, which can be
-proxied, or __pseudoscopes__, which use direct references to injected beans.
-
-The proxying mechanism creates some requirements for injecting objects in normal
-scope:
-
-* The objects may not be primitive types or arrays
-
-* The bean class must not be final
-
-* The bean class must not have final methods
-
-
-Beans annotated with [classname]#@UIScoped# or [classname]#@ViewScoped# use a
-pseudoscope, and are therefore injected with direct references to the bean
-instances, while [classname]#@NormalUIScoped# and [classname]#@NormalViewScoped#
-beans will use a proxy for communicating with the beans.
-
-When using proxies, be aware that it is not guaranteed that the
-[methodname]#hashCode()# or [methodname]#equals()# will match when comparing a
-proxy to its underlying instance. It is imperative to be aware of this when, for
-example, adding proxies to a [interfacename]#Collection#.
-
-You should avoid using normal scopes with Vaadin components, as proxies may not
-work correctly within the Vaadin framework. If Vaadin CDI plugin detects such
-use, it displays a warning such as the following:
-
-
-----
-INFO: The following Vaadin components are injected
-into normal scoped contexts:
- @NormalUIScoped org.example.User
-This approach uses proxy objects and has not been
-extensively tested with the framework. Please report
-any unexpected behavior. Switching to a pseudo-scoped
-context may also resolve potential issues.
-----
-
-
-(((range="endofrange", startref="term.advanced.cdi.scopes")))
-
-[[advanced.cdi.deployment]]
-== Deploying CDI UIs and Servlets
-
-Vaadin CDI hooks into Vaadin framework by using a special
-[classname]#VaadinCDIServlet#. As described earlier, you do not need to map an
-URL path to a UI, as it is handled by Vaadin CDI. However, in the following, we
-go through some cases where you need to customize the servlet or use CDI with
-non-CDI servlets and UIs in a web application.
-
-[[advanced.cdi.deployment.urlmapping]]
-=== Defining Servlet Root with [classname]#@URLMapping#
-
-CDI UIs are managed by a CDI servlet ( [classname]#VaadinCDIServlet#), which is
-by default mapped to the root of the application context. For example, if the
-name of a CDI UI is " [literal]#++my-cdi++#" and application context is
-[literal]#++/myproject++#, the UI would by default have URL "
-[literal]#++/myproject/my-cdi++#". If you do not want to have the servlet mapped
-to context root, you can use the [classname]#@URLMapping# annotation to map all
-CDI UIs to a sub-path. The annotation must be given to only one CDI UI, usually
-the one with the default ("") path.
-
-For example, if we have a root UI and another:
-
-
-[source, java]
-----
-@CDIUI("") // At CDI servlet root
-@URLMapping("mycdiuis") // Define CDI Servlet root
-public class MyCDIRootUI extends UI {...}
-
-@CDIUI("another")
-public class AnotherUI extends UI {...}
-----
-
-These two UIs would have URLs /myproject/mycdiuis and
-/myproject/mycdiuis/another, respectively.
-
-You can also map the CDI servlet to another URL in servlet definition in
-[filename]#web.xml#, as described the following.
-
-
-[[advanced.cdi.servlets.mixing]]
-=== Mixing With Other Servlets
-
-The [classname]#VaadinCDIServlet# is normally used as the default servlet, but
-if you have other servlets in the application, such as for non-CDI UIs, you need
-to define the CDI servlet explicitly in the [filename]#web.xml#. You can map the
-servlet to any URL path, but perhaps typically, you define it as the default
-servlet as follows, and map the other servlets to other URL paths:
-
-[subs="normal"]
-----
-&lt;web-app&gt;
- ...
-
- &lt;servlet&gt;
- &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
- &lt;servlet-class&gt;
- com.vaadin.cdi.internal.VaadinCDIServlet
- &lt;/servlet-class&gt;
- &lt;/servlet&gt;
-
- &lt;servlet-mapping&gt;
- &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
- &lt;url-pattern&gt;[replaceable]#/mycdiuis/*#&lt;/url-pattern&gt;
- &lt;/servlet-mapping&gt;
-
- &lt;servlet-mapping&gt;
- &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
- &lt;url-pattern&gt;/VAADIN/*&lt;/url-pattern&gt;
- &lt;/servlet-mapping&gt;
-&lt;/web-app&gt;
-----
-With such a setting, paths to CDI UIs would have base path
-[filename]#/myapp/mycdiuis#, to which the (optional) UI path would be appended.
-The [filename]#/VAADIN/*# only needs to be mapped to the servlet if there are no
-other Vaadin servlets.
-
-
-[[advanced.cdi.servlets.custom]]
-=== Custom Servlets
-
-When customizing the Vaadin servlet, as outlined in
-<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.servlet-service,"Vaadin
-Servlet, Portlet, and Service">>, you simply need to extend
-[classname]#com.vaadin.cdi.internal.VaadinCDIServlet# instead of
-[classname]#com.vaadin.servlet.VaadinServlet#.
-
-The custom servlet must not have [classname]#@WebServlet# annotation or
-[classname]#@VaadinServletConfiguration#, as you would normally with a Vaadin
-servlet, as described in
-<<dummy/../../../framework/application/application-environment#application.environment,"Deploying
-an Application">>.
-
-
-
-ifdef::web[]
-[[advanced.cdi.navigation]]
-== View Navigation
-
-Vaadin CDI extends the navigation framework in Vaadin, described in
-<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator,"Navigating
-in an Application">>. It manages CDI views with a special view provider and
-enables view scoping.
-
-[[advanced.cdi.navigation.ui]]
-=== Preparing the UI
-
-You can define navigation for any single-component container, as described in
-<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator.navigating,"Setting
-Up for Navigation">>, but typically you set up navigation for the entire UI
-content. To use Vaadin CDI views, you need to inject a
-[classname]#CDIViewProvider# in the UI and add it as a provider for the
-navigator.
-
-
-[source, java]
-----
-@CDIUI("mycdiui")
-public class MyCDIUI extends UI {
- @Inject
- CDIViewProvider viewProvider;
-
- @Override
- protected void init(VaadinRequest request) {
- Navigator navigator = new Navigator(this, this);
- navigator.addProvider(viewProvider);
-
- // Navigate to start view
- navigator.navigateTo("");
- }
-}
-----
-
-
-[[advanced.cdi.navigation.view]]
-=== The View
-
-A view managed by Vaadin CDI only needs to have the [classname]#@CDIView#
-annotation.
-
-
-[source, java]
-----
-@CDIView("main")
-public class MainView extends CustomComponent implements View {
- ...
-----
-
-The annotation can have the following optional paramers:
-
-value (optional):: Specifies the view name by which it can be accessed programmatically and by the
-URI fragment.
-
-
-+
-[source, java]
-----
-@CDIView("main")
-----
-+
-If other optional parameters are given, the value must be given by the named
-[parameter]#value# parameter.
-
-+
-If the view name is not given, it is derived from the class name by removing a
-possible "View" suffix, making it lower case, and using a dash ("-") to separate
-words originally denoted by capital letters. Thereby, a view class such as
-[classname]#MyFunnyView# would have name " [literal]#++my-funny++#".
-
-supportsParameters:: Specifies whether view parameters can be passed to the view as a suffix to the
-name in the navigation state, that is, in the form of
-[literal]#++viewname+viewparameters++#. The view name is merely a prefix and
-there is no separator nor format for the parameters, but those are left for the
-view to handle. The parameter support mode is disabled by default.
-
-
-+
-[source, java]
-----
-@CDIView(value="myview", supportsParameters=true)
-----
-+
-You could then navigate to the state with a URI fragment such as
-[literal]#++#!myview/someparameter++# or programmatically with:
-
-
-+
-[source, java]
-----
-getUI().getNavigator().navigateTo("myview/someparameter");
-----
-+
-The [methodname]#enter()# method of the view gets the URI fragment as parameter
-as is and can interpret it in any application-defined way.
-
-+
-Note that in this mode, matching a navigation state to a view is done by the
-prefix of the fragment! Thereby, no other views may start with the name of the
-view as prefix. For example, if the view name is " [literal]#++main++#", you
-must not have a view named " [literal]#++maintenance++#".
-
-uis:: If the application has multiple UIs that use [classname]#CDIViewProvider#, you
-can use this parameter to specify which UIs can show the view.
-
-
-+
-[source, java]
-----
-@CDIView(value="myview", uis={MyCDIUI.class})
-----
-+
-If the list contains [parameter]#UI.class#, the view is available to all UIs.
-
-
-+
-[source, java]
-----
-@CDIView(value="myview", uis={UI.class})
-----
-
-
-In the following, we have a login view that accesses a session-scoped user
-object. Here, we use a constant to define the view name, so that we can use the
-constant when navigating to it.
-
-
-[source, java]
-----
-@CDIView(LoginView.VIEWNAME)
-public class LoginView extends CustomComponent
- implements View {
- public final static String VIEWNAME = "";
-
- // Here we inject to the constructor and actually do
- // not store the injected object to use it later
- @Inject
- public LoginView(User user) {
- VerticalLayout layout = new VerticalLayout();
-
- // An input field for editing injected data
- BeanItem<User> item = new BeanItem<User>(user);
- TextField username = new TextField("User name",
- item.getItemProperty("name"));
- username.setNullRepresentation("");
- layout.addComponent(username);
-
- // Login button (authentication omitted) / Java 8
- layout.addComponent(new Button("Login", e ->
- getUI().getNavigator().
- navigateTo(MainView.VIEWNAME)));
-
- setCompositionRoot(layout);
- }
-
- @Override
- public void enter(ViewChangeEvent event) {}
-}
-----
-
-You could now navigate to the view from any other view in the UI with:
-
-
-[source, java]
-----
-getUI().getNavigator().navigateTo(LoginView.VIEWNAME);
-----
-
-
-endif::web[]
-
-ifdef::web[]
-[[advanced.cdi.events]]
-== CDI Events
-
-((("CDI", "events", id="term.advanced.cdi.events", range="startofrange")))
-
-
-CDI events can be used for many purposes in Vaadin applications, such as passing
-messages between different parts of a view, between views, between UIs, or
-between users. Some cases require special consideration, such as when
-communicating between UIs and how injected components should be scoped.
-
-[[advanced.cdi.events.intro]]
-=== Observing Events
-
-Let us consider a case where changes in one part of the UI (or view) require
-updating other parts of the UI. This is typical in master-detail views, for
-updating the master view after editing details, or when handling input from a
-sub-window. While you can handle such a situation with a custom call-back
-listener, CDI event mechanism simplifies the task.
-
-Let us consider the following simple UI containing two panels. The input panel
-will send events, which are received by other parts of the UI, in this case a
-display panel. The panels need to be injected to enable CDI event passing in
-them.
-
-
-[source, java]
-----
-@CDIUI("cdievents")
-@Theme("valo")
-public class CDIEventUI extends UI {
- @Inject
- InputPanel inputPanel;
-
- @Inject
- DisplayPanel displayPanel;
-
- @Override
- protected void init(VaadinRequest request) {
- Layout content =
- new HorizontalLayout(inputPanel, displayPanel);
- setContent(content);
- }
-}
-----
-
-Now, let us look closer at the sending panel. To send messages, it needs to
-inject a [classname]#javax.enterprise.event.Event# object. As we are injecting
-the event to a component class, we need to specify the full package name to
-avoid confusion with Vaadin [classname]#Component.Event#.
-
-
-[source, java]
-----
-class InputPanel extends Panel {
- @Inject
- private javax.enterprise.event.Event<MyEvent> event;
-
- public InputPanel() {
- super("Input");
-
- TextField editor = new TextField();
- Button save = new Button("Save", e -> // Java 8
- event.fire(new MyEvent(editor.getValue())));
-
- setContent(new VerticalLayout(editor, save));
- }
-}
-----
-
-Firing an event is done with the [methodname]#fire()# method on the injected
-event object. In our example, the event is as follows:
-
-
-[source, java]
-----
-public class MyEvent implements Serializable {
- private String text;
-
- public MyEvent(String text) {
- this.text = text;
- }
-
- public String getName() {
- return text;
- }
-}
-----
-
-The event is received by any method (in an injected object) marked by
-[classname]#@Observes# annotation for the event parameter to observe the event
-type.
-
-
-[source, java]
-----
-@UIScoped
-class DisplayPanel extends Panel {
- Label display = new Label("-nothing to display-");
-
- public DisplayPanel() {
- super("Display");
- setContent(display);
- }
-
- void myEventObserver(@Observes MyEvent event) {
- display.setValue("Observed: " + event.getName());
- }
-}
-----
-
-Such a component that observes events from other components must be scoped to
-the UI or view, as otherwise it will be request-scoped and a new instance is
-created for receiving each event.
-
-The UI with interaction is shown in <<figure.advanced.cdi.events.intro>>.
-
-[[figure.advanced.cdi.events.intro]]
-.Observing CDI Events
-image::img/cdi-events-observing.png[]
-
-Any injection qualifiers defined for the event object in the sender are matched
-in the observers, which feature we will use later to avoid receiving unwanted
-events.
-
-
-[[advanced.cdi.events.broadcasting]]
-=== Communicating Between UIs
-
-((("broadcasting", id="term.advanced.cdi.events.broadcasting", range="startofrange")))
-
-
-CDI events are not propagated to inactive contexts, and only the context of the
-currently processed UI is active. Further, as explained in
-<<dummy/../../../framework/advanced/advanced-push#advanced.push.running,"Accessing
-UI from Another Thread">>, other Vaadin UIs may not be accessed without proper
-synchronization, as their requests are processed concurrently in different
-server threads. Therefore, you need to pass the events through an
-application-scoped messaging service and synchronize the access to other UIs by
-using the [methodname]#access()# method.
-
-In
-<<dummy/../../../framework/advanced/advanced-push#advanced.push.pusharound,"Broadcasting
-to Other Users">> we looked into how to pass messages to all other UIs using a
-broadcasting service. In that example, we used static variables and methods to
-store references and to access the service. With CDI, we can let the context
-manage its lifecycle, access it by injection, and pass messages by CDI events.
-By scoping the messaging service to application, we essentially make it a
-singleton.
-
-
-[source, java]
-----
-@ApplicationScoped
-public class CDIBroadcaster implements Serializable {
-----
-
-As we can not let CDI deliver the messages, the messaging service needs to keep
-book of the messaging clients (UIs) waiting to receive messages.
-
-
-[source, java]
-----
- private Collection<UI> uis = new HashSet<UI>();
-
- public synchronized void register(UI listener) {
- uis.add(listener);
- }
-
- public synchronized void unregister(UI listener) {
- uis.remove(listener);
- }
-----
-
-The main logic of the messaging service is to observe messages and fire them in
-the recipient UIs. As we are broadcasting to all UIs here, we again use an
-executor service to execute the code. To lock on the session when accessing the
-UIs, we use the [methodname]#access()# method.
-
-
-[source, java]
-----
- // Inject event to be fired
- @Inject
- private javax.enterprise.event.Event<BroadcastMessage>
- messageEvent;
-
- ExecutorService executorService =
- Executors.newSingleThreadExecutor();
-
- // Observe messages (only from clients)
- @SuppressWarnings("unused")
- private synchronized void observeMessage(
- @Observes @OriginalSender
- final BroadcastMessage message) {
- for (final UI listener: uis)
- executorService.execute(() ->
- listener.access(()->
- messageEvent.fire(message)));
- }
-}
-----
-
-Here we use a [classname]#@OriginalSender# qualifier to receive events only from
-a client (original sender), not from the messaging service itself, which would
-cause an infinite event loop. The qualifier is defined as follows:
-
-((("CDI", "qualifiers")))
-
-[source, java]
-----
-@Qualifier
-@Retention(RUNTIME)
-@Target({PARAMETER, FIELD})
-public @interface OriginalSender {}
-----
-
-The message type is a simple POJO as follows:
-
-
-[source, java]
-----
-public class BroadcastMessage {
- private String text;
- private Object sender; // For checking if sent by self
-
- ... constructor, getters, and setters ...
-}
-----
-
-Let us take a look at the UI class, which manages both the messaging service and
-the client components. The UI just needs to register itself in the messaging
-service and build the UI, including the UI components doing messaging. We could,
-of course, do that also at view level.
-
-((("[classname]#@Push#")))
-
-[source, java]
-----
-@CDIUI("cdichat")
-@Push
-public class CDIChatUI extends UI {
- @Inject
- CDIBroadcaster broadcaster;
-
- @Inject
- ChatBox chatbox;
-
- @Override
- protected void init(VaadinRequest request) {
- setContent(chatbox);
-
- // Register to receive broadcasts
- broadcaster.register(this);
- }
-
- // Must also unregister when the UI expires or is closed
- @Override
- public void detach() {
- broadcaster.unregister(this);
- super.detach();
- }
-}
-----
-
-Now for an actual messaging client, we look at the chat box component. Most of
-the UI code is omitted from the example. As noted earlier, the component
-receiving events must be scoped to the UI, to avoid creation of invalid
-instances.
-
-((("[classname]#@UIScoped#")))
-
-[source, java]
-----
-@UIScoped
-class ChatBox extends CustomComponent {
- VerticalLayout messages = new VerticalLayout();
-
- public ChatBox(CDIChatUI cdiChatUI) {
- ... build the composite ...
-
- TextField input = new TextField();
-
- Button send = new Button("Send", e -> { // Java 8
- // Broadcast the input
- broadcast(input.getValue());
- addMessage(input.getValue()); // Add to self
- });
- ...
- }
-
- @Inject
- @OriginalSender
- private javax.enterprise.event.Event<BroadcastMessage>
- messageEvent;
-
- // Sends a message
- private void broadcast(String msg) {
- messageEvent.fire(new BroadcastMessage(msg, this));
- }
-
- // Receives messages
- @SuppressWarnings("unused")
- private void observeMessage(
- @Observes BroadcastMessage event) {
- if (event.getSender() != this)
- addMessage(event.getText());
- }
-
- private void addMessage(String msg) {
- messages.addComponent(new Label(msg));
- }
-}
-----
-
-((("CDI", "qualifiers")))
-Note that the client object is completely unaware of the fact that the messages
-are delivered through a messaging service; we have successfully decoupled the
-messaging logic required by Vaadin UIs from the component. Only the requirement
-for using the event qualifier remains (notice that its use is not checked at
-compile time).
-
-(((range="endofrange", startref="term.advanced.cdi.events.broadcasting")))
-
-(((range="endofrange", startref="term.advanced.cdi.events")))
-endif::web[]
-
-(((range="endofrange", startref="term.advanced.cdi.cdilong")))
-(((range="endofrange", startref="term.advanced.cdi.cdi")))
-(((range="endofrange", startref="term.advanced.cdi.cdiaddon")))
-
-