You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

advanced-cdi.asciidoc 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. ---
  2. title: Vaadin CDI Add-on
  3. order: 17
  4. layout: page
  5. ---
  6. [[advanced.cdi]]
  7. = Vaadin CDI Add-on
  8. ((("Contexts and Dependency Injection", id="term.advanced.cdi.cdilong", range="startofrange")))
  9. ((("CDI", id="term.advanced.cdi.cdi", range="startofrange")))
  10. ((("Vaadin CDI Add-on", id="term.advanced.cdi.cdiaddon", range="startofrange")))
  11. Vaadin CDI add-on makes it easier to use contexts and dependency injection (CDI)
  12. in Vaadin applications. CDI is a Java EE feature especially targeted for web
  13. applications, which have well-defined contextual scopes, such as sessions,
  14. views, requests, and so forth. The lifecycle of objects, such as beans, can be
  15. managed by binding their lifecycles to such contexts. Vaadin CDI enables these
  16. features with two additional kinds of Vaadin-specific contextual scopes: UIs and
  17. navigation views.
  18. To learn more about Vaadin CDI, the link:[Vaadin CDI Tutorial] gives a hands-on
  19. introduction. The source code of the CDI Tutorial demo is available for browsing
  20. or cloning at https://github.com/vaadin/cdi-tutorial.
  21. [[advanced.cdi.cdi]]
  22. == CDI Overview
  23. Contexts and dependency injection, defined in the JSR-299 standard, is a Java EE
  24. feature that, through a set of services, helps in improving application
  25. architecture by decoupling the management of service object lifecycles from
  26. client objects using them. The lifecycle of objects stored in a CDI container is
  27. defined by a context. The managed objects or beans are accessed using dependency
  28. injection.
  29. CDI builds on the Java concept of beans, but with somewhat different definition
  30. and requirements.
  31. Regarding general CDI topics, such as use of qualifiers, interceptors,
  32. decorators, event notifications, and other CDI features, we refer you to CDI
  33. documentation.
  34. ifdef::web[]
  35. * link:http://jaxenter.com/tutorial-introduction-to-cdi-contexts-and-dependency-injection-for-java-ee-jsr-299-104536.html[Introduction
  36. to CDI]. Pete Muir and Mark Struberg, JAXenter.
  37. * link:http://docs.jboss.org/weld/reference/latest/en-US/html_single/[Weld - CDI
  38. Reference Implementation]
  39. * link:http://cdi-spec.org/[CDI Specification]
  40. * link:https://vaadin.com/docs/v8/framework/articles/VaadinCDI.html[Vaadin
  41. CDI Tutorial]
  42. endif::web[]
  43. [[advanced.cdi.cdi.injection]]
  44. === Dependency Injection
  45. __Dependency injection__ is a way to pass dependencies (service objects) to
  46. dependent objects (clients) by injecting them in member variables or initializer
  47. parameters, instead of managing the lifecycle in the clients or passing them
  48. explicitly as parameters. In CDI, injection of a service object to a client is
  49. specified by the [classname]#@Inject# annotation.
  50. For example, if we have a UI view that depends on user data, we could inject the
  51. data in the client as follows:
  52. [source, java]
  53. ----
  54. public class MainView extends CustomComponent implements View {
  55. @Inject
  56. User user;
  57. ...
  58. @Override
  59. public void enter(ViewChangeEvent event) {
  60. greeting.setValue("Hello, " + user.getName());
  61. }
  62. }
  63. ----
  64. In addition to injecting managed beans with the annotation, you can query for
  65. them from the bean manager.
  66. [[advanced.cdi.cdi.contexts]]
  67. === Contexts and Scopes
  68. __Contexts__ in CDI are services that manage the lifecycle of objects and handle
  69. their injection. Generally speaking, a context is a situation in which an
  70. instance is used with a unique identity. Such objects are essentially
  71. "singletons" in the context. While conventional singletons are application-wide,
  72. objects managed by a CDI container can be "singletons" in a more narrow
  73. __scope__: a user session, a particular UI instance associated with the session,
  74. a view within the UI, or even just a single request. Such a context defines the
  75. lifecycle of the object: its creation, use, and finally its destruction.
  76. As a very typical example in a web application, you would have a user data
  77. object associated with a user session.
  78. [source, java]
  79. ----
  80. @SessionScoped
  81. public class User {
  82. private String name;
  83. public void setName(String name) {this.name = name;}
  84. public String getName() {return name;}
  85. }
  86. ----
  87. Now, when you need to refer to the user, you can use CDI injection to inject the
  88. session-scoped "singleton" to a member variable or a constructor parameter.
  89. [source, java]
  90. ----
  91. public class MainView extends CustomComponent implements View {
  92. @Inject
  93. User user;
  94. ...
  95. @Override
  96. public void enter(ViewChangeEvent event) {
  97. greeting.setValue("Hello, " + user.getName());
  98. }
  99. }
  100. ----
  101. [[advanced.cdi.installation]]
  102. == Installing Vaadin CDI Add-on
  103. Vaadin CDI requires a Java EE 7 compatible servlet container, such as Glassfish
  104. or Apache TomEE Web Profile, as mentioned for the reference toolchain in
  105. <<../getting-started/getting-started-environment#getting-started.environment,"Setting
  106. up the Development Environment">>.
  107. To install the Vaadin CDI add-on, either define it as an Ivy or Maven dependency
  108. or download it from the Vaadin Directory add-on page at
  109. <<,vaadin.com/directory#addon/vaadin-cdi>>. See
  110. <<../addons/addons-overview.asciidoc#addons.overview,"Using
  111. Vaadin Add-ons">> for general instructions for installing and using Vaadin
  112. add-ons.
  113. The Ivy dependency is as follows:
  114. [subs="normal"]
  115. ----
  116. &lt;dependency org="com.vaadin" name="vaadin-cdi"
  117. rev="[replaceable]#latest.release#"/&gt;
  118. ----
  119. The Maven dependency is as follows:
  120. [subs="normal"]
  121. ----
  122. &lt;dependency&gt;
  123. &lt;groupId&gt;com.vaadin&lt;/groupId&gt;
  124. &lt;artifactId&gt;vaadin-cdi&lt;/artifactId&gt;
  125. &lt;version&gt;[replaceable]#LATEST#&lt;/version&gt;
  126. &lt;/dependency&gt;
  127. &lt;dependency&gt;
  128. &lt;groupId&gt;javax.enterprise&lt;/groupId&gt;
  129. &lt;artifactId&gt;cdi-api&lt;/artifactId&gt;
  130. &lt;version&gt;[replaceable]#1.2#&lt;/version&gt;
  131. &lt;/dependency&gt;
  132. ----
  133. [[advanced.cdi.peparing]]
  134. == Preparing Application for CDI
  135. A Vaadin application that uses CDI must have a file named [filename]#beans.xml#
  136. in the [filename]#WEB-INF# directory. The file can be completely empty (it has
  137. content only in certain limited situations), but it must be present.
  138. The application should not have a servlet extending [classname]#VaadinServlet#,
  139. as Vaadin servlet has its own [classname]#VaadinCDIServlet# that is deployed
  140. automatically. If you need multiple servlets or need to customize the Vaadin CDI
  141. servlet, see <<advanced.cdi.deployment>>.
  142. [[advanced.cdi.cdiui]]
  143. == Injecting a UI with [classname]#@CDIUI#
  144. ((("[classname]#@CDIUI#", id="term.advanced.cdi.cdiui", range="startofrange")))
  145. Vaadin CDI offers an easier way to instantiate UIs and to define the URL mapping
  146. for them than the usual ways described in
  147. <<../application/application-environment#application.environment,"Deploying
  148. an Application">>. To define a UI class that should be instantiated for a given
  149. URL, you simply need to annotate the class with [classname]#@CDIUI#. It takes an
  150. optional URL path as parameter.
  151. [source, java]
  152. ----
  153. @CDIUI("myniceui")
  154. @Theme("valo")
  155. public class MyNiceUI extends UI {
  156. ...
  157. ----
  158. Giving empty UI path maps the UI to the root of the application context.
  159. [source, java]
  160. ----
  161. @CDIUI("")
  162. ----
  163. If the optional UI path is not given, the path is determined automatically from
  164. the class name by removing a possible "-UI" suffix in the class name, making it
  165. lower-case, and for capitalized letters, a hyphen is added. For example, a UI
  166. with class name [classname]#MyNiceUI# would have path [literal]#++my-nice++#.
  167. The URL consists of the server address, application context, and the UI path.
  168. For example, when running a Vaadin application in a development workstation, you
  169. would have URL such as http://localhost:8080/myproject/my-nice.
  170. UI path mappings are reported in the server log during deployment.
  171. See <<advanced.cdi.deployment>> for how to handle servlet URL mapping of CDI UIs
  172. when working with multiple servlets in the same web application.
  173. (((range="endofrange", startref="term.advanced.cdi.cdiui")))
  174. [[advanced.cdi.scopes]]
  175. == Scopes
  176. ((("CDI", "scopes", id="term.advanced.cdi.scopes", range="startofrange")))
  177. As in programming languages, where a variable name refers to a unique object
  178. within the scope of the variable, a CDI scope is a context in which an object
  179. has unique identity. In CDI, objects to be injected are identified by their type
  180. and any qualifiers they may have. The scope can be defined as an annotation to
  181. the service class as follows:
  182. [source, java]
  183. ----
  184. @SessionScoped
  185. public class User {
  186. ...
  187. ----
  188. CDI defines a number of scopes. Note that the standard CDI scopes are defined
  189. under the [package]#javax.enterprise.context# package and Vaadin CDI scopes
  190. under [package]#com.vaadin.cdi#, while JSF scopes are defined in
  191. [package]#javax.faces.bean#.
  192. [[advanced.cdi.scopes.ui]]
  193. === UI Scope
  194. UI-scoped beans are uniquely identified within a UI instance, that is, a browser
  195. window or tab.
  196. Vaadin CDI provides two annotations for the UI scope, differing in how they
  197. enable proxies, as explained later.
  198. [classname]#@UIScoped#([package]#com.vaadin.cdi#):: ((("[classname]#@UIScoped#", id="term.advanced.cdi.scopes.uiscoped", range="startofrange")))
  199. +
  200. Injection with this annotation will create a direct reference to the bean rather
  201. than a proxy. There are some limitations when not using proxies. Circular
  202. references (injecting A to B and B to A) will not work, and neither do CDI
  203. interceptors and decorators.
  204. (((range="endofrange", startref="term.advanced.cdi.scopes.uiscoped")))
  205. [classname]#@NormalUIScoped#([package]#com.vaadin.cdi#):: As [classname]#@UIScoped#, but injecting a managed bean having this annotation
  206. injects a proxy for the bean instead of a direct reference. This is the normal
  207. behaviour with CDI, as many CDI features utilize the proxy.
  208. Defining a CDI view (annotated with [classname]#@CDIView# as described later) as
  209. [classname]#@UIScoped# makes the view retain the same instance when the user
  210. navigates away and back to the view.
  211. [[advanced.cdi.scopes.view]]
  212. === View Scopes
  213. The lifecycle of a view-scoped bean starts when the user navigates to a view
  214. referring to the object and ends when the user navigates out of the view (or
  215. when the UI is closed or expires).
  216. Vaadin CDI provides two annotations for the view scope, differing in how they
  217. enable proxies, as explained later.
  218. [classname]#@ViewScoped#([package]#com.vaadin.cdi#):: Injection with this annotation will create a direct reference to the bean rather
  219. than a proxy. There are some limitations when not using proxies. Circular
  220. references (injecting A to B and B to A) will not work, and neither do CDI
  221. interceptors and decorators.
  222. [classname]#@NormalViewScoped#([package]#com.vaadin.cdi#):: As [classname]#@NormalScoped#, except that injecting with this annotation will
  223. create a proxy for the contextual instance rather than provide the contextual
  224. instance itself. See the explanation of proxies below.
  225. [[advanced.cdi.scopes.cdi]]
  226. === Standard CDI Scopes
  227. [classname]#@ApplicationScoped#:: ((("[classname]#@ApplicationScoped#", id="term.advanced.cdi.scopes.applicationscoped", range="startofrange")))
  228. +
  229. Application-scoped beans are shared by all servlets in the web application, and
  230. are essentially equal to singletons.//TODO This is just a guess - is it
  231. true?
  232. Note that referencing application-scoped beans is not thread-safe and access
  233. must be synchronized.
  234. (((range="endofrange", startref="term.advanced.cdi.scopes.applicationscoped")))
  235. [classname]#@SessionScoped#:: ((("[classname]#@SessionScoped#", id="term.advanced.cdi.scopes.sessionscoped", range="startofrange")))
  236. +
  237. The lifecycle and visibility of session-scoped beans is bound to a HTTP or user
  238. session, which in Vaadin applications is associated with the
  239. [classname]#VaadinSession# (see
  240. <<../application/application-lifecycle#application.lifecycle.session,"User
  241. Session">>). This is a very typical scope to store user data, as is done in many
  242. examples in this section, or database connections. The lifecycle of
  243. session-scoped beans starts when a user opens the page for a UI in the browser,
  244. and ends when the session expires after the last UI in the session is closed.
  245. (((range="endofrange", startref="term.advanced.cdi.scopes.sessionscoped")))
  246. [[advanced.cdi.scopes.proxies]]
  247. === Proxies vs Direct References
  248. CDI uses proxy objects to enable many of the CDI features, by hooking into
  249. message-passing from client to service beans. Under the hood, a proxy is an
  250. instance of an automatically generated class that extends the proxied bean type,
  251. so communicating through a proxy occurs transparently, as it has the same
  252. polymorphic type as the actual bean. Whether proxying is enabled or not is
  253. defined in the scope: CDI scopes are either __normal scopes__, which can be
  254. proxied, or __pseudoscopes__, which use direct references to injected beans.
  255. The proxying mechanism creates some requirements for injecting objects in normal
  256. scope:
  257. * The objects may not be primitive types or arrays
  258. * The bean class must not be final
  259. * The bean class must not have final methods
  260. Beans annotated with [classname]#@UIScoped# or [classname]#@ViewScoped# use a
  261. pseudoscope, and are therefore injected with direct references to the bean
  262. instances, while [classname]#@NormalUIScoped# and [classname]#@NormalViewScoped#
  263. beans will use a proxy for communicating with the beans.
  264. When using proxies, be aware that it is not guaranteed that the
  265. [methodname]#hashCode()# or [methodname]#equals()# will match when comparing a
  266. proxy to its underlying instance. It is imperative to be aware of this when, for
  267. example, adding proxies to a [interfacename]#Collection#.
  268. You should avoid using normal scopes with Vaadin components, as proxies may not
  269. work correctly within the Vaadin framework. If Vaadin CDI plugin detects such
  270. use, it displays a warning such as the following:
  271. ----
  272. INFO: The following Vaadin components are injected
  273. into normal scoped contexts:
  274. @NormalUIScoped org.example.User
  275. This approach uses proxy objects and has not been
  276. extensively tested with the framework. Please report
  277. any unexpected behavior. Switching to a pseudo-scoped
  278. context may also resolve potential issues.
  279. ----
  280. (((range="endofrange", startref="term.advanced.cdi.scopes")))
  281. [[advanced.cdi.deployment]]
  282. == Deploying CDI UIs and Servlets
  283. Vaadin CDI hooks into Vaadin framework by using a special
  284. [classname]#VaadinCDIServlet#. As described earlier, you do not need to map an
  285. URL path to a UI, as it is handled by Vaadin CDI. However, in the following, we
  286. go through some cases where you need to customize the servlet or use CDI with
  287. non-CDI servlets and UIs in a web application.
  288. [[advanced.cdi.deployment.urlmapping]]
  289. === Defining Servlet Root with [classname]#@URLMapping#
  290. CDI UIs are managed by a CDI servlet ( [classname]#VaadinCDIServlet#), which is
  291. by default mapped to the root of the application context. For example, if the
  292. name of a CDI UI is " [literal]#++my-cdi++#" and application context is
  293. [literal]#++/myproject++#, the UI would by default have URL "
  294. [literal]#++/myproject/my-cdi++#". If you do not want to have the servlet mapped
  295. to context root, you can use the [classname]#@URLMapping# annotation to map all
  296. CDI UIs to a sub-path. The annotation must be given to only one CDI UI, usually
  297. the one with the default ("") path.
  298. For example, if we have a root UI and another:
  299. [source, java]
  300. ----
  301. @CDIUI("") // At CDI servlet root
  302. @URLMapping("mycdiuis") // Define CDI Servlet root
  303. public class MyCDIRootUI extends UI {...}
  304. @CDIUI("another")
  305. public class AnotherUI extends UI {...}
  306. ----
  307. These two UIs would have URLs /myproject/mycdiuis and
  308. /myproject/mycdiuis/another, respectively.
  309. You can also map the CDI servlet to another URL in servlet definition in
  310. [filename]#web.xml#, as described the following.
  311. [[advanced.cdi.servlets.mixing]]
  312. === Mixing With Other Servlets
  313. The [classname]#VaadinCDIServlet# is normally used as the default servlet, but
  314. if you have other servlets in the application, such as for non-CDI UIs, you need
  315. to define the CDI servlet explicitly in the [filename]#web.xml#. You can map the
  316. servlet to any URL path, but perhaps typically, you define it as the default
  317. servlet as follows, and map the other servlets to other URL paths:
  318. [subs="normal"]
  319. ----
  320. &lt;web-app&gt;
  321. ...
  322. &lt;servlet&gt;
  323. &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
  324. &lt;servlet-class&gt;
  325. com.vaadin.cdi.internal.VaadinCDIServlet
  326. &lt;/servlet-class&gt;
  327. &lt;/servlet&gt;
  328. &lt;servlet-mapping&gt;
  329. &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
  330. &lt;url-pattern&gt;[replaceable]#/mycdiuis/*#&lt;/url-pattern&gt;
  331. &lt;/servlet-mapping&gt;
  332. &lt;servlet-mapping&gt;
  333. &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
  334. &lt;url-pattern&gt;/VAADIN/*&lt;/url-pattern&gt;
  335. &lt;/servlet-mapping&gt;
  336. &lt;/web-app&gt;
  337. ----
  338. With such a setting, paths to CDI UIs would have base path
  339. [filename]#/myapp/mycdiuis#, to which the (optional) UI path would be appended.
  340. The [filename]#/VAADIN/*# only needs to be mapped to the servlet if there are no
  341. other Vaadin servlets.
  342. [[advanced.cdi.servlets.custom]]
  343. === Custom Servlets
  344. When customizing the Vaadin servlet, as outlined in
  345. <<../application/application-lifecycle#application.lifecycle.servlet-service,"Vaadin
  346. Servlet, Portlet, and Service">>, you simply need to extend
  347. [classname]#com.vaadin.cdi.internal.VaadinCDIServlet# instead of
  348. [classname]#com.vaadin.servlet.VaadinServlet#.
  349. The custom servlet must not have [classname]#@WebServlet# annotation or
  350. [classname]#@VaadinServletConfiguration#, as you would normally with a Vaadin
  351. servlet, as described in
  352. <<../application/application-environment#application.environment,"Deploying
  353. an Application">>.
  354. ifdef::web[]
  355. [[advanced.cdi.navigation]]
  356. == View Navigation
  357. Vaadin CDI extends the navigation framework in Vaadin, described in
  358. <<../advanced/advanced-navigator#advanced.navigator,"Navigating
  359. in an Application">>. It manages CDI views with a special view provider and
  360. enables view scoping.
  361. [[advanced.cdi.navigation.ui]]
  362. === Preparing the UI
  363. You can define navigation for any single-component container, as described in
  364. <<advanced-navigator#advanced.navigator.navigating,"Setting
  365. Up for Navigation">>, but typically you set up navigation for the entire UI
  366. content. To use Vaadin CDI views, you need to inject a
  367. [classname]#CDIViewProvider# in the UI and add it as a provider for the
  368. navigator.
  369. [source, java]
  370. ----
  371. @CDIUI("mycdiui")
  372. public class MyCDIUI extends UI {
  373. @Inject
  374. CDIViewProvider viewProvider;
  375. @Override
  376. protected void init(VaadinRequest request) {
  377. Navigator navigator = new Navigator(this, this);
  378. navigator.addProvider(viewProvider);
  379. // Navigate to start view
  380. navigator.navigateTo("");
  381. }
  382. }
  383. ----
  384. [[advanced.cdi.navigation.view]]
  385. === The View
  386. A view managed by Vaadin CDI only needs to have the [classname]#@CDIView#
  387. annotation.
  388. [source, java]
  389. ----
  390. @CDIView("main")
  391. public class MainView extends CustomComponent implements View {
  392. ...
  393. ----
  394. The annotation can have the following optional paramers:
  395. value (optional):: Specifies the view name by which it can be accessed programmatically and by the
  396. URI fragment.
  397. +
  398. [source, java]
  399. ----
  400. @CDIView("main")
  401. ----
  402. +
  403. If other optional parameters are given, the value must be given by the named
  404. [parameter]#value# parameter.
  405. +
  406. If the view name is not given, it is derived from the class name by removing a
  407. possible "View" suffix, making it lower case, and using a dash ("-") to separate
  408. words originally denoted by capital letters. Thereby, a view class such as
  409. [classname]#MyFunnyView# would have name " [literal]#++my-funny++#".
  410. +
  411. You can navigate to a state with a URI fragment such as
  412. [literal]#++#!myview/someparameter++# or programmatically with:
  413. +
  414. [source, java]
  415. ----
  416. getUI().getNavigator().navigateTo("myview/someparameter");
  417. ----
  418. +
  419. The [methodname]#enter()# method of the view gets the URI fragment as parameter
  420. as is and can interpret it in any application-defined way.
  421. +
  422. Note that in this mode, matching a navigation state to a view is done by the
  423. prefix of the fragment! Thereby, no other views may start with the name of the
  424. view as prefix. For example, if the view name is " [literal]#++main++#", you
  425. must not have a view named " [literal]#++maintenance++#".
  426. uis:: If the application has multiple UIs that use [classname]#CDIViewProvider#, you
  427. can use this parameter to specify which UIs can show the view.
  428. +
  429. [source, java]
  430. ----
  431. @CDIView(value="myview", uis={MyCDIUI.class})
  432. ----
  433. +
  434. If the list contains [parameter]#UI.class#, the view is available to all UIs.
  435. +
  436. [source, java]
  437. ----
  438. @CDIView(value="myview", uis={UI.class})
  439. ----
  440. In the following, we have a login view that accesses a session-scoped user
  441. object. Here, we use a constant to define the view name, so that we can use the
  442. constant when navigating to it.
  443. [source, java]
  444. ----
  445. @CDIView(LoginView.VIEWNAME)
  446. public class LoginView extends CustomComponent
  447. implements View {
  448. public final static String VIEWNAME = "";
  449. // Here we inject to the constructor and actually do
  450. // not store the injected object to use it later
  451. @Inject
  452. public LoginView(User user) {
  453. VerticalLayout layout = new VerticalLayout();
  454. // An input field for editing injected data
  455. BeanItem<User> item = new BeanItem<User>(user);
  456. TextField username = new TextField("User name",
  457. item.getItemProperty("name"));
  458. username.setNullRepresentation("");
  459. layout.addComponent(username);
  460. // Login button (authentication omitted) / Java 8
  461. layout.addComponent(new Button("Login", e ->
  462. getUI().getNavigator().
  463. navigateTo(MainView.VIEWNAME)));
  464. setCompositionRoot(layout);
  465. }
  466. @Override
  467. public void enter(ViewChangeEvent event) {}
  468. }
  469. ----
  470. You could now navigate to the view from any other view in the UI with:
  471. [source, java]
  472. ----
  473. getUI().getNavigator().navigateTo(LoginView.VIEWNAME);
  474. ----
  475. endif::web[]
  476. ifdef::web[]
  477. [[advanced.cdi.events]]
  478. == CDI Events
  479. ((("CDI", "events", id="term.advanced.cdi.events", range="startofrange")))
  480. CDI events can be used for many purposes in Vaadin applications, such as passing
  481. messages between different parts of a view, between views, between UIs, or
  482. between users. Some cases require special consideration, such as when
  483. communicating between UIs and how injected components should be scoped.
  484. [[advanced.cdi.events.intro]]
  485. === Observing Events
  486. Let us consider a case where changes in one part of the UI (or view) require
  487. updating other parts of the UI. This is typical in master-detail views, for
  488. updating the master view after editing details, or when handling input from a
  489. sub-window. While you can handle such a situation with a custom call-back
  490. listener, CDI event mechanism simplifies the task.
  491. Let us consider the following simple UI containing two panels. The input panel
  492. will send events, which are received by other parts of the UI, in this case a
  493. display panel. The panels need to be injected to enable CDI event passing in
  494. them.
  495. [source, java]
  496. ----
  497. @CDIUI("cdievents")
  498. @Theme("valo")
  499. public class CDIEventUI extends UI {
  500. @Inject
  501. InputPanel inputPanel;
  502. @Inject
  503. DisplayPanel displayPanel;
  504. @Override
  505. protected void init(VaadinRequest request) {
  506. Layout content =
  507. new HorizontalLayout(inputPanel, displayPanel);
  508. setContent(content);
  509. }
  510. }
  511. ----
  512. Now, let us look closer at the sending panel. To send messages, it needs to
  513. inject a [classname]#javax.enterprise.event.Event# object. As we are injecting
  514. the event to a component class, we need to specify the full package name to
  515. avoid confusion with Vaadin [classname]#Component.Event#.
  516. [source, java]
  517. ----
  518. class InputPanel extends Panel {
  519. @Inject
  520. private javax.enterprise.event.Event<MyEvent> event;
  521. public InputPanel() {
  522. super("Input");
  523. TextField editor = new TextField();
  524. Button save = new Button("Save", e -> // Java 8
  525. event.fire(new MyEvent(editor.getValue())));
  526. setContent(new VerticalLayout(editor, save));
  527. }
  528. }
  529. ----
  530. Firing an event is done with the [methodname]#fire()# method on the injected
  531. event object. In our example, the event is as follows:
  532. [source, java]
  533. ----
  534. public class MyEvent implements Serializable {
  535. private String text;
  536. public MyEvent(String text) {
  537. this.text = text;
  538. }
  539. public String getName() {
  540. return text;
  541. }
  542. }
  543. ----
  544. The event is received by any method (in an injected object) marked by
  545. [classname]#@Observes# annotation for the event parameter to observe the event
  546. type.
  547. [source, java]
  548. ----
  549. @UIScoped
  550. class DisplayPanel extends Panel {
  551. Label display = new Label("-nothing to display-");
  552. public DisplayPanel() {
  553. super("Display");
  554. setContent(display);
  555. }
  556. void myEventObserver(@Observes MyEvent event) {
  557. display.setValue("Observed: " + event.getName());
  558. }
  559. }
  560. ----
  561. Such a component that observes events from other components must be scoped to
  562. the UI or view, as otherwise it will be request-scoped and a new instance is
  563. created for receiving each event.
  564. The UI with interaction is shown in <<figure.advanced.cdi.events.intro>>.
  565. [[figure.advanced.cdi.events.intro]]
  566. .Observing CDI Events
  567. image::img/cdi-events-observing.png[]
  568. Any injection qualifiers defined for the event object in the sender are matched
  569. in the observers, which feature we will use later to avoid receiving unwanted
  570. events.
  571. [[advanced.cdi.events.broadcasting]]
  572. === Communicating Between UIs
  573. ((("broadcasting", id="term.advanced.cdi.events.broadcasting", range="startofrange")))
  574. CDI events are not propagated to inactive contexts, and only the context of the
  575. currently processed UI is active. Further, as explained in
  576. <<advanced-push#advanced.push.running,"Accessing
  577. UI from Another Thread">>, other Vaadin UIs may not be accessed without proper
  578. synchronization, as their requests are processed concurrently in different
  579. server threads. Therefore, you need to pass the events through an
  580. application-scoped messaging service and synchronize the access to other UIs by
  581. using the [methodname]#access()# method.
  582. In
  583. <<advanced-push#advanced.push.pusharound,"Broadcasting
  584. to Other Users">> we looked into how to pass messages to all other UIs using a
  585. broadcasting service. In that example, we used static variables and methods to
  586. store references and to access the service. With CDI, we can let the context
  587. manage its lifecycle, access it by injection, and pass messages by CDI events.
  588. By scoping the messaging service to application, we essentially make it a
  589. singleton.
  590. [source, java]
  591. ----
  592. @ApplicationScoped
  593. public class CDIBroadcaster implements Serializable {
  594. ----
  595. As we can not let CDI deliver the messages, the messaging service needs to keep
  596. book of the messaging clients (UIs) waiting to receive messages.
  597. [source, java]
  598. ----
  599. private Collection<UI> uis = new HashSet<UI>();
  600. public synchronized void register(UI listener) {
  601. uis.add(listener);
  602. }
  603. public synchronized void unregister(UI listener) {
  604. uis.remove(listener);
  605. }
  606. ----
  607. The main logic of the messaging service is to observe messages and fire them in
  608. the recipient UIs. As we are broadcasting to all UIs here, we again use an
  609. executor service to execute the code. To lock on the session when accessing the
  610. UIs, we use the [methodname]#access()# method.
  611. [source, java]
  612. ----
  613. // Inject event to be fired
  614. @Inject
  615. private javax.enterprise.event.Event<BroadcastMessage>
  616. messageEvent;
  617. ExecutorService executorService =
  618. Executors.newSingleThreadExecutor();
  619. // Observe messages (only from clients)
  620. @SuppressWarnings("unused")
  621. private synchronized void observeMessage(
  622. @Observes @OriginalSender
  623. final BroadcastMessage message) {
  624. for (final UI listener: uis)
  625. executorService.execute(() ->
  626. listener.access(()->
  627. messageEvent.fire(message)));
  628. }
  629. }
  630. ----
  631. Here we use a [classname]#@OriginalSender# qualifier to receive events only from
  632. a client (original sender), not from the messaging service itself, which would
  633. cause an infinite event loop. The qualifier is defined as follows:
  634. ((("CDI", "qualifiers")))
  635. [source, java]
  636. ----
  637. @Qualifier
  638. @Retention(RUNTIME)
  639. @Target({PARAMETER, FIELD})
  640. public @interface OriginalSender {}
  641. ----
  642. The message type is a simple POJO as follows:
  643. [source, java]
  644. ----
  645. public class BroadcastMessage {
  646. private String text;
  647. private Object sender; // For checking if sent by self
  648. ... constructor, getters, and setters ...
  649. }
  650. ----
  651. Let us take a look at the UI class, which manages both the messaging service and
  652. the client components. The UI just needs to register itself in the messaging
  653. service and build the UI, including the UI components doing messaging. We could,
  654. of course, do that also at view level.
  655. ((("[classname]#@Push#")))
  656. [source, java]
  657. ----
  658. @CDIUI("cdichat")
  659. @Push
  660. public class CDIChatUI extends UI {
  661. @Inject
  662. CDIBroadcaster broadcaster;
  663. @Inject
  664. ChatBox chatbox;
  665. @Override
  666. protected void init(VaadinRequest request) {
  667. setContent(chatbox);
  668. // Register to receive broadcasts
  669. broadcaster.register(this);
  670. }
  671. // Must also unregister when the UI expires or is closed
  672. @Override
  673. public void detach() {
  674. broadcaster.unregister(this);
  675. super.detach();
  676. }
  677. }
  678. ----
  679. Now for an actual messaging client, we look at the chat box component. Most of
  680. the UI code is omitted from the example. As noted earlier, the component
  681. receiving events must be scoped to the UI, to avoid creation of invalid
  682. instances.
  683. ((("[classname]#@UIScoped#")))
  684. [source, java]
  685. ----
  686. @UIScoped
  687. class ChatBox extends CustomComponent {
  688. VerticalLayout messages = new VerticalLayout();
  689. public ChatBox(CDIChatUI cdiChatUI) {
  690. ... build the composite ...
  691. TextField input = new TextField();
  692. Button send = new Button("Send", e -> { // Java 8
  693. // Broadcast the input
  694. broadcast(input.getValue());
  695. addMessage(input.getValue()); // Add to self
  696. });
  697. ...
  698. }
  699. @Inject
  700. @OriginalSender
  701. private javax.enterprise.event.Event<BroadcastMessage>
  702. messageEvent;
  703. // Sends a message
  704. private void broadcast(String msg) {
  705. messageEvent.fire(new BroadcastMessage(msg, this));
  706. }
  707. // Receives messages
  708. @SuppressWarnings("unused")
  709. private void observeMessage(
  710. @Observes BroadcastMessage event) {
  711. if (event.getSender() != this)
  712. addMessage(event.getText());
  713. }
  714. private void addMessage(String msg) {
  715. messages.addComponent(new Label(msg));
  716. }
  717. }
  718. ----
  719. ((("CDI", "qualifiers")))
  720. Note that the client object is completely unaware of the fact that the messages
  721. are delivered through a messaging service; we have successfully decoupled the
  722. messaging logic required by Vaadin UIs from the component. Only the requirement
  723. for using the event qualifier remains (notice that its use is not checked at
  724. compile time).
  725. (((range="endofrange", startref="term.advanced.cdi.events.broadcasting")))
  726. (((range="endofrange", startref="term.advanced.cdi.events")))
  727. endif::web[]
  728. (((range="endofrange", startref="term.advanced.cdi.cdilong")))
  729. (((range="endofrange", startref="term.advanced.cdi.cdi")))
  730. (((range="endofrange", startref="term.advanced.cdi.cdiaddon")))