From 99d6de546c74f0eed230ea8253dda6b85109d2e7 Mon Sep 17 00:00:00 2001 From: Markus Koivisto Date: Fri, 22 Jan 2016 14:55:18 +0200 Subject: Add documentation to master branch Change-Id: I2504bb10f1ae73ec0cbc08b7ba5a88925caa1674 --- .../advanced/advanced-architecture.asciidoc | 298 ++ documentation/advanced/advanced-cdi.asciidoc | 997 +++++++ documentation/advanced/advanced-debug.asciidoc | 208 ++ documentation/advanced/advanced-dragndrop.asciidoc | 567 ++++ documentation/advanced/advanced-embedding.asciidoc | 460 +++ documentation/advanced/advanced-gae.asciidoc | 71 + documentation/advanced/advanced-global.asciidoc | 234 ++ .../advanced/advanced-javascript.asciidoc | 109 + documentation/advanced/advanced-logging.asciidoc | 137 + documentation/advanced/advanced-navigator.asciidoc | 289 ++ documentation/advanced/advanced-printing.asciidoc | 181 ++ documentation/advanced/advanced-push.asciidoc | 429 +++ .../advanced/advanced-requesthandler.asciidoc | 96 + documentation/advanced/advanced-security.asciidoc | 56 + documentation/advanced/advanced-shortcuts.asciidoc | 287 ++ documentation/advanced/advanced-spring.asciidoc | 696 +++++ documentation/advanced/advanced-urifu.asciidoc | 191 ++ documentation/advanced/advanced-windows.asciidoc | 180 ++ documentation/advanced/chapter-advanced.asciidoc | 41 + .../advanced/img/cdi-events-observing.png | Bin 0 -> 19007 bytes .../advanced/img/debug-hierarchy-tree.png | Bin 0 -> 13313 bytes documentation/advanced/img/debug-info.png | Bin 0 -> 22980 bytes documentation/advanced/img/debug-log-hi.png | Bin 0 -> 98079 bytes documentation/advanced/img/debug-log-lo.png | Bin 0 -> 37714 bytes .../advanced/img/debug-window-analyze-layouts.png | Bin 0 -> 17689 bytes .../advanced/img/debug-window-annotated-hi.png | Bin 0 -> 130028 bytes .../advanced/img/debug-window-annotated-lo.png | Bin 0 -> 41306 bytes documentation/advanced/img/debug-window.png | Bin 0 -> 26203 bytes documentation/advanced/img/embedding3.png | Bin 0 -> 43245 bytes documentation/advanced/img/mvp-pattern-hi.png | Bin 0 -> 157569 bytes documentation/advanced/img/mvp-pattern-lo.png | Bin 0 -> 37049 bytes documentation/advanced/img/navigator-mainview.png | Bin 0 -> 73454 bytes .../advanced/img/shortcut-defaultbutton.png | Bin 0 -> 19282 bytes .../advanced/img/threadlocal-concurrency-hi.png | Bin 0 -> 113309 bytes .../advanced/img/threadlocal-concurrency-lo.png | Bin 0 -> 29835 bytes .../advanced/img/threadlocal-sequentiality-hi.png | Bin 0 -> 72594 bytes .../advanced/img/threadlocal-sequentiality-lo.png | Bin 0 -> 18502 bytes documentation/advanced/img/urifu-1.png | Bin 0 -> 14828 bytes .../advanced/img/window-polling-example1.png | Bin 0 -> 19684 bytes documentation/advanced/img/windows-popup.png | Bin 0 -> 33219 bytes .../original-drawings/cdi-events-messaging.svg | 2926 ++++++++++++++++++++ .../advanced/original-drawings/debug-log.svg | 424 +++ .../original-drawings/debug-window-annotated.svg | 608 ++++ .../advanced/original-drawings/mvp-pattern.svg | 832 ++++++ .../original-drawings/threadlocal-concurrency.svg | 1142 ++++++++ .../threadlocal-sequentiality.svg | 980 +++++++ 46 files changed, 12439 insertions(+) create mode 100644 documentation/advanced/advanced-architecture.asciidoc create mode 100644 documentation/advanced/advanced-cdi.asciidoc create mode 100644 documentation/advanced/advanced-debug.asciidoc create mode 100644 documentation/advanced/advanced-dragndrop.asciidoc create mode 100644 documentation/advanced/advanced-embedding.asciidoc create mode 100644 documentation/advanced/advanced-gae.asciidoc create mode 100644 documentation/advanced/advanced-global.asciidoc create mode 100644 documentation/advanced/advanced-javascript.asciidoc create mode 100644 documentation/advanced/advanced-logging.asciidoc create mode 100644 documentation/advanced/advanced-navigator.asciidoc create mode 100644 documentation/advanced/advanced-printing.asciidoc create mode 100644 documentation/advanced/advanced-push.asciidoc create mode 100644 documentation/advanced/advanced-requesthandler.asciidoc create mode 100644 documentation/advanced/advanced-security.asciidoc create mode 100644 documentation/advanced/advanced-shortcuts.asciidoc create mode 100644 documentation/advanced/advanced-spring.asciidoc create mode 100644 documentation/advanced/advanced-urifu.asciidoc create mode 100644 documentation/advanced/advanced-windows.asciidoc create mode 100644 documentation/advanced/chapter-advanced.asciidoc create mode 100644 documentation/advanced/img/cdi-events-observing.png create mode 100644 documentation/advanced/img/debug-hierarchy-tree.png create mode 100644 documentation/advanced/img/debug-info.png create mode 100644 documentation/advanced/img/debug-log-hi.png create mode 100644 documentation/advanced/img/debug-log-lo.png create mode 100644 documentation/advanced/img/debug-window-analyze-layouts.png create mode 100644 documentation/advanced/img/debug-window-annotated-hi.png create mode 100644 documentation/advanced/img/debug-window-annotated-lo.png create mode 100644 documentation/advanced/img/debug-window.png create mode 100644 documentation/advanced/img/embedding3.png create mode 100644 documentation/advanced/img/mvp-pattern-hi.png create mode 100644 documentation/advanced/img/mvp-pattern-lo.png create mode 100644 documentation/advanced/img/navigator-mainview.png create mode 100644 documentation/advanced/img/shortcut-defaultbutton.png create mode 100644 documentation/advanced/img/threadlocal-concurrency-hi.png create mode 100644 documentation/advanced/img/threadlocal-concurrency-lo.png create mode 100644 documentation/advanced/img/threadlocal-sequentiality-hi.png create mode 100644 documentation/advanced/img/threadlocal-sequentiality-lo.png create mode 100644 documentation/advanced/img/urifu-1.png create mode 100644 documentation/advanced/img/window-polling-example1.png create mode 100644 documentation/advanced/img/windows-popup.png create mode 100644 documentation/advanced/original-drawings/cdi-events-messaging.svg create mode 100644 documentation/advanced/original-drawings/debug-log.svg create mode 100644 documentation/advanced/original-drawings/debug-window-annotated.svg create mode 100644 documentation/advanced/original-drawings/mvp-pattern.svg create mode 100644 documentation/advanced/original-drawings/threadlocal-concurrency.svg create mode 100644 documentation/advanced/original-drawings/threadlocal-sequentiality.svg (limited to 'documentation/advanced') diff --git a/documentation/advanced/advanced-architecture.asciidoc b/documentation/advanced/advanced-architecture.asciidoc new file mode 100644 index 0000000000..437c6f4a1d --- /dev/null +++ b/documentation/advanced/advanced-architecture.asciidoc @@ -0,0 +1,298 @@ +--- +title: Advanced Application Architectures +order: 10 +layout: page +--- + +[[advanced.architecture]] += Advanced Application Architectures + +In this section, we continue from the basic application architectures described +in +<> and discuss some of the more advanced patterns that are often used in +Vaadin applications. + +[[advanced.architecture.layering]] +== Layered Architectures + +Layered architectures, where each layer has a clearly distinct responsibility, +are probably the most common architectures. Typically, applications follow at +least a three-layer architecture: + +* User interface (or presentation) layer +* Domain layer +* Data store layer + +Such an architecture starts from a __domain model__, which defines the data +model and the "business logic" of the application, typically as beans or POJOs. +A user interface is built on top of the domain model, in our context with the +Vaadin Framework. The Vaadin user interface could be bound directly to the data +model through the Vaadin Data Model, described in +<>. Beneath the domain model lies a data store, such as a +relational database. The dependencies between the layers are restricted so that +a higher layer may depend on a lower one, but never the other way around. + +[[figure.advanced.architecture.layering]] +.Three-Layer Architecture +image::img/three-layer-architecture-hi.png[] + +An __application layer__ (or __service layer__) is often distinguished from the +domain layer, offering the domain logic as a service, which can be used by the +user interface layer, as well as for other uses. In Java EE development, +Enterprise JavaBeans (EJBs) are typically used for building this layer. + +An __infrastructure layer__ (or __data access layer__) is often distinguished +from the data store layer, with a purpose to abstract the data store. For +example, it could involve a persistence solution such as JPA and an EJB +container. This layer becomes relevant with Vaadin when binding Vaadin +components to data with the JPAContainer, as described in +<>. + + +[[advanced.architecture.mvp]] +== Model-View-Presenter Pattern + +The Model-View-Presenter (MVP) pattern is one of the most common patterns in +developing large applications with Vaadin. It is similar to the older +Model-View-Controller (MVC) pattern, which is not as meaningful in Vaadin +development. Instead of an implementation-aware controller, there is an +implementation-agnostic presenter that operates the view through an interface. +The view does not interact directly with the model. This isolates the view +implementation better than in MVC and allows easier unit testing of the +presenter and model. + +[[figure.advanced.architecture.mvp]] +.Model-View-Presenter Pattern +image::img/mvp-pattern-hi.png[] + +<> illustrates the MVP pattern with a simple +calculator. The domain model is realized in the [classname]#Calculator# class, +which includes a data model and some model logic operations. The +[classname]#CalculatorViewImpl# is a Vaadin implementation of the view, defined +in the [interfacename]#CalculatorView# interface. The +[classname]#CalculatorPresenter# handles the user interface logic. User +interaction events received in the view are translated into +implementation-independent events for the presenter to handle (the view +implementation could also just call the presenter). + +Let us first look how the model and view are bound together by the presenter in +the following example: + + +[source, java] +---- + +// Create the model and the Vaadin view implementation +CalculatorModel model = new CalculatorModel(); +CalculatorViewImpl view = new CalculatorViewImpl(); + +// The presenter binds the model and view together +new CalculatorPresenter(model, view); + +// The view implementation is a Vaadin component +layout.addComponent(view); +---- + +You could add the view anywhere in a Vaadin application, as it is a composite +component. + +[[advanced.architecture.mvp.model]] +=== The Model + +Our business model is quite simple, with one value and a number of operations +for manipulating it. + + +[source, java] +---- +/** The model **/ +class CalculatorModel { + private double value = 0.0; + + public void clear() { + value = 0.0; + } + + public void add(double arg) { + value += arg; + } + + public void multiply(double arg) { + value *= arg; + } + + public void divide(double arg) { + if (arg != 0.0) + value /= arg; + } + + public double getValue() { + return value; + } + + public void setValue(double value) { + this.value = value; + } +} +---- + + +[[advanced.architecture.mvp.view]] +=== The View + +The purpose of the view in MVP is to display data and receive user interaction. +It relays the user interaction to the presenter in an fashion that is +independent of the view implementation, that is, no Vaadin events. It is defined +as a UI framework interface that can have multiple implementations. + + +[source, java] +---- +interface CalculatorView { + public void setDisplay(double value); + + interface CalculatorViewListener { + void buttonClick(char operation); + } + public void addListener(CalculatorViewListener listener); +} +---- + +The are design alternatives for the view. It could receive the listener in its +constructor, or it could just know the presenter. Here, we forward button clicks +as an implementation-independent event. + +As we are using Vaadin, we make a Vaadin implementation of the interface as +follows: + + +[source, java] +---- +class CalculatorViewImpl extends CustomComponent + implements CalculatorView, ClickListener { + private Label display = new Label("0.0"); + + public CalculatorViewImpl() { + GridLayout layout = new GridLayout(4, 5); + + // Create a result label that spans over all + // the 4 columns in the first row + layout.addComponent(display, 0, 0, 3, 0); + + // The operations for the calculator in the order + // they appear on the screen (left to right, top + // to bottom) + String[] operations = new String[] { + "7", "8", "9", "/", "4", "5", "6", + "*", "1", "2", "3", "-", "0", "=", "C", "+" }; + + // Add buttons and have them send click events + // to this class + for (String caption: operations) + layout.addComponent(new Button(caption, this)); + + setCompositionRoot(layout); + } + + public void setDisplay(double value) { + display.setValue(Double.toString(value)); + } + + /* Only the presenter registers one listener... */ + List listeners = + new ArrayList(); + + public void addListener(CalculatorViewListener listener) { + listeners.add(listener); + } + + /** Relay button clicks to the presenter with an + * implementation-independent event */ + @Override + public void buttonClick(ClickEvent event) { + for (CalculatorViewListener listener: listeners) + listener.buttonClick(event.getButton() + .getCaption().charAt(0)); + } +} +---- + + +[[advanced.architecture.mvp.presenter]] +=== The Presenter + +The presenter in MVP is a middle-man that handles all user interaction logic, +but in an implementation-independent way, so that it doesn't actually know +anything about Vaadin. It shows data in the view and receives user interaction +back from it. + + +[source, java] +---- +class CalculatorPresenter + implements CalculatorView.CalculatorViewListener { + CalculatorModel model; + CalculatorView view; + + private double current = 0.0; + private char lastOperationRequested = 'C'; + + public CalculatorPresenter(CalculatorModel model, + CalculatorView view) { + this.model = model; + this.view = view; + + view.setDisplay(current); + view.addListener(this); + } + + @Override + public void buttonClick(char operation) { + // Handle digit input + if ('0' <= operation && operation <= '9') { + current = current * 10 + + Double.parseDouble("" + operation); + view.setDisplay(current); + return; + } + + // Execute the previously input operation + switch (lastOperationRequested) { + case '+': + model.add(current); + break; + case '-': + model.add(-current); + break; + case '/': + model.divide(current); + break; + case '*': + model.multiply(current); + break; + case 'C': + model.setValue(current); + break; + } // '=' is implicit + + lastOperationRequested = operation; + + current = 0.0; + if (operation == 'C') + model.clear(); + view.setDisplay(model.getValue()); + } +} +---- + +In the above example, we held some state information in the presenter. +Alternatively, we could have had an intermediate controller between the +presenter and the model to handle the low-level button logic. + + + + + diff --git a/documentation/advanced/advanced-cdi.asciidoc b/documentation/advanced/advanced-cdi.asciidoc new file mode 100644 index 0000000000..d5d135ca1f --- /dev/null +++ b/documentation/advanced/advanced-cdi.asciidoc @@ -0,0 +1,997 @@ +--- +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&p_p_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=row-1&p_p_col_pos=1&p_p_col_count=3&p_r_p_185834411_title=Vaadin+CDI&p_r_p_185834411_nodeName=vaadin.com+wiki&_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 +<>. + +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 +<> for general instructions for installing and using Vaadin +add-ons. + +The Ivy dependency is as follows: + +[subs="normal"] +---- + <dependency org="com.vaadin" name="vaadin-cdi" + rev="[replaceable]#latest.release#"/> +---- +The Maven dependency is as follows: + +[subs="normal"] +---- + <dependency> + <groupId>com.vaadin</groupId> + <artifactId>vaadin-cdi</artifactId> + <version>[replaceable]#LATEST#</version> + </dependency> + <dependency> + <groupId>javax.enterprise</groupId> + <artifactId>cdi-api</artifactId> + <version>[replaceable]#1.2#</version> + </dependency> +---- + +[[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.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 +<>. 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 <> 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 +<>). 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"] +---- +<web-app> + ... + + <servlet> + <servlet-name>Default</servlet-name> + <servlet-class> + com.vaadin.cdi.internal.VaadinCDIServlet + </servlet-class> + </servlet> + + <servlet-mapping> + <servlet-name>Default</servlet-name> + <url-pattern>[replaceable]#/mycdiuis/*#</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>Default</servlet-name> + <url-pattern>/VAADIN/*</url-pattern> + </servlet-mapping> +</web-app> +---- +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 +<>, 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 +<>. + + + +ifdef::web[] +[[advanced.cdi.navigation]] +== View Navigation + +Vaadin CDI extends the navigation framework in Vaadin, described in +<>. 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 +<>, 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 item = new BeanItem(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 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]] +.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 +<>, 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 +<> 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 uis = new HashSet(); + + 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 + 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 + 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"))) + + diff --git a/documentation/advanced/advanced-debug.asciidoc b/documentation/advanced/advanced-debug.asciidoc new file mode 100644 index 0000000000..9a0d8d7ba8 --- /dev/null +++ b/documentation/advanced/advanced-debug.asciidoc @@ -0,0 +1,208 @@ +--- +title: Debug Mode and Window +order: 3 +layout: page +--- + +[[advanced.debug]] += Debug Mode and Window + +Vaadin applications can be run in two modes: __debug mode__ and __production +mode__. The debug mode, which is on by default, enables a number of built-in +debug features for Vaadin developers: + +* Debug Window +* Display debug information in the Debug Window and server console +* On-the-fly compilation of Sass themes + +[[advanced.debug.mode]] +== Enabling the Debug Mode + +The debug mode is enabled and production mode disabled by default in the UI +templates created with the Eclipse plugin or the Maven archetypes. The debug +mode can be enabled by giving a [parameter]#productionMode=false# parameter to +the Vaadin servlet configuration: + +[subs="normal"] +---- +@VaadinServletConfiguration( + productionMode = **false**, + ui = **MyprojectUI.class**) +---- +Or with a context parameter in the [filename]#web.xml# deployment descriptor: + +[subs="normal"] +---- +<context-param> + <description>Vaadin production mode</description> + <param-name>productionMode</param-name> + <param-value>**false**</param-value> +</context-param> +---- +Enabling the production mode disables the debug features, thereby preventing +users from easily inspecting the inner workings of the application from the +browser. + + +[[advanced.debug.open]] +== Opening the Debug Window + +Running an application in the debug mode enables the client-side Debug Window in +the browser. You can open the Debug Window by adding " ?debug" parameter to the +URL of the UI, for example, http://localhost:8080/myapp/?debug. The Debug Window +has buttons for controlling the debugging features and a scrollable log of debug +messages. + +[[]] +.Debug Window +image::img/debug-window-annotated-hi.png[] + +The functionalities are described in detail in the subsequent sections. You can +move the window by dragging it from the title bar and resize it from the +corners. The [guibutton]#Minimize# button minimizes the debug window in the +corner of the browser window, and the [guibutton]#Close# button closes it. + +If you use the Firebug plugin for Firefox or the Developer Tools console in +Chrome, the log messages will also be printed to the Firebug console. In such a +case, you may want to enable client-side debugging without showing the Debug +Window with " ?debug=quiet" in the URL. In the quiet debug mode, log messages +will only be printed to the console of the browser debugger. + + +[[advanced.debug.log]] +== Debug Message Log + +The debug message log displays client-side debug messages, with time counter in +milliseconds. The control buttons allow you to clear the log, reset the timer, +and lock scrolling. + +[[]] +.Debug Message Log +image::img/debug-log-hi.png[] + +[[advanced.debug.log.custom]] +=== Logging to Debug Window + +You can take advantage of the debug mode when developing client-side components, +by using the standard Java [classname]#Logger# to write messages to the log. The +messages will be written to the debug window and Firebug console. No messages +are written if the debug window is not open or if the application is running in +production mode. + + + +[[advanced.debug.info]] +== General Information + +The [guilabel]#General information about the application(s)# tab displays +various information about the UI, such as version numbers of the client and +servlet engine, and the theme. If they do not match, you may need to compile the +widget set or theme. + +[[]] +.General Information +image::img/debug-info.png[] + + +[[advanced.debug.hierarchy]] +== Inspecting Component Hierarchy + +The [guilabel]#Component Hierarchy# tab has several sub-modes that allow +debugging the component tree in various ways. + +[[advanced.debug.hierarchy.tree]] +=== Connector Hierarchy Tree + +The [guibutton]#Show the connector hierarchy tree# button displays the +client-side connector hierarchy. As explained in +<>, client-side widgets are managed by connectors that +handle communication with the server-side component counterparts. The connector +hierarchy therefore corresponds with the server-side component tree, but the +client-side widget tree and HTML DOM tree have more complexity. + +[[]] +.Connector Hierarchy Tree +image::img/debug-hierarchy-tree.png[] + +Clicking on a connector highlights the widget in the UI. + + +[[advanced.debug.hierarchy.inspect]] +=== Inspecting a Component + +The [guibutton]#Select a component in the page to inspect it# button lets you +select a component in the UI by clicking it and display its client-side +properties. + +To view the HTML structure and CSS styles in more detail, you can use Firebug in +Firefox, or the Developer Tools in Chrome, as described in +<>. Firefox also has a built-in feature for inspecting HTML and CSS. + + +[[advanced.debug.hierarchy.analyze]] +=== Analyzing Layout Problems + +The [guilabel]#Check layouts for potential problems# button analyzes the +currently visible UI and makes a report of possible layout related problems. All +detected layout problems are displayed in the log and also printed to the +console. + +[[]] +.Debug Window Showing the Result of Layout Analysis. +image::img/debug-window-analyze-layouts.png[] + +Clicking on a reported problem highlights the component with the problem in the +UI. + +The most common layout problem is caused by placing a component that has a +relative size inside a container (layout) that has undefined size in the +particular direction (height or width). For example, adding a +[classname]#Button# with 100% width inside a [classname]#VerticalLayout# with +undefined width. In such a case, the error would look as shown in +<>. + +[classname]#CustomLayout# components can not be analyzed in the same way as +other layouts. For custom layouts, the button analyzes all contained +relative-sized components and checks if any relative dimension is calculated to +zero so that the component will be invisible. The error log will display a +warning for each of these invisible components. It would not be meaningful to +emphasize the component itself as it is not visible, so when you select such an +error, the parent layout of the component is emphasized if possible. + + +[[advanced.debug.hierarchy.used]] +=== Displaying Used Connectors + +The last button, [guibutton]#Show used connectors and how to optimize widget +set#, displays a list of all currently visible connectors. It also generates a +connector bundle loader factory, which you can use to optimize the widget set so +that it only contains the widgets actually used in the UI. Note, however, that +it only lists the connectors visible in the current UI state, and you usually +have more connectors than that. + + + +[[advanced.debug.communication]] +== Communication Log + +The [guilabel]#Communication# tab displays all server requests. You can unfold +the requests to view details, such as the connectors involved. Clicking on a +connector highlights the corresponding element in the UI. + +You can use Firebug or Developer Tools in Firefox or Chrome, respectively, to +get more detailed information about the requests and responses. + + +[[advanced.debug.devmodes]] +== Debug Modes + +The [guilabel]#Menu# tab in the window opens a sub-menu to select various +settings. Here you can also launch the GWT SuperDevMode, as described in +<>. + + + + diff --git a/documentation/advanced/advanced-dragndrop.asciidoc b/documentation/advanced/advanced-dragndrop.asciidoc new file mode 100644 index 0000000000..69335c6369 --- /dev/null +++ b/documentation/advanced/advanced-dragndrop.asciidoc @@ -0,0 +1,567 @@ +--- +title: Drag and Drop +order: 12 +layout: page +--- + +[[advanced.dragndrop]] += Drag and Drop + +((("Drag and Drop", id="term.advanced.dragndrop", range="startofrange"))) + + +Dragging an object from one location to another by grabbing it with mouse, +holding the mouse button pressed, and then releasing the button to "drop" it to +the other location is a common way to move, copy, or associate objects. For +example, most operating systems allow dragging and dropping files between +folders or dragging a document on a program to open it. In Vaadin, it is +possible to drag and drop components and parts of certain components. + +Dragged objects, or __transferables__, are essentially data objects. You can +drag and drop rows in [classname]#Table# and nodes in [classname]#Tree# +components, either within or between the components. You can also drag entire +components by wrapping them inside [classname]#DragAndDropWrapper#. + +Dragging starts from a __drag source__, which defines the transferable. +Transferables implement the [classname]#Transferable# interfaces. For trees and +tables, which are bound to [classname]#Container# data sources, a node or row +transferable is a reference to an [classname]#Item# in the Vaadin Data Model. +Dragged components are referenced with a [classname]#WrapperTransferable#. +Starting dragging does not require any client-server communication, you only +need to enable dragging. All drag and drop logic occurs in two operations: +determining ( __accepting__) where dropping is allowed and actually dropping. +Drops can be done on a __drop target__, which implements the +[classname]#DropTarget# interface. Three components implement the interface: +[classname]#Tree#, [classname]#Table#, and [classname]#DragAndDropWrapper#. +These accept and drop operations need to be provided in a __drop handler__. +Essentially all you need to do to enable drag and drop is to enable dragging in +the drag source and implement the [methodname]#getAcceptCriterion()# and +[methodname]#drop()# methods in the [classname]#DropHandler# interface. + +The client-server architecture of Vaadin causes special requirements for the +drag and drop functionality. The logic for determining where a dragged object +can be dropped, that is, __accepting__ a drop, should normally be done on the +client-side, in the browser. Server communications are too slow to have much of +such logic on the server-side. The drag and drop feature therefore offers a +number of ways to avoid the server communications to ensure a good user +experience. + +[[advanced.dragndrop.drophandler]] +== Handling Drops + +Most of the user-defined drag and drop logic occurs in a __drop handler__, which +is provided by implementing the [methodname]#drop()# method in the +[classname]#DropHandler# interface. A closely related definition is the drop +accept criterion, which is defined in the [methodname]#getAcceptCriterion()# +method in the same interface. It is described in +<> later. + +The [methodname]#drop()# method gets a [classname]#DragAndDropEvent# as its +parameters. The event object provides references to two important object: +[classname]#Transferable# and [classname]#TargetDetails#. + +A [classname]#Transferable# contains a reference to the object (component or +data item) that is being dragged. A tree or table item is represented as a +[classname]#TreeTransferable# or [classname]#TableTransferable# object, which +carries the item identifier of the dragged tree or table item. These special +transferables, which are bound to some data in a container, are +[classname]#DataBoundTransferable#. Dragged components are represented as +[classname]#WrapperTransferable# objects, as the components are wrapped in a +[classname]#DragAndDropWrapper#. + +The [classname]#TargetDetails# object provides information about the exact +location where the transferable object is being dropped. The exact class of the +details object depends on the drop target and you need to cast it to the proper +subclass to get more detailed information. If the target is selection component, +essentially a tree or a table, the [classname]#AbstractSelectTargetDetails# +object tells the item on which the drop is being made. For trees, the +[classname]#TreeTargetDetails# gives some more details. For wrapped components, +the information is provided in a [classname]#WrapperDropDetails# object. In +addition to the target item or component, the details objects provide a __drop +location__. For selection components, the location can be obtained with the +[methodname]#getDropLocation()# and for wrapped components with +[methodname]#verticalDropLocation()# and [methodname]#horizontalDropLocation()#. +The locations are specified as either [classname]#VerticalDropLocation# or +[classname]#HorizontalDropLocation# objects. The drop location objects specify +whether the transferable is being dropped above, below, or directly on (at the +middle of) a component or item. + +Dropping on a [classname]#Tree#, [classname]#Table#, and a wrapped component is +explained further in the following sections. + + +[[advanced.dragndrop.treedrop]] +== Dropping Items On a [classname]#Tree# + +You can drag items from, to, or within a [classname]#Tree#. Making tree a drag +source requires simply setting the drag mode with [methodname]#setDragMode()#. +[classname]#Tree# currently supports only one drag mode, +[literal]#++TreeDragMode.NODE++#, which allows dragging single tree nodes. While +dragging, the dragged node is referenced with a [classname]#TreeTransferable# +object, which is a [classname]#DataBoundTransferable#. The tree node is +identified by the item ID of the container item. + +When a transferable is dropped on a tree, the drop location is stored in a +[classname]#TreeTargetDetails# object, which identifies the target location by +item ID of the tree node on which the drop is made. You can get the item ID with +[methodname]#getItemIdOver()# method in +[classname]#AbstractSelectTargetDetails#, which the +[classname]#TreeTargetDetails# inherits. A drop can occur directly on or above +or below a node; the exact location is a [classname]#VerticalDropLocation#, +which you can get with the [methodname]#getDropLocation()# method. + +In the example below, we have a [classname]#Tree# and we allow reordering the +tree items by drag and drop. + + +[source, java] +---- +final Tree tree = new Tree("Inventory"); +tree.setContainerDataSource(TreeExample.createTreeContent()); +layout.addComponent(tree); + +// Expand all items +for (Iterator it = tree.rootItemIds().iterator(); it.hasNext();) + tree.expandItemsRecursively(it.next()); + +// Set the tree in drag source mode +tree.setDragMode(TreeDragMode.NODE); + +// Allow the tree to receive drag drops and handle them +tree.setDropHandler(new DropHandler() { + public AcceptCriterion getAcceptCriterion() { + return AcceptAll.get(); + } + + public void drop(DragAndDropEvent event) { + // Wrapper for the object that is dragged + Transferable t = event.getTransferable(); + + // Make sure the drag source is the same tree + if (t.getSourceComponent() != tree) + return; + + TreeTargetDetails target = (TreeTargetDetails) + event.getTargetDetails(); + + // Get ids of the dragged item and the target item + Object sourceItemId = t.getData("itemId"); + Object targetItemId = target.getItemIdOver(); + + // On which side of the target the item was dropped + VerticalDropLocation location = target.getDropLocation(); + + HierarchicalContainer container = (HierarchicalContainer) + tree.getContainerDataSource(); + + // Drop right on an item -> make it a child + if (location == VerticalDropLocation.MIDDLE) + tree.setParent(sourceItemId, targetItemId); + + // Drop at the top of a subtree -> make it previous + else if (location == VerticalDropLocation.TOP) { + Object parentId = container.getParent(targetItemId); + container.setParent(sourceItemId, parentId); + container.moveAfterSibling(sourceItemId, targetItemId); + container.moveAfterSibling(targetItemId, sourceItemId); + } + + // Drop below another item -> make it next + else if (location == VerticalDropLocation.BOTTOM) { + Object parentId = container.getParent(targetItemId); + container.setParent(sourceItemId, parentId); + container.moveAfterSibling(sourceItemId, targetItemId); + } + } +}); +---- + +[[advanced.dragndrop.treedrop.criteria]] +=== Accept Criteria for Trees + +[classname]#Tree# defines some specialized accept criteria for trees. + +[classname]#TargetInSubtree#(client-side):: Accepts if the target item is in the specified sub-tree. The sub-tree is specified by the item ID of the root of the sub-tree in the constructor. The second constructor includes a depth parameter, which specifies how deep from the given root node are drops accepted. Value [literal]#++-1++# means infinite, that is, the entire sub-tree, and is therefore the same as the simpler constructor. +[classname]#TargetItemAllowsChildren#(client-side):: Accepts a drop if the tree has [methodname]#setChildrenAllowed()# enabled for the target item. The criterion does not require parameters, so the class is a singleton and can be acquired with [methodname]#Tree.TargetItemAllowsChildren.get()#. For example, the following composite criterion accepts drops only on nodes that allow children, but between all nodes: ++ +[source, java] +---- +return new Or (Tree.TargetItemAllowsChildren.get(), new Not(VerticalLocationIs.MIDDLE)); +---- + +[classname]#TreeDropCriterion#(server-side):: Accepts drops on only some items, which as specified by a set of item IDs. You must extend the abstract class and implement the [methodname]#getAllowedItemIds()# to return the set. While the criterion is server-side, it is lazy-loading, so that the list of accepted target nodes is loaded only once from the server for each drag operation. See <> for an example. + + +In addition, the accept criteria defined in [classname]#AbstractSelect# are +available for a [classname]#Tree#, as listed in +<>. + + + +[[advanced.dragndrop.tabledrop]] +== Dropping Items On a [classname]#Table# + +You can drag items from, to, or within a [classname]#Table#. Making table a drag +source requires simply setting the drag mode with [methodname]#setDragMode()#. +[classname]#Table# supports dragging both single rows, with +[literal]#++TableDragMode.ROW++#, and multiple rows, with +[literal]#++TableDragMode.MULTIROW++#. While dragging, the dragged node or nodes +are referenced with a [classname]#TreeTransferable# object, which is a +[classname]#DataBoundTransferable#. Tree nodes are identified by the item IDs of +the container items. + +When a transferable is dropped on a table, the drop location is stored in a +[classname]#AbstractSelectTargetDetails# object, which identifies the target row +by its item ID. You can get the item ID with [methodname]#getItemIdOver()# +method. A drop can occur directly on or above or below a row; the exact location +is a [classname]#VerticalDropLocation#, which you can get with the +[methodname]#getDropLocation()# method from the details object. + +[[advanced.dragndrop.tabledrop.criteria]] +=== Accept Criteria for Tables + +[classname]#Table# defines one specialized accept criterion for tables. + +[classname]#TableDropCriterion#(server-side):: Accepts drops only on (or above or below) items that are specified by a set of item IDs. You must extend the abstract class and implement the [methodname]#getAllowedItemIds()# to return the set. While the criterion is server-side, it is lazy-loading, so that the list of accepted target items is loaded only once from the server for each drag operation. + + + + +[[advanced.dragndrop.acceptcriteria]] +== Accepting Drops + +((("Drag and Drop", "Accept Criteria", id="term.advanced.dragndrop.acceptcriteria", range="startofrange"))) + + +You can not drop the objects you are dragging around just anywhere. Before a +drop is possible, the specific drop location on which the mouse hovers must be +__accepted__. Hovering a dragged object over an accepted location displays an +__accept indicator__, which allows the user to position the drop properly. As +such checks have to be done all the time when the mouse pointer moves around the +drop targets, it is not feasible to send the accept requests to the server-side, +so drops on a target are normally accepted by a client-side __accept +criterion__. + +A drop handler must define the criterion on the objects which it accepts to be +dropped on the target. The criterion needs to be provided in the +[classname]#getAcceptCriterion()# method of the [classname]#DropHandler# +interface. A criterion is represented in an [classname]#AcceptCriterion# object, +which can be a composite of multiple criteria that are evaluated using logical +operations. There are two basic types of criteria: __client-side__ and +__server-side criteria__. The various built-in criteria allow accepting drops +based on the identity of the source and target components, and on the __data +flavor__ of the dragged objects. + +To allow dropping any transferable objects, you can return a universal accept +criterion, which you can get with [methodname]#AcceptAll.get()#. + + +[source, java] +---- +tree.setDropHandler(new DropHandler() { + public AcceptCriterion getAcceptCriterion() { + return AcceptAll.get(); + } + ... +---- + +[[advanced.dragndrop.acceptcriteria.client-side]] +=== Client-Side Criteria + +The __client-side criteria__, which inherit the +[classname]#ClientSideCriterion#, are verified on the client-side, so server +requests are not needed for verifying whether each component on which the mouse +pointer hovers would accept a certain object. + +The following client-side criteria are define in +[package]#com.vaadin.event.dd.acceptcriterion#: + +[classname]#AcceptAll#:: Accepts all transferables and targets. +[classname]#And#:: Performs the logical AND operation on two or more client-side criteria; accepts the transferable if all the given sub-criteria accept it. +[classname]#ContainsDataFlavour#:: The transferable must contain the defined data flavour. +[classname]#Not#:: Performs the logical NOT operation on a client-side criterion; accepts the transferable if and only if the sub-criterion does not accept it. +[classname]#Or#:: Performs the logical OR operation on two or more client-side criteria; accepts the transferable if any of the given sub-criteria accepts it. +[classname]#SourceIs#:: Accepts all transferables from any of the given source components +[classname]#SourceIsTarget#:: Accepts the transferable only if the source component is the same as the target. This criterion is useful for ensuring that items are dragged only within a tree or a table, and not from outside it. +[classname]#TargetDetailIs#:: Accepts any transferable if the target detail, such as the item of a tree node or table row, is of the given data flavor and has the given value. + + +In addition, target components such as [classname]#Tree# and [classname]#Table# +define some component-specific client-side accept criteria. See +<> for more details. + +[classname]#AbstractSelect# defines the following criteria for all selection +components, including [classname]#Tree# and [classname]#Table#. + +[classname]#AcceptItem#:: Accepts only specific items from a specific selection component. The selection component, which must inherit [classname]#AbstractSelect#, is given as the first parameter for the constructor. It is followed by a list of allowed item identifiers in the drag source. +[classname]#AcceptItem.ALL#:: Accepts all transferables as long as they are items. +[classname]#TargetItemIs#:: Accepts all drops on the specified target items. The constructor requires the target component ( [classname]#AbstractSelect#) followed by a list of allowed item identifiers. +[classname]#VerticalLocationIs.MIDDLE#,[classname]#TOP#, and[classname]#BOTTOM#:: The three static criteria accepts drops on, above, or below an item. For example, you could accept drops only in between items with the following: +[source, java] +---- +public AcceptCriterion getAcceptCriterion() { + return new Not(VerticalLocationIs.MIDDLE); +} +---- + + + + + +[[advanced.dragndrop.acceptcriteria.server-side]] +=== Server-Side Criteria + +The __server-side criteria__ are verified on the server-side with the +[methodname]#accept()# method of the [classname]#ServerSideCriterion# class. +This allows fully programmable logic for accepting drops, but the negative side +is that it causes a very large amount of server requests. A request is made for +every target position on which the pointer hovers. This problem is eased in many +cases by the component-specific lazy loading criteria +[classname]#TableDropCriterion# and [classname]#TreeDropCriterion#. They do the +server visit once for each drag and drop operation and return all accepted rows +or nodes for current [classname]#Transferable# at once. + +The [methodname]#accept()# method gets the drag event as a parameter so it can +perform its logic much like in [methodname]#drop()#. + + +[source, java] +---- +public AcceptCriterion getAcceptCriterion() { + // Server-side accept criterion that allows drops on any other + // location except on nodes that may not have children + ServerSideCriterion criterion = new ServerSideCriterion() { + public boolean accept(DragAndDropEvent dragEvent) { + TreeTargetDetails target = (TreeTargetDetails) + dragEvent.getTargetDetails(); + + // The tree item on which the load hovers + Object targetItemId = target.getItemIdOver(); + + // On which side of the target the item is hovered + VerticalDropLocation location = target.getDropLocation(); + if (location == VerticalDropLocation.MIDDLE) + if (! tree.areChildrenAllowed(targetItemId)) + return false; // Not accepted + + return true; // Accept everything else + } + }; + return criterion; +} +---- + +The server-side criteria base class [classname]#ServerSideCriterion# provides a +generic [methodname]#accept()# method. The more specific +[classname]#TableDropCriterion# and [classname]#TreeDropCriterion# are +conveniency extensions that allow definiting allowed drop targets as a set of +items. They also provide some optimization by lazy loading, which reduces server +communications significantly. + + +[source, java] +---- +public AcceptCriterion getAcceptCriterion() { + // Server-side accept criterion that allows drops on any + // other tree node except on node that may not have children + TreeDropCriterion criterion = new TreeDropCriterion() { + @Override + protected Set getAllowedItemIds( + DragAndDropEvent dragEvent, Tree tree) { + HashSet allowed = new HashSet(); + for (Iterator i = + tree.getItemIds().iterator(); i.hasNext();) { + Object itemId = i.next(); + if (tree.hasChildren(itemId)) + allowed.add(itemId); + } + return allowed; + } + }; + return criterion; +} +---- + + +[[advanced.dragndrop.acceptcriteria.indicators]] +=== Accept Indicators + +When a dragged object hovers on a drop target, an __accept indicator__ is +displayed to show whether or not the location is accepted. For +[parameter]#MIDDLE# location, the indicator is a box around the target (tree +node, table row, or component). For vertical drop locations, the accepted +locations are shown as horizontal lines, and for horizontal drop locations as +vertical lines. + +For [classname]#DragAndDropWrapper# drop targets, you can disable the accept +indicators or __drag hints__ with the [parameter]#no-vertical-drag-hints#, +[parameter]#no-horizontal-drag-hints#, and [parameter]#no-box-drag-hints# +styles. You need to add the styles to the __layout that contains__ the wrapper, +not to the wrapper itself. + + +[source, java] +---- +// Have a wrapper +DragAndDropWrapper wrapper = new DragAndDropWrapper(c); +layout.addComponent(wrapper); + +// Disable the hints +layout.addStyleName("no-vertical-drag-hints"); +layout.addStyleName("no-horizontal-drag-hints"); +layout.addStyleName("no-box-drag-hints"); +---- + + +(((range="endofrange", startref="term.advanced.dragndrop.acceptcriteria"))) + +[[advanced.dragndrop.dragging]] +== Dragging Components + +Dragging a component requires wrapping the source component within a +[classname]#DragAndDropWrapper#. You can then allow dragging by putting the +wrapper (and the component) in drag mode with [methodname]#setDragStartMode()#. +The method supports two drag modes: [parameter]#DragStartMode.WRAPPER# and +[parameter]#DragStartMode.COMPONENT#, which defines whether the entire wrapper +is shown as the drag image while dragging or just the wrapped component. + + +[source, java] +---- +// Have a component to drag +final Button button = new Button("An Absolute Button"); + +// Put the component in a D&D wrapper and allow dragging it +final DragAndDropWrapper buttonWrap = new DragAndDropWrapper(button); +buttonWrap.setDragStartMode(DragStartMode.COMPONENT); + +// Set the wrapper to wrap tightly around the component +buttonWrap.setSizeUndefined(); + +// Add the wrapper, not the component, to the layout +layout.addComponent(buttonWrap, "left: 50px; top: 50px;"); +---- + +The default height of [classname]#DragAndDropWrapper# is undefined, but the +default width is 100%. If you want to ensure that the wrapper fits tightly +around the wrapped component, you should call [methodname]#setSizeUndefined()# +for the wrapper. Doing so, you should make sure that the wrapped component does +not have a relative size, which would cause a paradox. + +Dragged components are referenced in the [classname]#WrapperTransferable#. You +can get the reference to the dragged component with +[methodname]#getDraggedComponent()#. The method will return [literal]#++null++# +if the transferable is not a component. Also HTML 5 drags (see later) are held +in wrapper transferables. + + +[[advanced.dragndrop.drop-on-component]] +== Dropping on a Component + +Drops on a component are enabled by wrapping the component in a +[classname]#DragAndDropWrapper#. The wrapper is an ordinary component; the +constructor takes the wrapped component as a parameter. You just need to define +the [classname]#DropHandler# for the wrapper with +[methodname]#setDropHandler()#. + +In the following example, we allow moving components in an absolute layout. +Details on the drop handler are given later. + + +[source, java] +---- +// A layout that allows moving its contained components +// by dragging and dropping them +final AbsoluteLayout absLayout = new AbsoluteLayout(); +absLayout.setWidth("100%"); +absLayout.setHeight("400px"); + +... put some (wrapped) components in the layout ... + +// Wrap the layout to allow handling drops +DragAndDropWrapper layoutWrapper = + new DragAndDropWrapper(absLayout); + +// Handle moving components within the AbsoluteLayout +layoutWrapper.setDropHandler(new DropHandler() { + public AcceptCriterion getAcceptCriterion() { + return AcceptAll.get(); + } + + public void drop(DragAndDropEvent event) { + ... + } +}); +---- + +[[advanced.dragndrop.drop-on-component.details]] +=== Target Details for Wrapped Components + +The drop handler receives the drop target details in a +[classname]#WrapperTargetDetails# object, which implements the +[classname]#TargetDetails# interface. + + +[source, java] +---- +public void drop(DragAndDropEvent event) { + WrapperTransferable t = + (WrapperTransferable) event.getTransferable(); + WrapperTargetDetails details = + (WrapperTargetDetails) event.getTargetDetails(); +---- + +The wrapper target details include a [classname]#MouseEventDetails# object, +which you can get with [methodname]#getMouseEvent()#. You can use it to get the +mouse coordinates for the position where the mouse button was released and the +drag ended. Similarly, you can find out the drag start position from the +transferable object (if it is a [classname]#WrapperTransferable#) with +[methodname]#getMouseDownEvent()#. + + +[source, java] +---- +// Calculate the drag coordinate difference +int xChange = details.getMouseEvent().getClientX() + - t.getMouseDownEvent().getClientX(); +int yChange = details.getMouseEvent().getClientY() + - t.getMouseDownEvent().getClientY(); + +// Move the component in the absolute layout +ComponentPosition pos = + absLayout.getPosition(t.getSourceComponent()); +pos.setLeftValue(pos.getLeftValue() + xChange); +pos.setTopValue(pos.getTopValue() + yChange); +---- + +You can get the absolute x and y coordinates of the target wrapper with +[methodname]#getAbsoluteLeft()# and [methodname]#getAbsoluteTop()#, which allows +you to translate the absolute mouse coordinates to coordinates relative to the +wrapper. Notice that the coordinates are really the position of the wrapper, not +the wrapped component; the wrapper reserves some space for the accept +indicators. + +The [methodname]#verticalDropLocation()# and +[methodname]#horizontalDropLocation()# return the more detailed drop location in +the target. + + + +[[advanced.dragndrop.external]] +== Dragging Files from Outside the Browser + +The [classname]#DragAndDropWrapper# allows dragging files from outside the +browser and dropping them on a component wrapped in the wrapper. Dropped files +are automatically uploaded to the application and can be acquired from the +wrapper with [methodname]#getFiles()#. The files are represented as +[classname]#Html5File# objects as defined in the inner class. You can define an +upload [classname]#Receiver# to receive the content of a file to an +[classname]#OutputStream#. + +Dragging and dropping files to browser is supported in HTML 5 and requires a +compatible browser, such as Mozilla Firefox 3.6 or newer. + + +(((range="endofrange", startref="term.advanced.dragndrop"))) + + diff --git a/documentation/advanced/advanced-embedding.asciidoc b/documentation/advanced/advanced-embedding.asciidoc new file mode 100644 index 0000000000..ca2ccd3a0e --- /dev/null +++ b/documentation/advanced/advanced-embedding.asciidoc @@ -0,0 +1,460 @@ +--- +title: Embedding UIs in Web Pages +order: 2 +layout: page +--- + +[[advanced.embedding]] += Embedding UIs in Web Pages + +Many web sites are not all Vaadin, but Vaadin UIs are used only for specific +functionalities. In practice, many web applications are a mixture of dynamic web +pages, such as JSP, and Vaadin UIs embedded in such pages. + +Embedding Vaadin UIs in web pages is easy and there are several different ways +to embed them. One is to have a [literal]#++
++# placeholder for the UI and +load the Vaadin Client-Side Engine with some simple JavaScript code. Another +method is even easier, which is to simply use the [literal]#++ +---- + +endif::web[] + +ifdef::web[] +[[advanced.embedding.div.div]] +=== UI Placeholder Element + +A Vaadin UI is embedded in a placeholder [literal]#++
++# element. It should +have the following features: + +* The [literal]#++
++# element must have an [literal]#++id++# attribute, which must be a unique ID in the page, normally something that identifies the servlet of the UI uniquely. +* It must have at least the [literal]#++v-app++# style class. +* it should have a nested [literal]#++
++# element with [literal]#++v-app-loading++# style class. This is a placeholder for the loading indicator that is displayed while the UI is being loaded. +* It should also contain a [literal]#++