From fb207248d5567a2661d5729d5149c7c8920a2efa Mon Sep 17 00:00:00 2001 From: Henri Muurimaa Date: Mon, 11 Sep 2017 11:57:15 +0300 Subject: Migrate wiki articles to Vaadin documentation (#9912) * Vaadin Tutorial For Swing Developers * Setting And Reading Session Attributes * Enabling Server Push * Cleaning Up Resources In A UI * Sending Email From Java Applications * Using Parameters With Views * Optimizing Sluggish UI * Configuring Push For Your Enviroment * Setting And Reading Cookies * Using Polling * Creating An Application That Preserves State On Refresh * Finding The Current UI And Page And Vaadin Session * Sending Events From The Client To The Server Using RPC * Handling Logout * Remember To Set The Locale * Scalable Web Applications * MVC Basics In ITMill Toolkit * Access Control For Views * Customizing The Startup Page In An Application --- .../articles/AccessControlForViews.asciidoc | 200 +++++ .../articles/CleaningUpResourcesInAUI.asciidoc | 104 +++ .../ConfiguringPushForYourEnviroment.asciidoc | 278 ++++++ ...ApplicationThatPreservesStateOnRefresh.asciidoc | 50 ++ ...stomizingTheStartupPageInAnApplication.asciidoc | 114 +++ ...ingPortletsForTheWebSpherePortalServer.asciidoc | 95 ++ ...pingPortletsForTheWebsherePortalServer.asciidoc | 95 -- documentation/articles/EnablingServerPush.asciidoc | 136 +++ ...ingTheCurrentUIAndPageAndVaadinSession.asciidoc | 59 ++ documentation/articles/HandlingLogout.asciidoc | 29 + .../articles/MVCBasicsInITMillToolkit.asciidoc | 140 +++ .../articles/OptimizingSluggishUI.asciidoc | 191 +++++ .../articles/RememberToTheSetTheLocale.asciidoc | 183 ++++ .../articles/ScalableWebApplications.asciidoc | 723 ++++++++++++++++ .../SendingEmailFromJavaApplications.asciidoc | 429 ++++++++++ ...EventsFromTheClientToTheServerUsingRPC.asciidoc | 139 +++ .../articles/SettingAndReadingCookies.asciidoc | 136 +++ .../SettingAndReadingSessionAttributes.asciidoc | 89 ++ .../articles/UsingParametersWithViews.asciidoc | 112 +++ documentation/articles/UsingPolling.asciidoc | 222 +++++ .../VaadinTutorialForSwingDevelopers.asciidoc | 952 +++++++++++++++++++++ documentation/articles/contents.asciidoc | 20 +- documentation/articles/img/ActivityUML.jpg | Bin 0 -> 12429 bytes documentation/articles/img/MVCBasicsProject.zip | Bin 0 -> 2541784 bytes documentation/articles/img/designersetup.jpg | Bin 0 -> 360610 bytes documentation/articles/img/ejbswingvaadin.png | Bin 0 -> 110047 bytes documentation/articles/img/figure3s2.png | Bin 0 -> 115245 bytes documentation/articles/img/figure6a.png | Bin 0 -> 47221 bytes documentation/articles/img/figure6s.png | Bin 0 -> 75505 bytes documentation/articles/img/figure7s.png | Bin 0 -> 218079 bytes documentation/articles/img/helloworldview.png | Bin 0 -> 37481 bytes documentation/articles/img/howvaadinworks2.png | Bin 0 -> 79130 bytes documentation/articles/img/mockapp-ui.png | Bin 0 -> 394112 bytes documentation/articles/img/moduleDesign.jpg | Bin 0 -> 13117 bytes documentation/articles/img/view.jpg | Bin 0 -> 11811 bytes documentation/articles/img/webusers.png | Bin 0 -> 67500 bytes 36 files changed, 4400 insertions(+), 96 deletions(-) create mode 100644 documentation/articles/AccessControlForViews.asciidoc create mode 100644 documentation/articles/CleaningUpResourcesInAUI.asciidoc create mode 100644 documentation/articles/ConfiguringPushForYourEnviroment.asciidoc create mode 100644 documentation/articles/CreatingAnApplicationThatPreservesStateOnRefresh.asciidoc create mode 100644 documentation/articles/CustomizingTheStartupPageInAnApplication.asciidoc create mode 100644 documentation/articles/DevelopingPortletsForTheWebSpherePortalServer.asciidoc delete mode 100644 documentation/articles/DevelopingPortletsForTheWebsherePortalServer.asciidoc create mode 100644 documentation/articles/EnablingServerPush.asciidoc create mode 100644 documentation/articles/FindingTheCurrentUIAndPageAndVaadinSession.asciidoc create mode 100644 documentation/articles/HandlingLogout.asciidoc create mode 100644 documentation/articles/MVCBasicsInITMillToolkit.asciidoc create mode 100644 documentation/articles/OptimizingSluggishUI.asciidoc create mode 100644 documentation/articles/RememberToTheSetTheLocale.asciidoc create mode 100644 documentation/articles/ScalableWebApplications.asciidoc create mode 100644 documentation/articles/SendingEmailFromJavaApplications.asciidoc create mode 100644 documentation/articles/SendingEventsFromTheClientToTheServerUsingRPC.asciidoc create mode 100644 documentation/articles/SettingAndReadingCookies.asciidoc create mode 100644 documentation/articles/SettingAndReadingSessionAttributes.asciidoc create mode 100644 documentation/articles/UsingParametersWithViews.asciidoc create mode 100644 documentation/articles/UsingPolling.asciidoc create mode 100644 documentation/articles/VaadinTutorialForSwingDevelopers.asciidoc create mode 100644 documentation/articles/img/ActivityUML.jpg create mode 100644 documentation/articles/img/MVCBasicsProject.zip create mode 100644 documentation/articles/img/designersetup.jpg create mode 100644 documentation/articles/img/ejbswingvaadin.png create mode 100644 documentation/articles/img/figure3s2.png create mode 100644 documentation/articles/img/figure6a.png create mode 100644 documentation/articles/img/figure6s.png create mode 100644 documentation/articles/img/figure7s.png create mode 100644 documentation/articles/img/helloworldview.png create mode 100644 documentation/articles/img/howvaadinworks2.png create mode 100644 documentation/articles/img/mockapp-ui.png create mode 100644 documentation/articles/img/moduleDesign.jpg create mode 100644 documentation/articles/img/view.jpg create mode 100644 documentation/articles/img/webusers.png (limited to 'documentation') diff --git a/documentation/articles/AccessControlForViews.asciidoc b/documentation/articles/AccessControlForViews.asciidoc new file mode 100644 index 0000000000..f48b7aeea2 --- /dev/null +++ b/documentation/articles/AccessControlForViews.asciidoc @@ -0,0 +1,200 @@ +[[access-control-for-views]] +Access control for views +------------------------ + +The Navigator API provides a simple mechanism to allow or disallow +navigating to a View. Before a View is shown, each ViewChangeListener +that is registered with the Navigator is given the opportunity to veto +the View change. + +One can also make the View itself trigger a navigation to another View +in navigateTo(), but let's take a look at the more flexible +beforeViewChange() and afterViewChange(), that exists specifically for +this purpose. + +First, let's continue from previous examples and create a MessageView +for secret messages: + +[source,java] +.... +import com.vaadin.navigator.View; +import com.vaadin.ui.Label; + +public class SecretView extends MessageView implements View { + public static final String NAME = "secret"; + + public SecretView() { + setCaption("Private messages"); + ((Layout) getContent()).addComponent(new Label("Some private stuff.")); + } +} +.... + +As you can see, there is absolutely nothing special going on here, we +just customize the View enough to be able to distinguish from the +regular MessageView. + +Next, we'll register this new View with the Navigator, exactly as +before. At this point our SecretView is not secret at all, but let's fix +that by adding a ViewChangeListener to the Navigator: + +[source,java] +.... +navigator.addViewChangeListener(new ViewChangeListener() { + + @Override + public boolean beforeViewChange(ViewChangeEvent event) { + if (event.getNewView() instanceof SecretView && + ((NavigationtestUI)UI.getCurrent()).getLoggedInUser() == null) { + Notification.show("Permission denied", Type.ERROR_MESSAGE); + return false; + } else { + return true; + } + } + + @Override + public void afterViewChange(ViewChangeEvent event) { + } + +}); +.... + +So if we're on our way to the SecretView, but not logged in +(getLoggedInUser() == null), the View change is cancelled. Quite simple +rules in our case, but you could check anything - most probably you'll +want to call a helper method that checks the user for permission. + +Let's go ahead and add some links to the MainView again, so that we +don't have to muck with the address-bar to try it out: + +[source,java] +.... +import com.vaadin.navigator.View; +import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; +import com.vaadin.server.ExternalResource; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Link; +import com.vaadin.ui.Panel; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +public class MainView extends Panel implements View { + + public static final String NAME = ""; + + public MainView() { + + VerticalLayout layout = new VerticalLayout(); + + Link lnk = new Link("Count", new ExternalResource("#!" + CountView.NAME)); + layout.addComponent(lnk); + + lnk = new Link("Message: Hello", new ExternalResource("#!" + + MessageView.NAME + "/Hello")); + layout.addComponent(lnk); + + lnk = new Link("Message: Bye", new ExternalResource("#!" + + MessageView.NAME + "/Bye/Goodbye")); + layout.addComponent(lnk); + + lnk = new Link("Private message: Secret", new ExternalResource("#!" + + SecretView.NAME + "/Secret")); + layout.addComponent(lnk); + + lnk = new Link("Private message: Topsecret", new ExternalResource("#!" + + SecretView.NAME + "/Topsecret")); + layout.addComponent(lnk); + + // login/logout toggle so we can test this + Button logInOut = new Button("Toggle login", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + Object user = ((NavigationtestUI)UI.getCurrent()).getLoggedInUser(); + ((NavigationtestUI)UI.getCurrent()).setLoggedInUser( + user == null ? "Smee" : null); + } + }); + layout.addComponent(logInOut); + setContent(layout); + } + + @Override + public void enter(ViewChangeEvent event) { + } +} +.... + +Instead of just showing a notification and leaving the user wondering, +we should obviously allow the user to log in and continue. We'll do just +that in the separate tutorial about Handling login, but for now we just +add a button that toggles our logged in/out state. + +Meanwhile, here is the the full source for the UI so far: + +[source,java] +.... +import com.vaadin.navigator.Navigator; +import com.vaadin.navigator.ViewChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Notification.Type; +import com.vaadin.ui.UI; + +public class NavigationtestUI extends UI { + + Navigator navigator; + + String loggedInUser; + + @Override + public void init(VaadinRequest request) { + // Create Navigator, make it control the ViewDisplay + navigator = new Navigator(this, this); + + // Add some Views + navigator.addView(MainView.NAME, new MainView()); // no fragment + + // #count will be a new instance each time we navigate to it, counts: + navigator.addView(CountView.NAME, CountView.class); + + // #message adds a label with whatever it receives as a parameter + navigator.addView(MessageView.NAME, new MessageView()); + + // #secret works as #message, but you need to be logged in + navigator.addView(SecretView.NAME, new SecretView()); + + // we'll handle permissions with a listener here, you could also do + // that in the View itself. + + navigator.addViewChangeListener(new ViewChangeListener() { + + @Override + public boolean beforeViewChange(ViewChangeEvent event) { + if (event.getNewView() instanceof SecretView + && ((NavigationtestUI)UI.getCurrent()).getLoggedInUser() == null) { + Notification.show("Permission denied", Type.ERROR_MESSAGE); + return false; + } else { + return true; + } + } + + @Override + public void afterViewChange(ViewChangeEvent event) { + System.out.println("After view change"); + } + + }); + } + + public String getLoggedInUser(){ + return loggedInUser; + } + + public void setLoggedInUser(String user){ + loggedInUser = user; + } +} +.... diff --git a/documentation/articles/CleaningUpResourcesInAUI.asciidoc b/documentation/articles/CleaningUpResourcesInAUI.asciidoc new file mode 100644 index 0000000000..d26183c36f --- /dev/null +++ b/documentation/articles/CleaningUpResourcesInAUI.asciidoc @@ -0,0 +1,104 @@ +[[cleaning-up-resources-in-a-ui]] +Cleaning up resources in a UI +----------------------------- + +Vaadin UIs that are open on the client side send a regular heartbeat +to the server to indicate they are still alive, even though there is no +ongoing user interaction. When the server does not receive a valid +heartbeat for a given UI, it will eventually remove that UI from the +session. + +By default, heartbeats are sent every five minutes, and the server +closes an UI after three missed heartbeats. The heartbeat interval can +be customized by providing an init parameter named `heartbeatInterval` +in your web.xml, setting its value to the desired interval in seconds: + +[source,xml] +.... + + + heartbeatInterval + 120 + + + + + + + heartbeatInterval + 120 + + + +.... + +To do custom cleanup in your UIs, `DetachListener`s can be registered: + +[source,java] +.... +public class MyUI extends UI { + @Override + protected void init(VaadinRequest request) { + addDetachListener(new DetachListener() { + + @Override + public void detach(DetachEvent event) { + releaseSomeResources(); + } + }); + } + + private void releaseSomeResources() { + // ... + } +.... + +Of course, your UI could also implement `DetachListener` itself: + +[source,java] +.... +public class MyUI extends UI implements DetachListener { + protected void init(VaadinRequest request) { + addDetachListener(this); + } + + @Override + public void detach(DetachEvent event) { + // do cleanup + } +} +.... + +If you'd like to share a listener instance between multiple UIs, the +current UI can be queried: + +[source,java] +.... +public void detach(DetachEvent event) { + // do cleanup + event.getConnector().getUI(); + + // or equivalent: + UI.getCurrent(); +} +.... + +Because heartbeat requests are just like any other request from the +servlet container's viewpoint, each heartbeat extends the lifetime of +the underlying HttpSession. This means that as long as there is an open +UI, the session never expires even though there is no user interaction. +This is desirable in some situations, but in others it may be not. + +You can control this behavior by setting an init parameter named +`closeIdleSessions` to `true`. When it is set to true (the default is +`false`), the session will be closed if no UI is active. Before the +session is closed, the detach methods will be called, and cleanup is +performed. + +[source,xml] +.... + + closeIdleSessions + true + +.... diff --git a/documentation/articles/ConfiguringPushForYourEnviroment.asciidoc b/documentation/articles/ConfiguringPushForYourEnviroment.asciidoc new file mode 100644 index 0000000000..dd837e5093 --- /dev/null +++ b/documentation/articles/ConfiguringPushForYourEnviroment.asciidoc @@ -0,0 +1,278 @@ +[[configuring-push-for-your-environment]] +Configuring Push For Your Enviroment +------------------------------------ + +Server push and especially websockets are emerging technologies and not +all servers and browsers handle them correctly (or even close to +correctly). Here are gathered a few known issues and ways to work around +them: + +*Rule of thumb: Use the latest version of your server and the latest +Vaadin version. Vaadin 7.6 has a completely rewritten logic for dealing +with buffering proxies and unreliabilities in the connection to the +server.* + +[[portals]] +Portals +~~~~~~~ + +Push is not supported in portals. +See https://dev.vaadin.com/ticket/11493 for more information. + +[[streaming]] +Streaming +~~~~~~~~~ + +*Avoid streaming and use long-polling instead*. Streaming and +long-polling works similarly on top of normal HTTP requests but +streaming uses the same HTTP response for multiple messages whereas +long-polling only writes on message per HTTP response. Especially +proxies can cause problems with streaming as they might deliver only +part of the message and buffer the rest. + +[[tomcat-6-streaming]] +Tomcat 6 + Streaming +~~~~~~~~~~~~~~~~~~~~ + +For Tomcat 6, falling back to streaming always results in an error message such as +[source] +.... +Failed using comet support: org.atmosphere.container.TomcatCometSupport, error: Tomcat failed to detect this is a Comet application because context.xml is missing or the Http11NioProtocol Connector is not enabled.If that's not the case, you can also remove META-INF/context.xml and WEB-INF/lib/atmosphere-compat-tomcat.jar Is the Nio or Apr Connector enabled?WARNING: Using org.atmosphere.container.BlockingIOCometSupport` +.... + +Atmosphere is expecting the Servlet to implement Tomcat's proprietary interface https://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/CometProcessor.html[CometProcessor]. (See https://github.com/Atmosphere/atmosphere/blob/atmosphere-project-1.0.14/modules/cpr/src/main/java/org/atmosphere/cpr/AtmosphereServlet.java[AtmosphereServlet]) + +Vaadin's default servlet does not implement this interface. + +When fallback to native Comet fails, Atmosphere uses +`BlockingIOCometSupport`, which seems to work with some applications and +not with others. If it does not work for your application, you may want +to try Tomcat 7 with a Servlet 3.0 application. + +[[tomcat-7-streaming]] +Tomcat 7 + Streaming +~~~~~~~~~~~~~~~~~~~~ + +For Tomcat 7, if your application is a Servlet 3.0 application, set the +property `org.atmosphere.useWebSocketAndServlet3=true` and make sure +your Servlet and your filters in Web.xml have +`true` or the equivalent annotation. + +For Servlet < 3.0, see "Tomcat6 + Streaming" above. + +[[tomcat-7-websockets]] +Tomcat 7 + Websockets +~~~~~~~~~~~~~~~~~~~~~ + +Tomcat 7 is unable to share the HTTP session between HTTP request and +websockets request. Because of this a FakeHttpSession (a copy of the +real session) is used for websockets. This has certain implications such +as that it is impossible to invalidate the session from a websockets +enabled application. Tomcat 8 does not have this problem. + +The Websockets implementation in the 7.0.2x series is rather immature, +so all kinds of issues may occur.  + +If you use Tomcat 7, upgrade to the latest version! + +*It is recommended to upgrade to the latest Tomcat 8 (requires Vaadin +7.2+) if you want to use websockets.* + +[[tomcat-8-websockets]] +Tomcat 8 + Websockets +~~~~~~~~~~~~~~~~~~~~~ + +.... +java.lang.ClassNotFoundException: org.eclipse.jetty.websocket.WebSocketFactory$Acceptor +.... + +This implies you have Jetty deployed on the classpath somewhere. +Atmosphere gets confused and tries to use its Websocket implementation +instead of Tomcat's. One common reason for this is that you have +accidentally deployed vaadin-client-compiler, which has Jetty as a +dependency (needed by SuperDevMode for instance.) + +[[glassfish-234-streaming]] +Glassfish 2/3/4 + Streaming +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Glassfish 2/3/4 requires the "comet" option to be enabled for streaming +to work. + +For Glassfish 2, set +`(Configurations -> HTTP service -> HTTP listeners -> http-listener-1 -> Add Property -> "cometSupport"="true")` +or use +`asadmin set server.http-service.http-listener.http-listener-1.property.cometSupport=true` + +For Glassfish 3/4, set +`(Configurations -> server-config -> Network Config -> Protocols -> http-listener-1 -> HTTP -> Comet Support)` +or use +`asadmin set server-config.network-config.protocols.protocol.http-listener-1.http.comet-support-enabled="true"` + +[[glassfish-3-websockets]] +Glassfish 3 + Websockets +~~~~~~~~~~~~~~~~~~~~~~~~ + +As a rule of thumb, don't do this. + +The Grizzly version shipped with Glassfish 3.1.2.2 contains a +https://java.net/jira/browse/GRIZZLY-1289[fatal bug] which prevents +Vaadin from working. Replace *glassfish/modules/grizzly-websockets.jar* +with +https://java.net/jira/secure/attachment/50681/grizzly-websockets-1.9.50-fix.jar +to get websockets working (with Vaadin 7.3). *This version is actually +also broken in many ways, so you may or may not get it to work. If you +want websockets, you should upgrade to Glassfish 4.* + +Glassfish 3 requires the websockets option to be enabled for websockets +to work +`(Configurations -> server-config -> Network Config -> Protocols -> http-listener-1 -> HTTP -> Websockets Support)` +or +`asadmin set server-config.network-config.protocols.protocol.http-listener-1.http.websockets-support-enabled="true"`. + +[[glassfish-4-websockets]] +Glassfish 4 + Websockets +~~~~~~~~~~~~~~~~~~~~~~~~ + +Glassfish 4 + websockets require Vaadin 7.2+. *If you are using +Glassfish 4.0, upgrade to Glassfish 4.1 to avoid problems* + +[[wildfly-8-websockets]] +Wildfly 8 + Websockets +~~~~~~~~~~~~~~~~~~~~~~ + +Wildfly requires all websocket endpoints to be deployed during web +application initialization and refuses to deploy them later. If you are +using multiple push enabled Vaadin servlets you should mark them as +load-on-startup=true to avoid issues. (Vaadin 7.2-7.4). Vaadin 7.5 fixes +this by initializing websockets during context deployment so +load-on-startup is not needed. + +[[weblogic-12-websockets]] +Weblogic 12 + Websockets +~~~~~~~~~~~~~~~~~~~~~~~~ + +Use WebLogic 12.1.3 or newer with Java 8 and Vaadin 7.5+. + +If you see "java.lang.IllegalStateException: +javax.websocket.server.ServerContainer is null. Make sure you are using +1.8+ and your server has websocket support enabled" you are probably +running with Java 7 or older. + +WebLogic 12 specifies a timeout of 30s by default for websocket +connections +(https://docs.oracle.com/middleware/1212/wls/WLPRG/websockets.htm#WLPRG811). +To avoid constant reconnects, you can set the init +parameter `weblogic.websocket.tyrus.session-max-idle-timeout` to either +-1 (no timeout in use) or a higher value than 30000 (value is in ms). + +[[jboss-eap-6.4-and-websockets]] +JBoss EAP 6.4  and Websockets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +JBoss EAP 6.4 includes support for websockets but they are not enabled +by default. To make websockets work you need to + +1. Change JBoss to use the NIO connector ++ +This can be done by running ++ +`$ bin/jboss-cli.sh --connect` ++ +and the following commands ++ +.... +batch +/subsystem=web/connector=http/:write-attribute(name=protocol,value=org.apache.coyote.http11.Http11NioProtocol) +run-batch +:reload +.... + +2. Add a *WEB-INF/jboss-web.xml* to you war file with the following +contents to enable websockets + +[source,xml] +.... + + true + +.... + +[[liberty-profileand-websockets]] +Liberty profile and Websockets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use Liberty beta 2015.9.0.0 or later and Vaadin 7.6+. + +[[buffering-proxies-and-long-polling]] +Buffering proxies and long polling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use Vaadin 7.6+ to deal with buffering proxies. Also see "Duplicate +resource xyz-abc-def-ghi-jkl" below + +[[kaspersky-anti-virus-long-polling]] +Kaspersky anti virus + long polling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use Vaadin 7.6+ to avoid problems with long polling. + +[[chrome-sayserr_incomplete_chunked_encoding]] +Chrome says ERR_INCOMPLETE_CHUNKED_ENCODING +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is completely normal and means that the (long-polling) push +connection was aborted by a third party. This typically happens when +there is a proxy between the browser and the server and the proxy has a +configured timeout and cuts the connection when the timeout is reached. +The browser should reconnect to the server normally after this happens. + +Server logs contain + +.... +Duplicate resource xyz-abc-def-ghi-jkl. Could be +caused by a dead connection not detected by your server. Replacing the +old one with the fresh one" +.... + +This indicates that first, the browser connected to the server and used +the given identifier for the push connection. Everything went as +expected. Later on, a browser (probably the same one) connected again using the +same identifier but according to the server, the old browser connection +should still be active. The server closes the old connection and logs +the warning. + +[[why-does-this-happen]] +Why does this happen? +^^^^^^^^^^^^^^^^^^^^^ + +Typically there was a proxy between the browser and the server, and the +proxy was configured to kill open connections after a certain inactivity +timeout on the connection (no data is sent before the server issues a +push command). Because of how TCP/IP works, the server has no idea that +the connection has been killed and continues to think that the old +client is connected and all is well. + +[[what-can-you-do-to-avoid-this]] +What can you do to avoid this? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You have a couple of options: + +1. If you are in control of the proxy, configure it not to timeout/kill +push connections (connections to the /PUSH url) +2. If you know what the proxy timeout is, configure a slightly shorter +timeout for push in the Vaadin application so that the server terminates +the idle connection and is aware of the termination before the proxy can +kill the connection. Use the `pushLongPollingSuspendTimeout` servlet +parameter for this (defined in milliseconds) (Vaadin 7.6+) + +If you do not configure the proxy so that the server knows when the +connection is killed, you also have a small chance of losing pushed +data. If it so happens that the server does a push right after the +connection was killed, it will not realize that it pushed data into a +closed connection (because of how sockets work and especially how they +work in Java). Disabling the timeout or setting the timeout on the +server also resolves this potential issue. diff --git a/documentation/articles/CreatingAnApplicationThatPreservesStateOnRefresh.asciidoc b/documentation/articles/CreatingAnApplicationThatPreservesStateOnRefresh.asciidoc new file mode 100644 index 0000000000..3f33ec3259 --- /dev/null +++ b/documentation/articles/CreatingAnApplicationThatPreservesStateOnRefresh.asciidoc @@ -0,0 +1,50 @@ +[[creating-an-application-that-preserves-state-on-refresh]] +Creating an application that preserves state on refresh +------------------------------------------------------- + +By default, Vaadin 7 does not preserve UI state when the browser page is +refreshed. This means that the instance number in this example is +incremented and the text field cleared on every page refresh: + +[source,java] +.... +public class CreatingPreserveState extends UI { + private static int instanceCounter = 0; + + private final CssLayout content = new CssLayout(); + + @Override + public void init(VaadinRequest request) { + TextField tf = new TextField("Instance #" + (++instanceCounter)); + tf.setImmediate(true); + + content.addComponent(tf); + setContent(content); + } +} +.... + +You can however modify your application to preserve your UI between page +refreshes with the `@PreserveOnRefresh` annotation like so + +[source,java] +.... +@PreserveOnRefresh +public class PreserveStateUI extends UI { + ... +} +.... + +If you want to reinitialize some part of your application when the page +is refreshed, you can (starting from Vaadin 7.2) override the refresh +method in your UI class. This method is called whenever an already +initialized UI is refreshed. + +[source,java] +.... +@Override +protected void refresh(VaadinRequest request) { + content.addComponent(new Label("UI was refreshed @" + + System.currentTimeMillis())); +} +.... diff --git a/documentation/articles/CustomizingTheStartupPageInAnApplication.asciidoc b/documentation/articles/CustomizingTheStartupPageInAnApplication.asciidoc new file mode 100644 index 0000000000..d48fcc6e39 --- /dev/null +++ b/documentation/articles/CustomizingTheStartupPageInAnApplication.asciidoc @@ -0,0 +1,114 @@ +[[customizing-the-startup-page-in-an-application]] +Customizing the startup page in an application +---------------------------------------------- + +In Vaadin 6, the startup page - used to bootstrap a new Vaadin UI +instance in the browser - was generated as a monolithic chunk of HTML +and was not easily customizable. In Vaadin 7, we added a new facility +for registering special _bootstrap listeners_ that are invoked before +the bootstrap response is sent. In addition, instead of bare HTML in a +string, the response is now built as a DOM tree that is easy to +manipulate programmatically. + +Here's an example of a simple bootstrap listener: + +[source,java] +.... +import org.jsoup.nodes.Comment; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.jsoup.parser.Tag; + +// ... + +new BootstrapListener() { + @Override + public void modifyBootstrapPage(BootstrapPageResponse response) { + response.getDocument().body().appendChild(new Comment("Powered by Vaadin!", "")); + } + + @Override + public void modifyBootstrapFragment(BootstrapFragmentResponse response) { + // Wrap the fragment in a custom div element + Element myDiv = new Element(Tag.valueOf("div"), ""); + List nodes = response.getFragmentNodes(); + for(Node node : nodes) { + myDiv.appendChild(node); + } + nodes.clear(); + nodes.add(myDiv); + } +} +.... + +The HTML library we use is http://jsoup.org/[jsoup]. It provides a very +convenient API for traversing, manipulating and extracting data from a +DOM, and is HTML5 compliant. + +The `BootstrapListener` interface contains two methods, one of which is +usually left empty. This is because a Vaadin application can be either +stand-alone, in which case it "owns" the whole page its UI resides in, +or embedded, such as a portlet, in which case it does not control the +content of the page it is embedded in. + +The `modifyBootstrapFragment` method is called in both cases. It +receives a `BootstrapFragmentResponse` that represents the HTML fragment +that is inserted in the host page, whether the page is controlled by +Vaadin or not. Hence, you only need to implement this method if you do +not care about the host page, whether your application is embedded or +standalone. + +The `modifyBootstrapPage` method is called with a +`BootstrapPageResponse` argument that represents the whole bootstrap +page, including the fragment mentioned above. Thus, it is only invoked +when the application is standalone and actually responsible for +generating the page. This method allows you to, for instance, add things +to the `head` element. The `BootstrapPageResponse` class also allows +setting arbitrary HTTP response headers: + +[source,java] +.... +public void modifyBootstrapPage(BootstrapPageResponse response) { + response.setHeader("X-Powered-By", "Vaadin 7"); +} +.... + +But how and where should the bootstrap listeners be registered? It +should be only once per session, and right in the beginning, so that +they are already added when the first response is sent. + +To do that you should write a custom servlet that extends +`VaadinServlet`, or a custom portlet extending `VaadinPortlet`, and a +session init listener that adds the bootstrap listener to the new +session. + +[source,java] +.... +class MyVaadinServlet extends VaadinServlet { + @Override + protected void servletInitialized() throws ServletException { + super.servletInitialized(); + getService().addSessionInitListener(new SessionInitListener() { + @Override + public void sessionInit(SessionInitEvent event) { + event.getSession().addBootstrapListener(listener); + } + }); + } +} + +// Or... + +class MyVaadinPortlet extends VaadinPortlet { + @Override + protected void portletInitialized() throws PortletException { + super.portletInitialized(); + getService().addSessionInitListener(new SessionInitListener() { + @Override + public void sessionInit(SessionInitEvent event) { + event.getSession().addBootstrapListener(listener); + } + }); + } +} +.... diff --git a/documentation/articles/DevelopingPortletsForTheWebSpherePortalServer.asciidoc b/documentation/articles/DevelopingPortletsForTheWebSpherePortalServer.asciidoc new file mode 100644 index 0000000000..4362b7e7f6 --- /dev/null +++ b/documentation/articles/DevelopingPortletsForTheWebSpherePortalServer.asciidoc @@ -0,0 +1,95 @@ +[[developing-portlets-for-the-websphere-portal-server]] +Developing portlets for the Websphere Portal Server +--------------------------------------------------- + +When creating portlets for the Websphere Portal Server (aka WPS) you +have the choice between different frameworks + +* JSF (2.0) +* Spring Portlet MVC +* Vaadin 6 / 7 + +While using JSF seems to be a bit outdated, because WPS just supports an +old JSF Version (MyFaces 2.0.2) Spring Portlet MVC is a good and valid +options for developing portlets. + +On this page I will try to collect all information to +develop Vaadin portlets in a fast and easy to use way. I will also +handle topics like using CDI and the navigator in a portal environment +as well as some architectural ideas like using the MVP pattern for a +portlet project. As an example portlet I will use a simple master / +detail portlet just like the Vaadin address book application. I have +developed all code examples on this wiki pages with the current Vaadin +version (7.4.2 as I am writing this) and tested the portlets on WPS 8.0 +and 8.5. + +I use Maven for dependency management and SLF4J for logging. You can +download the small zipped project in the attachments section. Please, +feel free to leave comments and / or questions on the bottom of the +page. + +[[a-simple-portlet]] +A simple Portlet +~~~~~~~~~~~~~~~~ + +Lets start with a "Click Me" (aka "Hello World") Vaading portlet. + +The UI class is identical to servlet development (create a button with a +click listener and show a notification when clicking the button). The +interesting part is the configuration of the portlet.xml file. + +[[portlet.xml]] +Portlet.xml +^^^^^^^^^^^ + +[source,xml] +.... + +      +          + Vaadin Click Me Portlet          + Vaadin Click Me Portlet          + Vaadin Click Me Portlet         + com.vaadin.server.VaadinPortlet + +            + UI            + com.gisag.vaadin.ClickMeUI          +          + +              + productionMode              + false          +      +      +            + Path of all static vaadin resources (configurable from context root)              + vaadin.resources.path              + PORTLET_CONTEXT        + + +          +              + text/html              + view          +      + + +.... + +In the `portlet` tag you have to set a value for the `portlet-class`. For +this simple we can use the default Vaadin portlet class +`com.vaadin.server.VaadinPortlet`; you also have to name you UI class as a +portlet init parameter. + +To let WPS find the Vaadin javascript and theme resources you have to +use the portlet init parameter `vaadin.resources.path`. The value +`PORTLET_CONTEXT` is a Vaadin constant value that makes the vaadin +resources available in the portlets resource path. + +Run the Maven build with `clean package` as goals and deploy the created +war file in the portal administration. Create a blank portal page and +add your portlet to the page. Your "Click me" portlet should look like +this: + +image:img/Click_Me_2015-03-31_21-03-27.png[Your first portlet] diff --git a/documentation/articles/DevelopingPortletsForTheWebsherePortalServer.asciidoc b/documentation/articles/DevelopingPortletsForTheWebsherePortalServer.asciidoc deleted file mode 100644 index 4362b7e7f6..0000000000 --- a/documentation/articles/DevelopingPortletsForTheWebsherePortalServer.asciidoc +++ /dev/null @@ -1,95 +0,0 @@ -[[developing-portlets-for-the-websphere-portal-server]] -Developing portlets for the Websphere Portal Server ---------------------------------------------------- - -When creating portlets for the Websphere Portal Server (aka WPS) you -have the choice between different frameworks - -* JSF (2.0) -* Spring Portlet MVC -* Vaadin 6 / 7 - -While using JSF seems to be a bit outdated, because WPS just supports an -old JSF Version (MyFaces 2.0.2) Spring Portlet MVC is a good and valid -options for developing portlets. - -On this page I will try to collect all information to -develop Vaadin portlets in a fast and easy to use way. I will also -handle topics like using CDI and the navigator in a portal environment -as well as some architectural ideas like using the MVP pattern for a -portlet project. As an example portlet I will use a simple master / -detail portlet just like the Vaadin address book application. I have -developed all code examples on this wiki pages with the current Vaadin -version (7.4.2 as I am writing this) and tested the portlets on WPS 8.0 -and 8.5. - -I use Maven for dependency management and SLF4J for logging. You can -download the small zipped project in the attachments section. Please, -feel free to leave comments and / or questions on the bottom of the -page. - -[[a-simple-portlet]] -A simple Portlet -~~~~~~~~~~~~~~~~ - -Lets start with a "Click Me" (aka "Hello World") Vaading portlet. - -The UI class is identical to servlet development (create a button with a -click listener and show a notification when clicking the button). The -interesting part is the configuration of the portlet.xml file. - -[[portlet.xml]] -Portlet.xml -^^^^^^^^^^^ - -[source,xml] -.... - -      -          - Vaadin Click Me Portlet          - Vaadin Click Me Portlet          - Vaadin Click Me Portlet         - com.vaadin.server.VaadinPortlet - -            - UI            - com.gisag.vaadin.ClickMeUI          -          - -              - productionMode              - false          -      -      -            - Path of all static vaadin resources (configurable from context root)              - vaadin.resources.path              - PORTLET_CONTEXT        - - -          -              - text/html              - view          -      - - -.... - -In the `portlet` tag you have to set a value for the `portlet-class`. For -this simple we can use the default Vaadin portlet class -`com.vaadin.server.VaadinPortlet`; you also have to name you UI class as a -portlet init parameter. - -To let WPS find the Vaadin javascript and theme resources you have to -use the portlet init parameter `vaadin.resources.path`. The value -`PORTLET_CONTEXT` is a Vaadin constant value that makes the vaadin -resources available in the portlets resource path. - -Run the Maven build with `clean package` as goals and deploy the created -war file in the portal administration. Create a blank portal page and -add your portlet to the page. Your "Click me" portlet should look like -this: - -image:img/Click_Me_2015-03-31_21-03-27.png[Your first portlet] diff --git a/documentation/articles/EnablingServerPush.asciidoc b/documentation/articles/EnablingServerPush.asciidoc new file mode 100644 index 0000000000..37bd197cbb --- /dev/null +++ b/documentation/articles/EnablingServerPush.asciidoc @@ -0,0 +1,136 @@ +[[enabling-server-push]] +Enabling server push +-------------------- + +The traditional way of communication between client and server in Vaadin +has been through XHR, i.e. AJAX requests. The client does a request to +the server with information about RPC method invocations, which are +executed on the server. As a result the state of one or several +components is updated and the changes are sent back as a response to the +client. Vaadin 7.1 introduces a new way of doing communications using +server push, which enables the server to push state changes to the +client without a request initiated by the client. + +To create a push enabled application you start by creating a normal +Vaadin 7 project using Eclipse or Maven. First you need to add the +vaadin-push package to your project, so open pom.xml or ivy.xml and add +a vaadin-push dependency, e.g. in Ivy + +[source,xml] +.... + +.... + +and in Maven + +[source,xml] +.... + + com.vaadin + vaadin-push + ${vaadin.version} + +.... + +Open your UI class and add a @Push annotation to enable push for the ui + +[source,java] +.... +@Push +public class PushTestUI extends UI { +... +} +.... + +If you are using a servlet 3.0 compatible server, open *web.xml* and +enable asynchronous processing by adding a +`true` tag. + +Your servlet definition should look something like this: + +[source,xml] +.... + + MyServlet + com.vaadin.server.VaadinServlet + + ui + org.vaadin.example.MyUI + + true + +.... + +Your application is now setup for push and will automatically push +changes to the browser when needed. You can test it out using e.g. the +following UI which only adds a Label and starts a thread which does the +real initialization: + +[source,java] +.... +@Push +public class PushTestUI extends UI { + + private VerticalLayout mainLayout; + + @Override + protected void init(VaadinRequest request) { + mainLayout = new VerticalLayout(); + mainLayout.setSizeFull(); + mainLayout.setMargin(true); + setContent(mainLayout); + + mainLayout.setDefaultComponentAlignment(Alignment.MIDDLE_CENTER); + Label loadingText = new Label("Loading UI, please wait..."); + loadingText.setSizeUndefined(); + mainLayout.addComponent(loadingText); + new InitializerThread().start(); + } + + class InitializerThread extends Thread { + @Override + public void run() { + // Do initialization which takes some time. + // Here represented by a 1s sleep + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + + // Init done, update the UI after doing locking + access(new Runnable() { + @Override + public void run() { + // Here the UI is locked and can be updated + mainLayout.removeAllComponents(); + mainLayout + .addComponent(new TextArea("This is the real UI")); + } + }); + } + } +} +.... + +`InitializerThread` is a `Thread` which simulates some work using a +sleep and then updates the UI with the real content. The UI update takes +place inside an _access_ call, which ensures the UI (actually the +`VaadinSession`) is locked to prevent synchronizations problems. + +Now deploy the application to your server and open the UI in a browser. +You will see the "Loading..." text for roughly a second and when +the initialization is complete, the Label will be replaced by a +`TextArea`. + +The changes were automatically pushed to the browser when the +_access_-block was done running. If you want full control on when +changes are pushed to the client, add `@Push(PushMode.MANUAL)` instead and +call `UI.push()` to push the changes (`UI.push()` needs to be called when +the session is locked, so run that inside the _access_ block too). + +You can also configure push mode for the whole application using the +`pushmode` servlet init parameter. Possible values are `automatic`, `manual` +and `disabled`. + +It is also possible to switch the push mode on the fly using +`UI.getPushConfiguration().setPushMode()`. diff --git a/documentation/articles/FindingTheCurrentUIAndPageAndVaadinSession.asciidoc b/documentation/articles/FindingTheCurrentUIAndPageAndVaadinSession.asciidoc new file mode 100644 index 0000000000..e10ce53c91 --- /dev/null +++ b/documentation/articles/FindingTheCurrentUIAndPageAndVaadinSession.asciidoc @@ -0,0 +1,59 @@ +[[finding-the-current-ui-and-page-and-vaadin-session]] +Finding the current UI and page and vaadin session +-------------------------------------------------- +There are many cases where you need a reference to the active `UI`, `Page` +or `VaadinServiceSession`, for instance for showing notifications in a +click listener. It is possible to get a reference to the component from +the event and then a reference from the component to the UI but Vaadin +also offers an easier way through two static methods: + +[source,java] +.... +UI.getCurrent() +Page.getCurrent() +VaadinSession.getCurrent() +.... + +For example when you want to show the name of the current UI class: + +[source,java] +.... +Button helloButton = new Button("Say Hello"); + helloButton.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + Notification.show("This UI is " + + UI.getCurrent().getClass().getSimpleName()); + } + }); +.... + +Similarly for `VaadinServiceSession`, for instance to find out if the +application is running in production mode: + +[source,java] +.... +public void buttonClick(ClickEvent event) { + String msg = "Running in "; + msg += VaadinSession.getCurrent().getConfiguration() + .isProductionMode() ? "production" : "debug"; + Notification.show(msg); +} +.... + +And finally similiarly for `Page`. For instance adding a browser window +resize listener can be added like this: + +[source,java] +.... +javaPage.getCurrent().addBrowserWindowResizeListener( + new Page.BrowserWindowResizeListener() { + @Override + public void browserWindowResized(BrowserWindowResizeEvent event) { + Notification.show("Browser resized to " + event.getWidth() + "x" + event.getHeight()); + } +}); +.... + +*Note* that these are based on `ThreadLocal` so they won't work in a +background thread (or otherwise outside the standard request scope). diff --git a/documentation/articles/HandlingLogout.asciidoc b/documentation/articles/HandlingLogout.asciidoc new file mode 100644 index 0000000000..e83ef7705b --- /dev/null +++ b/documentation/articles/HandlingLogout.asciidoc @@ -0,0 +1,29 @@ +[[handling-logout]] +Handling logout +--------------- +What should happen the user wants to log out from a Vaadin application +depends on how the user is stored when the user logged in. + +If the user information is stored in the `VaadinSession`, that session +should be closed using its `close()` method. If the information on the +other hand is stored in the `HttpSession` or `PortletSession`, then that +session should be invalidated using the `invalidate()` method in Vaadin's +`WrappedSession` that represents either underlying session type. + +Aside from removing the user's information, the user should also be +redirected to a logout page to avoid keeping the UI open in the browser +after all server-side information about is has been removed. + +[source,java] +.... +private void logout() { + // Close the VaadinServiceSession + getUI().getSession().close(); + + // Invalidate underlying session instead if login info is stored there + // VaadinService.getCurrentRequest().getWrappedSession().invalidate(); + + // Redirect to avoid keeping the removed UI open in the browser + getUI().getPage().setLocation(getLogoutPageLocation()); +} +.... diff --git a/documentation/articles/MVCBasicsInITMillToolkit.asciidoc b/documentation/articles/MVCBasicsInITMillToolkit.asciidoc new file mode 100644 index 0000000000..437a2a5817 --- /dev/null +++ b/documentation/articles/MVCBasicsInITMillToolkit.asciidoc @@ -0,0 +1,140 @@ +[[mvc-basics-in-itmill-toolkit]] +MVC Basics in IT Mill Toolkit +----------------------------- + +The Goal +^^^^^^^^ + +image:img/moduleDesign.jpg[1] + +We want to create a simple UI following the MVC pattern using the IT Mill Toolkit. The project components need to have low coupling and follow an enterprise design. In our example we also want to retrieve information from a database and display it in the view. The different parts of the UI need also to be able to communicate with eachother. + +We have divided the project in two layers; A UI layer, which purpose is to display information to the user, and a Data layer which has no knowledge of the Toolkit and which is only responsible for retrieving and storing data. The reason for dividing the project up in these layers is so that, if we choose, we can easily use multiple servers. + +The Data layer +^^^^^^^^^^^^^^ + +For the example we have created a ''Database.java'' class which will function as our database. We will never call upon this database directly from the UI. To access the data we will have the UI controllers contact the ''Authentication.java'' or ''Channel.java'' which will retrieve it for us. + +image:img/view.jpg[1] + +image:img/ActivityUML.jpg[1] + +The UI layer +^^^^^^^^^^^^ + +First off lets discuss what we mean with ''View''. The Toolkit is such an flexible tool that the term needs to be defined on pretty much a case by case basis. In this example we have decided to let the center portion of the UI be the View. + +In our example the UI consists of the Header, Menu and View. When the user chooses a item from the menu we need to easily update the View or in our case, switch View completely. We want to do this in such a way that we don't couple the different UI components together so that we can easily add extra components if needed. To achieve this we use the Observer pattern which is easily implemented in the Toolkit using ''Events''. + +== The Controller == + +We started off by creating the ''UiHandler.java'' class where we define which components we want to add to our UI. This class will also work as the mediator for the different components by adding ''Listeners'' and monitoring for events in the components. + +[source,java] +.... +public class UiHandler extends VerticalLayout { + // Portions of the application that exist at all times. + private Header header; + private WelcomeView defaultView; + + // The views that are shown to logged users. + private UserView userView; + private ChannelView itmillView; + private ChannelView ubuntuView; + + private Menu menu; + private SplitPanel menusplit; + + // Used to keep track of the current main view. + private HashMap viewList = new HashMap(); + +... +} +.... + +We want to listen for changes in the menu which indicates that the user has chosen a new item and wants to change view. The menu consists of a Tree component which generates a ''ValueChangeEvent'' when a new item is selected from the tree. We catch these types of events in the UiHandler by adding a UserChangeListener in the ExampleApplication.java init() method. + +[source,java] +.... +public class ExampleApplication extends Application implements TransactionListener { + public UiHandler ui; + + @Override + public void init() { + // sets the current application to ThreadLocal. + setProject(this); + + // Creates the Main Window and then hands over all UI work to the + // UiHandler + setMainWindow(new Window("MVC Example Application")); + + setTheme("MVCExampleDefault"); + + ui = new UiHandler(getMainWindow()); + + // Adds a TransactionListener for this class. + getContext().addTransactionListener(this); + + // Register user change listener for UiHandler. + addListener(ui); + } +} +.... + +[source,java] +.... +public class UiHandler extends VerticalLayout implements UserChangeListener { + public void applicationUserChanged(UserChangeEvent event) { + // The value is null if the user logs out. + if (event.getNewUser() == null) { + userLoggedOut(); + } else { + userLoggedIn(); + } + } +} +.... + +The menu is now isolated with no knowledge about other components. This gives us great flexibility with adding new instances of the menu if needed. + +The View +^^^^^^^^ + +Following the MVC-pattern we have removed all control logic from the Views and transferred it to the controllers. The Views now consist only of the elements needed to display the data while the controllers handle the retrieving and manipulating of said data. The separation between control logic and View is done so that, if needed, we may have many different views displaying the same data without having to copy code. We can now simply add a controller to each new View to gain the same data functionality as any other View. + +[source,java] +.... +public class ChannelView extends AbstractView { + protected Window confirm; + private ChannelController controller; + + public void sendMessage() { + // Let the controller modify the current text on the inputline and + // insert it into the channel text table. + controller.writeToChannel(inputLine.getValue(), textTable); + ... + } +} +.... + +When creating a project you may want to have different views displayed at different times sosetting the view is an easy task. We are using the SplitPanel component to create two sections in the UI. Adding components to the ''SplitPanel'' is achieved with ''setFirstComponent(c)'' to add on the left side and ''setSecondComponent(c)'' to add on the right side of the split. By our definition, our view is the area on the right side of the split. Had we been using the Layout component we could have achieved the same result using ''replaceComponent(oldComponent, newComponent)''. + +[source,java] +.... +// Set the menu on the left side of the split. +menusplit.setFirstComponent(menu); + +// Set the user welcome View on the right side. +setMainView(userView); + +... + +public void setMainView(AbstractView c) { + menusplit.setSecondComponent(c); +} +.... + +Setting/Switching the View is now as easy as simply replacing the second component in the the SplitPanel using ''setMainView''. + +The source code for this project can be found in the MVCBasicsProject.zip file where we've added the .project and .classpath for your convinience, in case you are a Eclipse user. Remove these files if you use some other IDE. diff --git a/documentation/articles/OptimizingSluggishUI.asciidoc b/documentation/articles/OptimizingSluggishUI.asciidoc new file mode 100644 index 0000000000..317bd16fb5 --- /dev/null +++ b/documentation/articles/OptimizingSluggishUI.asciidoc @@ -0,0 +1,191 @@ +[[optimizing-sluggish-ui]] +Optimizing sluggish UI +---------------------- + +Is your Vaadin application becoming sluggish? Yes, this can happen - it +is no secret. This can happen for every application, with every +programming language, with every UI library and with all hardware +platforms. Make it a web application and it is not even hard. For end +users this is not acceptable, especially when building applications for +frequent use. + +All developers have heard the phrase _premature optimization is the root +of all evil_, coined by software guru +http://www.google.com/search?&rls=en&q=premature+optimization+is+the+root+of+all+evil&ie=UTF-8&oe=UTF-8[Donald +Knuth]. There is a wisdom in that clause. Still I want to motivate you +(Vaadin developer) to read this article, even if you currently have no +performance issues. I'd say it is not that bad to know what will +inevitably make your application slow. You might subconsciously avoid +the worst pitfalls (but still not be subjected to premature +optimization) and avoid optimization task totally. + +Resolving performance issues in Vaadin-based applications may be a bit +tricky in some situations. Performance issues are one of the most common +issues why project managers in IT Mill come and disturb our "peace" in +the RnD team. Usually we'll end up modifying the application, not +Vaadin. Vaadin abstracts away the browser environment, and the +abstraction may make it hard to figure out what is the actual cause for +a slow UI. + +The first step is to detect whether to optimize the server side or the +client side. You can use all standard profiling tools with Vaadin apps +like Firebug for the client side and JProfiler for the server side. For +a quick look for what is taking so long it is easy to use "?debug" query +parameter in application. It will show you a small floating console in +the browser. Inspecting messages there, one can see server visit time +(includes both network latency and server processing time) and the +actual time spent handling the response in client. + +If the problem is on server side, it is most commonly in the back-end +system or how it is connected to Vaadin components. The server side code +of Vaadin is pretty well optimized by the JVM. If the server side is +your problem, I'd bet you will end up optimizing SQL queries. Optimizing +tricks for server side are very similar to any other Java application. + +If it is the client side processing that takes a long time, optimizing +methods are more Vaadin specific. There are several tricks one can +perform to optimize the client side processing time. Some of them are +more or less generic to ajax applications in common, others are purely +Vaadin specific tricks. If you belong to the large group of Java +developers who hate browser programming, you don't need to get worried +at this point. Although the processing time is long on client, you will +be mostly modifying the pure server side Java code when optimizing your +application. + +[[best-tricks-to-makekeep-your-vaadin-apps-ui-responsive]] +Best tricks to make/keep your Vaadin apps UI responsive +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[[render-less-components]] +#1 Render less components +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The most common cause for slow rendering time is that you are rendering +a lot of components.It's easy to forget that the browser is always the +browser, and too much complicated stuff will cause slowness. The +JavaScript engines have been optimized a lot lately, but the actual +rendering is still a bottleneck. + +* consider if you can use one component instead of many (eg. instead of +using one label per line, use a label with multiple lines using html : +label.setContentMode(Label.CONTENT_XHTML) ) +* hide rarely used features (this also improves usability) when possible + +[[try-to-keep-component-tree-simple-flat]] +#2 Try to keep component tree simple (flat) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When component tree (the hierarchy of components, not the 'Tree' +component) gets deeper (more components inside others) the rendering +task gets heavier for browsers. As the growth is more than linear, I +have split this from previous hint. To really show you the importance of +this tip, I made a small example application. Try it at: +http://uilder.virtuallypreinstalled.com/run/deepcomponenttrees/?restartApplication&debug + + Tips for keeping the component tree simple: + +* Avoid for example using vertical layouts inside another vertical +layouts when possible +* Do you need to extend CustomComponent in your server side composition +or could you just extend some layout? This will result having one +component less in the component tree. You might sometimes be argueing +against this because of architectual reasons (CustomComponent has a +fewer methods than VerticalLayout), but on the other hand Java has +interfaces to deal the issue in a cleaner manner. +* Maybe you have an  extra layout inside your Panel or Window (see +setContent method)? This is a common pitfall for Vaadin newcomers. + +[[use-the-right-component]] +#3 Use the right component +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some components in Vaadin are just faster to render than others. For +example our standard VerticalLayout and HorizontaLayout have a huge +feature set supporting for example spacing, margin, alignments and +expand ratios. Supporting all these comes with a price of performance +hit. Rendering a lot of simple components into CssLayout (which does not +support all those features), is often several times faster than into the +default layouts. + +So favor simpler components in your application if you don't need all +those features. This will be essential in your frequently recycled +server side compositions. So consider if you could use: + +* Vertical/HorizontalLayout instead of GridLayout. +* single GridLayout instead of multiple nested +Vertical/HorizontalLayouts. +* CssLayout (available in standard distribution since 6.1) instead of +full featured HorizontalLayout. +* GridLayout (or even FastGrid from FastLayouts incubator project) +instead of Table. Table is meant for displaying tabular data, GridLayout +is meant for laying out components. + +In some extreme cases it may be a viable option to build optimized +client side component instead of using pure server side composition. It +is not the easiest path to take as you need to work in browser +environment too, but you then have a full control of what is happening. +With custom client side component one can also more easily optimize also +the data transferred between client and server. Refer to manual for more +information. + +[[use-table-efficiently]] +#4 Use Table efficiently +^^^^^^^^^^^^^^^^^^^^^^^^ + +Table is one of the most optimized component in Vaadin, both server and +client side. Still it is very easy to put both client and server on its +knees with it. Common things to check if you have performance issues +with Table: + +* make sure the container used in table loads data lazily from back-end +if you have huge amounts of data +* using the editable mode or ColumnGenerator can make a huge amount of +components to be rendered on client. Especially if table size is +maximized. Consider using lighter components in Table (like putting +complex property editor into PopupView instead of straight to table +cell) +* Don't overuse layouts in table, use CssLayout instead of others when +possible +* Use lazy-loading of rows, don't render all rows at once +* Minimize caching with setCacheRate function, if you have heavy table +body (like large editable table with several columns). + +[[avoid-complex-custom-layouts]] +#5 Avoid complex custom layouts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With CustomLayouts it is common to use html tables to build complex +layout. Using html tables as a layout has several drawbacks like heavy +rendering and browser differences. Rendering Vaadin components into a +complex table based dom structure may be much slower than into a simple +div based layout. The core reason for this optimization is the same as +in trick #2 : the rendering is more more expensive in complex dom +structures. + +[[use-a-light-theme]] +#6 Use a light theme +^^^^^^^^^^^^^^^^^^^^ + +The effect of theme may be radical in some cases. Believe it or not, but +I have seen cases where rendering time triples just by using a different +themes. Heavy theme combined with a deep component tree is something +that will really test the speed of browsers rendering engine. For +optimizing theme you can google some generic instructions.  Minify, +gzip, use simple (and fewer) selectors, optimize images, use +transparency moderately. + + Sizing components can be done in both server side Java code and in +themes css. Both approaches have some good and bad features. Don't use +both methods at the same time for the same component, it may render +improperly and add an extra performance hit. + +[[use-generic-component-features-moderately]] +#7 Use generic component features moderately +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All Vaadin components have captions, icons and error indicators. All of +them adds extra burden to client side rendering engine, just like extra +components. As captions, icons and errors are also packed with +surprisingly wide set of features (see ticket +http://dev.vaadin.com/ticket/1710[#1710] in trac), in some cases it may +even be faster to use extra Label or Embedded instead of them. diff --git a/documentation/articles/RememberToTheSetTheLocale.asciidoc b/documentation/articles/RememberToTheSetTheLocale.asciidoc new file mode 100644 index 0000000000..042682e234 --- /dev/null +++ b/documentation/articles/RememberToTheSetTheLocale.asciidoc @@ -0,0 +1,183 @@ +[[remember-to-the-set-the-locale]] +Remember to the set the locale +------------------------------ +The Locale of an application or an individual component dictates the +language and format used for displaying and parsing numbers and dates. +This includes things like names of months, 12 or 24 hour time formats, +the order of days and months in dates, and decimal separators in +numbers. + +_Displaying_ values in a locale foreign to the user is bad enough. +Forcing your users to _enter_ values in a foreign locale (such as +decimal separator periods instead of commas, or vice versa) can be +considered a cruel (although sadly not particularly unusual) punishment. + +A Vaadin application’s locale, if not explicitly set, defaults to the +locale defined in the request headers sent by the browser , or, if +that’s missing, the locale returned by `java.util.Locale.getDefault()`, +which in turn is the default locale of the Java Virtual Machine, which +depends on the configuration of the environment in which it happens to +be running. Either way, chances are that the end result does not match +what your users expect. + +[[per-component]] +Per Component +~~~~~~~~~~~~~ + +Vaadin components have a *`setLocale()`* method that allows specifying +the locale separately for each component. + +[source,java] +.... +InlineDateField datePicker = new InlineDateField(); +datePicker.setLocale( java.util.Locale.CANADA_FRENCH ); +.... + +[[inheritance]] +Inheritance +^^^^^^^^^^^ + +A component _inherits its locale_ from its parent. So setting the locale +on a component affects its nested children components by default. +Remember that layouts and even the +https://vaadin.com/api/7.2.5/com/vaadin/ui/UI.html[UI] (Vaadin 7) object +are components too, so setting their locale affects their content. + +[[session-default]] +Session Default +~~~~~~~~~~~~~~~ + +Instead of setting a locale for each individual component, you may set a +Session-wide default. The components inherit that property. You may +continue to override this session-default locale for individual +components, where needed, with a call to `setLocale`. + +Setting the default locale changed between Vaadin 6 and 7. + +[[in-vaadin-6]] +In Vaadin 6 +^^^^^^^^^^^ + +In Vaadin 6, you set the locale by calling +https://vaadin.com/api/6.8.9/com/vaadin/Application.html#setLocale(java.util.Locale)[`setLocale`]method +on the +https://vaadin.com/api/6.8.9/com/vaadin/Application.html[`Application`] +object. See +https://vaadin.com/book/vaadin6/-/page/advanced.global.html[chapter +12.14 Accessing Session-Global Data] of the Book of Vaadin, Vaadin 6 +edition, for important information about accessing the Application +object. + +[[in-vaadin-7]] +In Vaadin 7 +^^^^^^^^^^^ + +In Vaadin session, you must go through the current `VaadinSession` +object to call `setLocale`. You may access that object in either of two +ways: + +* Through that class’ static method `getCurrent` + +* Jumping from a component object to a UI object to the current +VaadinSession object. + +[[bug-workaround]] +Bug & Workaround\\ +++++++++++++++++++ + +Unfortunately, there is a bug (or design issue) in Vaadin 7. See +http://dev.vaadin.com/ticket/12350[ticket 12350]. The problem is that +setting the locale of the VaadinSession does not affect already existing +UI objects. So, while the `init` method of your app's UI is the natural +place to set the session's locale, doing so does not take effect in that +current UI until after a page refresh. + +The *workaround* is to explicitly set the current UI object's locale, in +addition to setting the VaadinSession object's locale. The first affects +the current UI, while the second affects any future UI objects that may +be instantiated in your app. + +This ( if in a UI object's "init" method)… + +[source,java] +.... +Locale locale = Locale.CANADA_FRENCH; +this.setLocale( locale ); // Call to affect this current UI. Workaround for bug: http://dev.vaadin.com/ticket/12350 +this.getSession().setLocale( locale ); // Affects only future UI instances, not current one because of bug. See workaround in line above. +// VaadinSession.getCurrent().setLocale( locale ); // Alternative to "this.getSession". +.... + +…or this ( if not in a UI object, add "getUI()" )… + +[source,java] +.... +Locale locale = Locale.CANADA_FRENCH; +this.getUI().setLocale( locale ); // Call to affect this current UI. Workaround for bug: http://dev.vaadin.com/ticket/12350 +this.getUI().getSession().setLocale( locale ); // Affects only future UI instances, not current one because of bug. See workaround in line above. +// VaadinSession.getCurrent().setLocale( locale ); // Alternative to "this.getSession". +.... + +[[example-app]] +Example App +^^^^^^^^^^^ + +Here is source code for a complete Vaadin 7 example app. + +[source,java] +.... +package com.example.vaadinexperiment; + +import com.vaadin.annotations.Theme; +import com.vaadin.annotations.VaadinServletConfiguration; +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinServlet; +import com.vaadin.server.VaadinSession; +import com.vaadin.ui.InlineDateField; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; +import java.util.Locale; +import javax.servlet.annotation.WebServlet; + +@Theme ( "mytheme" ) +@SuppressWarnings ( "serial" ) +public class MyVaadinUI extends UI +{ + + @WebServlet ( value = "/*" , asyncSupported = true ) + @VaadinServletConfiguration ( productionMode = false , ui = MyVaadinUI.class , widgetset = "com.example.vaadinexperiment.AppWidgetSet" ) + public static class Servlet extends VaadinServlet + { + } + + @Override + protected void init ( VaadinRequest request ) + { + final VerticalLayout layout = new VerticalLayout(); + layout.setMargin( true ); + layout.setSpacing( true ); + setContent( layout ); + + Locale locale = Locale.CANADA_FRENCH; + this.setLocale( locale ); // Call to affect this current UI. Workaround for bug: http://dev.vaadin.com/ticket/12350 + this.getSession().setLocale( locale ); // Affects only future UI instances, not current one because of bug. See workaround in line above. + // VaadinSession.getCurrent().setLocale( locale ); // Alternative to "this.getSession". + + InlineDateField datePicker = new InlineDateField(); + datePicker.setCaption( "This component’s locale → defaults to parent’s, → which defaults to VaadinSession’s, → which defaults to JVM" ); + layout.addComponent( datePicker ); + + InlineDateField datePickerFinnish = new InlineDateField(); + datePickerFinnish.setCaption( "This component’s default locale is overridden for Finnish" ); + datePickerFinnish.setLocale( new Locale( "fi" , "FI" ) ); + layout.addComponent( datePickerFinnish ); + } + +} +.... + +image:http://i.imgur.com/w9CViCR.png[Calendar] + +''''' + +Information here drawn from +http://stackoverflow.com/q/16331112/642706[this StackOverflow.com +question]. diff --git a/documentation/articles/ScalableWebApplications.asciidoc b/documentation/articles/ScalableWebApplications.asciidoc new file mode 100644 index 0000000000..83ae8d6ee3 --- /dev/null +++ b/documentation/articles/ScalableWebApplications.asciidoc @@ -0,0 +1,723 @@ +[[scalable-web-applications]] +Scalable web applications +------------------------- + +[[introduction]] +Introduction +^^^^^^^^^^^^ + +Whether you are creating a new web application or maintaining an +existing one, one thing you certainly will consider is the scalability +of your web application. Scalability is your web application’s ability +to handle a growing number of concurrent users. How many concurrent +users can, for instance, your system serve at its peak usage? Will it be +intended for a small scale intranet usage of tens to hundreds of +concurrent users, or do you plan to reach for a medium size global web +application such as 500px.com with about 1000-3000 concurrent users. Or +is your target even higher? You might wonder how many concurrent users +there are in Facebook or Linkedin. We wonder about that too, and thus +made a small study to estimate it. You can see the results in Figure 1 +below. The estimates are derived from monthly visitors and the average +visit time data found from Alexa.com.  + +image:img/webusers.png[image] + +_Figure 1: Popular web applications with estimated number of concurrent +users._ + +The purpose of this article is to show you common pain points which tend +to decrease the scalability of your web applications and help you find +out ways to overcome those. We begin by introducing you to our example +application. We will show you how to test the scalability of this +example application with Gatling, a tool for stress testing your web +application. Then, in the next chapters, we will go through some pain +points of scalability, such as memory, CPU, and database, and see how to +overcome these. + +[[book-store-inventory-application]] +Book store inventory application +-------------------------------- + +Throughout this example we’ll use a book store inventory application +(see Figure 2) as an example application when deep diving into the world +of web application scalability. The application contains a login view +and an inventory view with CRUD operations to a mockup data source. It +also has the following common web application features: responsive +layouts, navigation, data listing and master detail form editor. This +application is publicly available as a Maven archetype +(`vaadin-archetype-application-example`). We will first test how many +concurrent users the application can serve on a single server. + +image:img/mockapp-ui.png[image] + +_Figure 2: Book store inventory application_ + +The purpose of scalability testing is to verify whether the +application's server side can survive with a predefined number of +concurrent users or not. We can utilize a scalability test to find the +limits, a breaking point or server side bottlenecks of the application. +There are several options for scalability testing web applications. One +of the most used free tools is Apache JMeter. JMeter suits well for +testing web applications, as long as the client-server communication +does not use websockets. When using asynchronous websocket +communication, one can use the free Gatling tool or the commercial +NeoLoad tool. + +You can find a lot of step by step tutorials online on how to use +Gatling and JMeter. There is typically a set of tips and tricks that one +should take into account when doing load testing on certain web +frameworks, such as the open source Vaadin Framework. For more +information on Vaadin specific tutorials, check the wiki pages on +https://vaadin.com/scalability[vaadin.com/scalability]. + +Gatling and JMeter can be used to record client to server requests of a +web application. After recording, the recorded requests can be played +back by numbers of concurrent threads. The more threads (virtual users) +you use the higher the simulated load generated on the tested +application. + +Since we want to test our application both in synchronous and +asynchronous communication modes, we will use Gatling. Another benefit +of Gatling compared to JMeter is that it is less heavy for a testing +server, thus more virtual users can be simulated on a single testing +server. Figure 3 shows the Gatling settings used to record the example +scenario of the inventory application. Typically all static resources +are excluded from the recording (see left bottom corner of the figure), +since these are typically served from a separate http server such as +Nginx or from a CDN (Content Delivery Network) service. In our first +test, however, we still recorded these requests to see the worst case +situation, where all requests are served from a single application +server. + +image:img/figure3s2.png[image] + +_Figure 3: Gatling recorder._ + +Gatling gathers the recorded requests as text files and composes a Scala +class which is used to playback the recorded test scenario. We planned a +test scenario for a typical inventory application user: The user logs in +and performs several updates (in our case 11) to the store in a +relatively short time span (3 minutes). We also assumed that they leave +the inventory application open in their browser which will result in the +HttpSession not closing before a session timeout (30min in our case). + +Let’s assume that we have an extremely large bookstore with several +persons (say 10000) responsible for updating the inventory. If one +person updates the inventory 5 times a day, and an update session takes +3 minutes, then with the same logic as we calculated concurrent users in +the Introduction, we will get a continuous load of about 100 concurrent +users. This is of course not a realistic assumption unless the +application is a global service or it is a round-the-clock used local +application, such as a patient information system. For testing purposes +this is, however, a good assumption. + +A snippet from the end of our test scenario is shown in Figure 4. This +test scenario is configured to be run with 100 concurrent users, all +started within 60 seconds (see the last line of code). + +[source,scala] +.... +.pause(9) +.exec(http(>"request_45") + .post(>"/test/UIDL/?v-uiId=0") + .headers(headers_9) + .body(RawFileBody(>"RecordedSimulation_0045_request.txt"))) +.pause(5) +.exec(http(>"request_46") + .post(>"/test/UIDL/?v-uiId=0") + .headers(headers_9) + .body(RawFileBody(>"RecordedSimulation_0046_request.txt")) + .resources(http(>"request_47") + .post(uri1 + >"/UIDL/?v-uiId=0") + .headers(headers_9) + .body(RawFileBody(>"RecordedSimulation_0047_request.txt"))))} +setUp(scn.inject(rampUsers(100) over (60 seconds))).protocols(httpProtocol) +.... + +_Figure 4: Part of the test scenario of inventory application._ + +To make the test more realistic, we would like to execute it several +times. Without repeating we do not get a clear picture of how the server +will tolerate a continuous high load. In a Gatling test script, this is +achieved by wrapping the test scenario into a repeat loop. We should +also flush session cookies to ensure that a new session is created for +each repeat. See the second line of code in Figure 5, for an example of +how this could be done. + +[source,scala] +.... +val scn = scenario("RecordedSimulation") + .repeat(100,"n"){exec(flushSessionCookies).exec(http("request_0") + .get("/test/") + .resources(http("request_1") + .post(uri1 + "/?v-1440411375172") + .headers(headers_4) + .formParam("v-browserDetails", "1") + .formParam("theme", "mytheme") + .formParam("v-appId", "test-3556498") +.... + +_Figure 5: Repeating 100 times with session cookie flushing (small part +of whole script)_ + +We tested how well this simple example application tolerated several +concurrent users. We deployed our application in Apache Tomcat 8.0.22 on +a Windows 10 machine with Java 1.7.0 and an older quad core mobile Intel +i7 processor. With its default settings (using the default heap size of +2GB), Tomcat was able to handle about 200 concurrent users for a longer +time. The CPU usage for that small number of concurrent users was not a +problem (it was lower than 5%), but the server configurations were a +bottleneck. Here we stumbled upon the first scalability pain point: +server configuration issues (see next chapter). It might sound +surprising that we could only run a such small number of concurrent +users by default, but do not worry, we are not stuck here. We will see +the reasons for this and other scalability pain points in the following +chapter. + +[[scalability-pain-points]] +Scalability pain points +----------------------- + +We will go through typical pain points of a web application developer +which she (or he) will encounter when developing a web application for +hundreds of concurrent users. Each pain point is introduced in its own +subchapter and followed by typical remedies. + +[[server-configuration-issues]] +Server configuration issues +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One typical problem that appears when there are lots of concurrent +users, is that the operating system (especially the *nix based ones) run +out of file descriptors. This happens since most *nix systems have a +pretty low default limit for the maximum number of open files, such as +network connections. This is usually easy to fix with the `ulimit` +command though sometimes it might require configuring the `sysctl` too. + +A little bit unexpected issues can also surface with network bandwidth. +Our test laptop was on a wireless connection and its sending bandwidth +started choking at about 300 concurrent users. (Please note that we use +an oldish laptop in this entire test to showcase the real scalability of +web apps –your own server environment will no doubt be even more +scalable even out of the box.) One part of this issue was the wifi and +another part was that we served the static resources, such as javascript +files, images and stylesheets, from Tomcat. At this point we stripped +the static resources requests out of our test script to simulate the +situation where those are served from a separate http server, such as +nginx. Please read the blog post +“https://vaadin.com/blog/-/blogs/optimizing-hosting-setup[Optimizing +hosting setup]” from our website for more information about the topic. + +Another quite typical configuration issue is that the application server +is not configured for a large number of concurrent users. In our +example, a symptom of this was that the server started rejecting +(“Request timed out”) new connections after a while, even though there +were lots of free memory and CPU resources available. + +After we configured our Apache Tomcat for high concurrent mode and +removed static resource requests, and connected the test laptop into a +wired network, we were able to push the number of concurrent users from +200 up to about 500 users. Our configuration changes into the server.xml +of Tomcat are shown in Figure 6, where we define a maximum thread count +(10240), an accepted threads count (4096), and a maximum number of +concurrent connections (4096). + +image:img/figure6a.png[image] + +_Figure 6: Configuring Tomcat’s default connector to accept a lot of +concurrent users._ + +The next pain point that appeared with more than 500 users was that we +were out of memory. The default heap size of 2GB eventually ran out with +such high number of concurrent users. On the other hand, there was still +a lot of CPU capacity available, since the average load was less than +5%. + +[[out-of-memory]] +Out of memory +~~~~~~~~~~~~~ + +Insufficient memory is possibly the most common problem that limits the +scalability of a web application with a state. An http session is used +typically to store the state of a web application for its user. In +Vaadin an http session is wrapped into a `VaadinSession`. A +VaadinSession contains the state (value) of each component (such as +`Grid`, `TextFields` etc.) of the user interface. Thus, +straightforwardly the more components and views you have in your Vaadin +web application, the bigger is the size of your session. + +In our inventory application, each session takes about 0.3MB of memory +which is kept in memory until the session finally closes and the garbage +collectors free the resources. The session size in our example is a +little bit high. With constant load of 100 concurrent users, a session +timeout of 30 minutes and an average 3 minutes usage time, the expected +memory usage is about 350MB. To see how the session size and the number +of concurrent users affect the needed memory in our case, we made a +simple analysis which results are shown in Figure 7. We basically +calculated how many sessions there can exist at most, by calculating how +many users there will be within an average usage time plus the session +timeout. + +image:img/figure6s.png[image] + +_Figure 7: Memory need for varying size sessions and a different number +of concurrent users._ + +[[remedies]] +Remedies +^^^^^^^^ + +[[use-more-memory]] +Use more memory ++++++++++++++++ + +This might sound simplistic, but many times it might be enough to just +add as much memory as possible to the server. Modern servers and server +operating systems have support for hundreds of gigabytes of physical +memory. For instance, again in our example, if the size of a session +would be 0.5MB and we had 5000 concurrent users, the memory need would +be about 28GB. + +You also have to take care that your application server is configured to +reserve enough memory. For example, the default heap size for Java is +typically 2GB and for example Apache Tomcat will not reserve more memory +if you do not ask it to do it with **`-Xmx`** JVM argument. You might +need a special JVM for extremely large heap sizes. We used the following +Java virtual machine parameters in our tests: + +.... +-Xms5g -Xmx5g -Xss512k -server +.... + +The parameters **`-Xms`** and **`-Xmx`** are for setting the minimum and +the maximum heap size for the server (5 GB in the example), the `-Xss` +is used to reduce the stack size of threads to save memory (typically +the default is 1MB for 64bit Java) and the `-server` option tells JVM +that the Java process is a server. + +[[minimize-the-size-of-a-session]] +Minimize the size of a session +++++++++++++++++++++++++++++++ + +The biggest culprit for the big session size in the inventory +application is the container (BeanItemContainer) which is filled with +all items of the database. Containers, and especially the built in fully +featured BeanItemContainer, are typically the most memory hungry parts +of Vaadin applications. One can either reduce the number of items loaded +in the container at one time or use some lightweight alternatives +available from Vaadin Directory +(https://vaadin.com/directory[vaadin.com/directory]) such as Viritin, +MCont, or GlazedLists Vaadin Container. Another approach is to release +containers and views to the garbage collection e.g. every time the user +switches into another view, though that will slightly increase the CPU +load since the views and containers have to be rebuilt again, if the +user returns to the view. The feasibility of this option is up to your +application design and user flow –usually it’s a good choice. + +[[use-a-shorter-session-time-out]] +Use a shorter session time out +++++++++++++++++++++++++++++++ + +Since every session in the memory reserves it for as long as it stays +there, the shorter the session timeout is, the quicker the memory is +freed. Assuming that the average usage time is much shorter than the +session timeout, we can state that halving the session timeout +approximately halves the memory need, too. Another way to reduce the +session’s time in the memory could be instructing users to logout after +they are done. + +The session of a Vaadin application is kept alive by requests (such as +user interactions) made from the client to the server. Besides user +interaction, the client side of Vaadin application sends a heartbeat +request into the server side, which should keep the session alive as +long as the browser window is open. To override this behaviour and to +allow closing idle sessions, we recommend that the `closeIdleSessions` +parameter is used in your servlet configuration. For more details, see +chapter +https://vaadin.com/book/-/page/application.lifecycle.html[Application +Lifecycle] in the Book of Vaadin. + +[[use-clustering]] +Use clustering +++++++++++++++ + +If there is not enough memory, for example if there is no way to reduce +the size of a session and the application needs a very long session +timeout, then there is only one option left: clustering. We will discuss +clustering later in the Out of CPU chapter since clustering is more +often needed for increasing CPU power. + +[[out-of-cpu]] +Out of CPU +~~~~~~~~~~ + +We were able to get past the previous limit of 500 concurrent users by +increasing the heap size of Tomcat to 5GB and reducing the session +timeout to 10 minutes. Following the memory calculations above, we +should theoretically be able to serve almost 3000 concurrent users with +our single server, if there is enough CPU available. + +Although the average CPU load was rather low (about 10%) still with 800 +concurrent users, it jumped up to 40% every now and then for several +seconds as the garbage collector cleaned up unused sessions etc. That is +also the reason why one should not plan to use full CPU capacity of a +server since that will increase the garbage collection time in worst +case even to tens of seconds, while the server will be completely +unresponsive for that time. We suggest that if the average load grows to +over 50% of the server’s capacity, other means have to be taken into use +to decrease the load of the single server. + +We gradually increased the number of concurrent users to find out the +limits of our test laptop and Tomcat. After trial and error, we found +that the safe number of concurrent users for our test laptop was about +1700. Above that, several request timeout events occurred even though +the CPU usage was about 40-50% of total capacity. We expect that using a +more powerful server, we could have reached 2000-3000 concurrent users +quite easily. + +[[remedies-1]] +Remedies +^^^^^^^^ + +[[analyze-and-optimize-performance-bottlenecks]] +Analyze and optimize performance bottlenecks +++++++++++++++++++++++++++++++++++++++++++++ + +If you are not absolutely sure about the origin of the high CPU usage, +it is always good to verify it with a performance profiling tool. There +are several options for profiling, such as JProfiler, XRebel, and Java +VisualVM. We will use VisualVM in this case since it comes freely with +every (Oracle’s) JDK since the version 1.5. + +Our typical procedure goes like this: 1. Deploy your webapp and start +your server, 2. Start VisualVM and double click your server’s process +(“e.g. Tomcat (pid 1234)”) on the Applications tab (see Figure 8), 3. +Start your load test script with, for instance, 100 concurrent users, 4. +Open the Sampler tab to see where the CPU time is spent, 5. Use the +filter on the bottom to show the CPU usage of your application (e.g. +“`biz.mydomain.projectx`”) and possible ORM (Object-relational mapping) +framework (e.g. “`org.hibernate`”) separately. + +Typically, only a small part (e.g. 0.1 - 2 %) of CPU time is spent on +the classes of your webapp, if your application does not contain heavy +business logic. Also, CPU time spent on the classes of Vaadin should be +very small (e.g. 1%). You can be relaxed about performance bottlenecks +of your code if the most time (>90%) is spent on application server’s +classes (e.g. “`org.apache.tomcat`”). + +Unfortunately, quite often database functions and ORM frameworks take a +pretty big part of CPU time. We will discuss how to tackle heavy +database operations in the Database chapter below. + +image:img/figure7s.png[image] + +_Figure 8: Profiling CPU usage of our inventory application with Java +VisualVM_ + +[[use-native-application-server-libraries]] +Use native application server libraries ++++++++++++++++++++++++++++++++++++++++ + +Some application servers (at least Tomcat and Wildfly) allow you to use +native (operating system specific) implementation of certain libraries. +For example, The Apache Tomcat Native Library gives Tomcat access to +certain native resources for performance and compatibility. Here we +didn’t test the effect of using native libraries instead of standard +ones. With little online research, it seems that the performance benefit +of native libraries for Tomcat is visible only if using secured https +connections. + +[[fine-tune-java-garbage-collection]] +Fine tune Java garbage collection ++++++++++++++++++++++++++++++++++ + +We recommended above not to strain a server more than 50% of its total +CPU capacity. The reason was that above that level, a garbage collection +pause tends to freeze the server for too long a time. That is because it +typically starts not before almost all of the available heap is already +spent and then it does the full collection. Fortunately, it is possible +to tune the Java garbage collector so that it will do its job in short +periods. With little online study, we found the following set of JVM +parameters for web server optimized garbage collection + +.... +-XX:+UseCMSInitiatingOccupancyOnly +-XX:CMSInitiatingOccupancyFraction=70 +.... + +The first parameter prevents Java from using its default garbage +collection strategy and makes it use CMS (concurrent-mark-sweep) +instead. The second parameter tells at which level of “occupancy” the +garbage collection should be started. The value 70% for the second +parameter is typically a good choice but for optimal performance it +should be chosen carefully for each environment e.g. by trial and error. + +The CMS collector should be good for heap sizes up to about 4GB. For +bigger heaps there is the G1 (Garbage first) collector that was +introduced in JDK 7 update 4. G1 collector divides the heap into regions +and uses multiple background threads to first scan regions that contain +the most of garbage objects. Garbage first collector is enabled with the +following JVM parameter. + +.... +-XX:+UseG1GC +.... + +If you are using Java 8 Update 20 or later, and G1, you can optimize the +heap usage of duplicated Strings (i.e. their internal `char[]` arrays) +with the following parameter. + +.... +-XX:+UseStringDeduplication +.... + +[[use-clustering-1]] +Use clustering +++++++++++++++ + +We have now arrived at the point where a single server cannot fulfill +our scalability needs whatever tricks we have tried. If a single server +is not enough for serving all users, obviously we have to distribute +them to two or more servers. This is called clustering. + +Clustering has more benefits than simply balancing the load between two +or more servers. An obvious additional benefit is that we do not have to +trust a single server. If one server dies, the user can continue on the +other server. In worst case, the user loses her session and has to log +in again, but at least she is not left without the service. You probably +have heard the term “session replication” before. It means that the +user’s session is copied into other servers (at least into one other) of +the cluster. Then, if the server currently used by the user goes down, +the load balancer sends subsequent requests to another server and the +user should not notice anything. + +We will not cover session replication in this article since we are +mostly interested in increasing the ability to serve more and more +concurrent users with our system. We will show two ways to do clustering +below, first with Apache WebServer and Tomcats and then with the Wildfly +Undertow server. + +[[clustering-with-apache-web-server-and-tomcat-nodes]] +Clustering with Apache Web Server and Tomcat nodes +++++++++++++++++++++++++++++++++++++++++++++++++++ + +Traditionally Java web application clustering is implemented with one +Apache Web Server as a load balancer and 2 or more Apache Tomcat servers +as nodes. There are a lot of tutorials online, thus we will just give a +short summary below. + +1. Install Tomcat for each node +2. Configure unique node names with jvmRoute parameter to each Tomcat’s +server.xml +3. Install Apache Web Server to load balancer node +4. Edit Apache’s httpd.conf file to include mod_proxy, mod_proxy_ajp, +and mod_proxy_balancer +5. Configure balancer members with node addresses and load factors into +end of httpd.conf file +6. Restart servers + +There are several other options (free and commercial ones) for the load +balancer, too. For example, our customers have used at least F5 in +several projects. + +[[clustering-with-wildfly-undertow]] +Clustering with Wildfly Undertow +++++++++++++++++++++++++++++++++ + +Using Wildfly Undertow as a load balancer has several advantages over +Apache Web Server. First, as Undertow comes with your WildFly server, +there is no need to install yet another software for a load balancer. +Then, you can configure Undertow with Java (see Figure 8) which +minimizes the error prone conf file or xml configurations. Finally, +using the same vendor for application servers and for a load balancer +reduces the risk of intercompatibility issues. The clustering setup for +Wildfly Undertow is presented below. We are using sticky session +management to maximize performance. + +1. Install Wildfly 9 to all nodes +2. Configure Wildfly’s standalone.xml +1. add `“instance-id=”node-id”` parameter undertow subsystem, e.g: +` `(this +is needed for the sticky sessions). +2. set http port to something else than 8080 in socket-binding-group, +e.g: `` +3. Start your node servers accepting all ip addresses: +`./standalone.sh -c standalone.xml -b=0.0.0.0` +4. Code your own load balancer (reverse proxy) with Java and Undertow +libraries (see Figure 9) and start it as a Java application. + +[source,java] +.... +public static void main(final String[] args) { + try { + LoadBalancingProxyClient loadBalancer = new LoadBalancingProxyClient() + .addHost(new URI("http://192.168.2.86:8081"),"node1") + .addHost(new URI("http://192.168.2.216:8082"),"node2") + .setConnectionsPerThread(1000); + Undertow reverseProxy = Undertow.builder() + .addHttpListener(8080, "localhost") + .setIoThreads(8) + .setHandler(new ProxyHandler(loadBalancer, 30000, ResponseCodeHandler.HANDLE_404)) + .build(); + reverseProxy.start(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } +} +.... + +_Figure 9: Simple load balancer with two nodes and sticky sessions._ + +[[database]] +Database +~~~~~~~~ + +In most cases, the database is the most common and also the most tricky +to optimize. Typically you’ll have to think about your database usage +before you actually need to start optimizing the memory and CPU as shown +above. We assume here that you use object to relational mapping +frameworks such as Hibernate or Eclipselink. These frameworks implement +several optimization techniques within, which are not discussed here, +although you might need those if you are using plain old JDBC. + +Typically profiling tools are needed to investigate how much the +database is limiting the scalability of your application, but as a rule +of thumb: the more you can avoid accessing the database, the less it +limits the scalability. Consequently, you should generally cache static +(or rarely changing) database content. + +[[remedies-2]] +Remedies +^^^^^^^^ + +[[analyze-and-optimize-performance-bottlenecks-1]] +Analyze and optimize performance bottlenecks +++++++++++++++++++++++++++++++++++++++++++++ + +We already discussed shortly, how to use Java VisualVM for finding CPU +bottlenecks. These same instructions also apply for finding out at what +level the database consumes the performance. Typically you have several +Repository-classes (e.g. `CustomerRepository`) in your web application, +used for CRUD (create, read, update, delete) operations (e.g. +`createCustomer`). Commonly your repository implementations either +extend Spring’s JPARepository or use `javax.persistence.EntityManager` +or Spring’s `Datasource` for the database access. Thus, when profiling, +you will probably see one or more of those database access methods in +the list of methods that are using most of your CPU’s capacity. + +According to our experience, one of the bottlenecks might be that small +database queries (e.g. `findTaskForTheDay`) are executed repeatedly +instead of doing more in one query (e.g. `findTasksForTheWeek`). In some +other cases, it might be vice versa: too much information is fetched and +only part of it is used (e.g. `findAllTheTasks`). A real life example of +the latter happened recently in a customer project, where we were able +to a gain significant performance boost just by using JPA Projections to +leave out unnecessary attributes of an entity (e.g. finding only Task’s +name and id) in a query. + +[[custom-caching-and-query-optimization]] +Custom caching and Query optimization ++++++++++++++++++++++++++++++++++++++ + +After performance profiling, you have typically identified a few queries +that are taking a big part of the total CPU time. A part of those +queries might be the ones that are relatively fast as a single query but +they are just done hundreds or thousands of times. Another part of +problematic queries are those that are heavy as is. Moreover, there is +also the __N__+1 query problem, when, for example, a query for fetching +a Task entity results __N__ more queries for fetching one-to-many +members (e.g. assignees, subtasks, etc.) of the Task. + +The queries of the first type might benefit from combining to bigger +queries as discussed in the previous subchapter (use +`findTasksForTheWeek` instead of `findTaskForTheDay`). I call this +approach custom caching. This approach typically requires changes in +your business logic too: you will need to store (cache) yet unneeded +entities, for example in a `HashMap` or `List` and then handle all these +entities sequentially. + +The queries of the second type are typically harder to optimize. +Typically slow queries can be optimized by adding a certain index or +changing the query logic into a little bit different form. The difficult +part is to figure out what exactly makes the query slow. I recommend +using a logging setting that shows the actual sql query made in your log +file or console (e.g. in Hibernate use `show_sql=true`). Then you can +take the query and run it against your database and try to vary it and +see how it behaves. You can even use the `EXPLAIN` keyword to ask MySQL +or PostgreSql (`EXPLAIN PLAN FOR` in Oracle and `SHOWPLAN_XML` in SQL +Server) to explain how the query is executed, what indexes are used etc. + +The __N__+1 queries can be detected by analysing the executed sqls in +the log file. The first solution for the issue is redesigning the +problematic query to use appropriate join(s) to make it fetch all the +members in a single sql query. Sometimes, it might be enough to use +`FetchType.EAGER` instead of `LAZY` for the problematic cases. Yet +another possibility could be your own custom caching as discussed above. + +[[second-level-cache]] +Second-level cache +++++++++++++++++++ + +According to Oracle’s Java EE Tutorial: a second-level cache is a local +store of entities managed by the persistence provider. It is used to +improve the application performance. A second-level cache helps to avoid +expensive database queries by keeping frequently used entities in the +cache. It is especially useful when you update your database only by +your persistence provider (Hibernate or Eclipselink), you read the +cached entities much more often than you update them, and you have not +clustered your database. + +There are different second-level cache vendors such as EHCache, OSCache, +and SwarmCache for Hibernate. You can find several tutorials for these +online. One thing to keep in mind is that the configuration of, for +example, EHCache varies whether you use Spring or not. Our experience of +the benefits of second-level caches this far is that in real world +applications the benefits might be surprisingly low. The benefit gain +depends highly on how much your application uses the kind of data from +the database that is mostly read-only and rarely updated. + +[[use-clustering-2]] +Use clustering +++++++++++++++ + +There are two common options for clustering or replication of the +database: master-master replication and master-slave replication. In the +master-master scheme any node in the cluster can update the database, +whereas in the master-slave scheme only the master is updated and the +change is distributed to the slave nodes right after that. Most +relational database management systems support at least the master-slave +replication. For instance, in MySql and PostgreSQL, you can enable it by +few configuration changes and by granting the appropriate master rights +for replication. You can find several step-by-step tutorials online by +searching with e.g. the keywords “postgresql master slave replication”. + +[[nosql]] +NoSQL ++++++ + +When looking back to the first figure (Figure 1) of the article, you +might wonder what kind of database solutions the world's biggest web +application’s use? Most of them use some relation database, partly, and +have a NoSQL database (such as Cassandra, MongoDB, and Memcached) for +some of the functionality. The big benefit of many NoSQL solutions is +that they are typically easier to cluster, and thus help one to achieve +extremely scalable web applications. The whole topic of using NoSQL is +so big that we do not have the possibility to discuss it in this +article. + +[[summary]] +Summary +------- + +We started the study by looking at typical applications and estimated +their average concurrent user number. We then started with a typical +Vaadin web application and looked at what bottlenecks we hit on the way, +by using a standard laptop. We discussed different ways of overcoming +everything from File Descriptors to Session size minimization, all the +way to Garbage collection tweaking and clustering your entire +application. At the end of the day, there are several issues that could +gap you applications scalability, but as shown in this study, with a few +fairly simple steps we can scale the app from 200 concurrent users to +3000 concurrent users. As a standard architectural answer, however: the +results in your environment might be different, so use tools discussed +in this paper to find your bottlenecks and iron them out. diff --git a/documentation/articles/SendingEmailFromJavaApplications.asciidoc b/documentation/articles/SendingEmailFromJavaApplications.asciidoc new file mode 100644 index 0000000000..07ed9181d9 --- /dev/null +++ b/documentation/articles/SendingEmailFromJavaApplications.asciidoc @@ -0,0 +1,429 @@ +[[sending-email-from-java-applications]] +Sending email from Java Applications +------------------------------------ + +[[introduction]] +Introduction +^^^^^^^^^^^^ + +Sending email is a common feature required in many business applications. +From simple notifications containing plain text to complex reports with +links and multiple attachments, email is a common way of asynchronous +communication with end users. + +This tutorial shows how to send email messages in two different ways: + +1. Using the Apache Commons Email library which offers a simplified API on top of the JavaMail API. +2. Using Spring Mail Support, a utility library that encapsulates the specifics of the mailing system, also implemented on top of the JavaMail API.  + +Although +email operations include sending, receiving, deleting, setting flags, +and others depending on the specific email server in use, this tutorial +only discusses email sending through SMTP. + +[[how-does-email-work]] +How does Email Work? +~~~~~~~~~~~~~~~~~~~~ + +Let’s start +with a quick overview of the email communication process. It all begins +with the end user composing a message using a client desktop or web +application. The message is sent through multiple networking devices +until it reaches its destination at the recipient’s machine. The +relevant elements of this process are depicted in the following figure: + +image:https://lh5.googleusercontent.com/GbbTWnXnPml4ijiQU1mMO8tkmGSGAcmpXEGwHQJwGOFGGI3zD98_rgYaGi-0OX18M9iTtkHyif8FnJNdKX1ubdE8MXIQ4k-Ww5qu0-MC4aoOhiqjKz56p8KLyN-QdonMZzSKEEGS[javamail-tutorial] + +Once the end +user has triggered the action to send the email, the client application +connects to its configured email server, the SMTP Server, which can be +described as a program capable of communicating with other SMTP Servers +using the Simple Mail Transfer Protocol (SMTP). This SMTP Server can be +your own server running software, such as Apache James Server, Postfix, +Sendmail, qmail, or a server managed by a third party, such as Gmail, +Outlook, and Yahoo Mail.  + +Your SMTP +Server (managed by yourself or by a third party) sends the email message +to the recipient’s SMTP Server. Once the message reaches its +destination, it is stored in the recipient’s inbox at the recipient’s +SMTP Server. Finally, the recipient can read the message by requesting +it from the SMTP Server. + +Nowadays, +SMTP is used to send email messages and IMAP (Internet Message Access +Protocol) or POP (Post Office Protocol) to receive messages. In this +case, your client application will use SMTP to send the message and the +recipient’s SMTP Server will use SMTP to receive the message and IMAP or +POP to serve the message when the recipient requests it. You don’t need +to understand the specifics of these protocols in order to send email +from a Java application but you might want to understand them deeper, if +you are planning to implement operations such as receiving, deleting, +and setting flags, or if your applications require sending zillions of +emails in a batch. + +[[configuring-a-test-smtp-server]] +Configuring a Test SMTP Server +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For the +purposes of this tutorial, we are going to use FakeSMTP, a free email +server that offers a convenient GUI for testing email sending. You can +download it from the following website: https://nilhcem.github.io/FakeSMTP/download.html[https://nilhcem.github.io/FakeSMTP/download.html] + +Extract the +content of the downloaded zip file and execute the extracted jar. You +can configure a port in the Listening port option (we will use 9090 in +this tutorial). Once ready, click the Start server button to start +getting emails. + +Please note +that with FakeSMTP you don’t need to provide any authentication values +(they will be ignored). + +[[javamail-api]] +JavaMail API +~~~~~~~~~~~~ + +The JavaMail +API is defined by the JSR 919 and is included in Java EE (but not in EJB +Lite nor Java EE Web Profile). It provides an abstraction over mail +systems which makes its API more verbose than those of Apache Commons +Email and Spring Mail Support. We are not covering JavaMail in this +tutorial. However, we provide an example application that uses JavaMail +to send emails. You can get the code from the following link: https://github.com/alejandro-du/java-email-tutorial/blob/master/javamail-example/src/main/java/com/example/javamail/JavaMailService.java[https://github.com/alejandro-du/java-email-tutorial/blob/master/javamail-example/src/main/java/com/example/javamail/JavaMailService.java] + +[[apache-commons-email]] +Apache Commons Email +~~~~~~~~~~~~~~~~~~~~ + +Apache +Commons Email is built on top of JavaMail and hides much of its +complexity. Therefore, it offers an API that simplifies the code to +implement email sending from Java applications. + +You must +download the Commons Email jar file from the following link: +https://commons.apache.org/proper/commons-email/download_email.cgi[https://commons.apache.org/proper/commons-email/download_email.cgi], +or add the dependency using a dependency management system. For example, +if you are using Maven, you can add the following to your pom.xml: + +[source, xml] +.... + + org.apache.commons + commons-email + 1.4 + +.... +  + +With Commons +Email, you can send emails with HTML content using the `HtmlEmail` class. +This class offers an abstraction to send emails with attachments. For +example, during testing you can configure the `HtmlEmail` instance as +follows: + +[source,java] +.... +HtmlEmail email = new HtmlEmail(); +email.setHostName("localhost"); +email.setSmtpPort(9090); +email.setAuthentication()"sender@test.com", "password"); +.... +  +Or if you want to use Gmail: + +[source,java] +.... +HtmlEmail email = new HtmlEmail(); +email.setHostName("smtp.gmail.com"); +email.setSmtpPort(465); +email.setSSLOnConnect(true); +email.setAuthentication("your-account-name@gmail.com", "your-password"); +.... + +Keep in mind +that hard-coding connection parameters like this is not good practice. +Instead, you should read the values from an external source (such as a +properties file) so that you can use different configurations for +different environments (development, testing, production).  + +You can use +the email instance to set the sender’s email address, add recipients, +and set the subject and the text of the message: + +[source,java] +.... +email.setFrom("sender@test.com"); +email.addTo("recipient1@test.com", "recipient2@test.com"); +email.setSubject("The subject"); +email.setHtmlMsg("This is the message."); +.... + +The `HtmlEmail` +class also exposes the attach method to add attachments to the message. +You can provide these attachments as an `InputStream` so that its content +can be dynamically generated at runtime if required (`FileInputStream` is +always an option in case you have `File` instances instead): + +[source,java] +.... +ByteArrayDataSource dataSource = new ByteArrayDataSource(inputStream, "text/plain"); +DataHandler dataHandler = new DataHandler(dataSource); +email.attach(dataSource, "attachment.txt", "description"); +.... +  + +The `attach` +method is overloaded with multiple implementations offering different +ways to attach files. The one used in the previous example requires to +specify a description for the attachment. + +You can find +a complete implementation of a utility class that implements email +sending using the Commons Email in the following link: https://github.com/alejandro-du/java-email-tutorial/blob/master/commons-email-example/src/main/java/com/example/javamail/CommonsEmailService.java[https://github.com/alejandro-du/java-email-tutorial/blob/master/commons-email-example/src/main/java/com/example/javamail/CommonsEmailService.java] + +[[spring-email-support]] +Spring Email Support +~~~~~~~~~~~~~~~~~~~~ + +Similarly to +the Apache Commons Email library, Spring offers an API on top of +JavaMail which abstracts away the details of the mailing system. You +need to add the `spring-context-support` dependency using Maven or Gradle. +There is no official download site for this dependency, but you can +download it directly from the following link if required: http://mvnrepository.com/artifact/org.springframework/spring-context-support/4.2.4.RELEASE[http://mvnrepository.com/artifact/org.springframework/spring-context-support/4.2.4.RELEASE]. + +If you are +using Maven you can add the following dependency to your pom.xml: + +[source,xml] +.... + + org.springframework + spring-context-support + 4.2.4.RELEASE + +.... + +You start by +obtaining an implementation of the `MailSender` interface. Spring provides +the `JavaMailSenderImpl` class that implements `MailSender`. You can obtain +an instance of this class either by configuring and injecting a bean, if +you are already using Spring Framework and have configured an +application context, or by direct instantiation:  + +[source,java] +.... +JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); +.... + +The +connection to the SMTP server is configured using properties. The +following example shows how to configure the `mailSender` to connect to +Gmail’s SMTP server: + +[source,java] +.... +Properties properties = new Properties(); +properties.put("mail.smtp.host", "smtp.gmail.com"); +properties.put("mail.smtp.port", "465"); +properties.put("mail.smtp.ssl.enable", "true"); + +mailSender.setJavaMailProperties(properties); +.... +  +Alternatively, +you can use methods defined in the `MailSender` interface to configure the +host and port, but in the case of SMTP servers using SSL, you will have +to provide at least the `mail.smtp.ssl.enable` property through a +`Properties` object. For this reason, we prefer to configure all the +settings using properties in this example. + +The authentication credentials are configured using the `MailSender` instance +as follows: + +[source,java] +.... +mailSender.setUsername("sender@test.com"); +mailSender.setPassword("password"); +.... + +The next step is to create a `MimeMessage` and a `MimeMessageHelper`: + +[source,java] +.... +MimeMessage message = mailSender.createMimeMessage(); +MimeMessageHelper helper = new MimeMessageHelper("The message body", true); +.... + +The second +parameter is set to true to create a multipart message that will allow +us to add attachments later. The `MimeMessageHelper` exposes a handful of +methods to directly set up the message: + +[source,java] +.... +helper.setFrom("sender@test.com"); +helper.setSubject("subject"); +helper.setText(text, true); // true to activate multipart +helper.addTo("recipient@test.com"); +.... + +There are +several overloaded methods in the `MimeMessageHelper` that provide +different ways to attach files. The following example uses the +`ByteArrayDataSource` class to provide an attachment from an `InputStream`: + +[source,java] +.... +ByteArrayDataSource dataSource = new ByteArrayDataSource(inputStream, "text/plain"); +helper.addAttachment("file.txt", dataSource); +.... + +Finally, you can send the email using the `MailSender` instance: + +[source,java] +.... +mailSender.send(message); +.... +  + +You can find +a complete implementation of a utility class that implements email +sending using Spring Email Support in the following link: https://github.com/alejandro-du/java-email-tutorial/blob/master/spring-mail-example/src/main/java/com/example/javamail/SpringEmailService.java[https://github.com/alejandro-du/java-email-tutorial/blob/master/spring-mail-example/src/main/java/com/example/javamail/SpringEmailService.java] + +[[an-example-web-application]] +An Example Web Application +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Let’s create +a Java web application to test this functionality. The application +consists of a text field where users can type an email address and a +button that will send an email with an attachment to the specified +address. + +We are going +to use the https://vaadin.com[Vaadin Framework] which allows us to quickly create a web +application by using only the Java Programming Language. This way, we +don’t need to worry about writing any HTML or JavaScript at all. + +Although most +IDEs have plugins to easily generate a new Vaadin project, we are going +to use a Maven archetype to generate the project that you can later +import into your favorite IDE. You can create a new Vaadin project with +Maven using the following command line:  + +[source] +.... +mvn archetype:generate -DarchetypeGroupId=com.vaadin -DarchetypeArtifactId=vaadin-archetype-application -DarchetypeVersion=7.6.2 +.... + +After +specifying a group and artifact id, you can run `mvn clean install` to +compile the project and `mvn jetty:run` to deploy and run the application. +Open your browser and navigate to http://localhost:8080[http://localhost:8080] to see the application +running. + +Open the `MyUI.java` file (it should be the only Java file in the project) and change the `init` method to the following: + +[source,java] +.... +//... imports mostly from com.vaadin package + +public class MyUI extends UI { +   @Override +   protected void init(VaadinRequest vaadinRequest) { +       // the text field where users will specify their email address +       TextField textField = new TextField("Your email:"); + +       // a button with a click listener that sends the email +       Button button = new Button("Send me the PDF", e -> sendEmail(textField.getValue())); + +       // a layout containing the previous components +       VerticalLayout layout = new VerticalLayout(textField, button); +       layout.setMargin(true); +       layout.setSpacing(true); + +       setContent(layout); // sets the content for this UI +   } +   ... +} +.... + +Add the missing `sendEmail` method and implement it as follows: + +[source,java] +.... +private void sendEmail(String to) { +    try { +        // all values as variables to clarify its usage +        InputStream inputStream = getClass().getResourceAsStream("/dock-magazine.pdf"); + String from = "sender@test.com"; +        String subject = "Your PDF"; +        String text = "Here there is your PDF file!"; +        String fileName = "file.pdf"; +        String mimeType = "application/pdf"; + +        CommonsEmailService.send(from, to, subject, text, inputStream, fileName, mimeType); + +        Notification.show("Email sent"); +    } catch (MessagingException | IOException e) { +        e.printStackTrace(); +        Notification.show("Error sending the email", Notification.Type.ERROR_MESSAGE); +    } +} +.... +  + +At this point +you might want to create the missing `CommonsEmailService` class (or +`SpringMailService` class) and implement the send method as an exercise. +But if you prefer, you can take the example implementation from the +following link: https://github.com/alejandro-du/java-email-tutorial/blob/master/commons-email-example/src/main/java/com/example/javamail/CommonsEmailService.java[https://github.com/alejandro-du/java-email-tutorial/blob/master/commons-email-example/src/main/java/com/example/javamail/CommonsEmailService.java] + +Finally, add +a PDF file with the name file.pdf in the resources directory of your +Maven project. You may want to use a small file so that SMTP servers +would be able to accept it. + +Stop the +Jetty server if necessary, run `mvn clean install` again, and reload the +web page in the browser. The following is a screenshot of the web +application: image:https://lh5.googleusercontent.com/zcy_LwtCa9TW-sP3phTlczRP9lBvE9ozaxd0Ae4yJghOjQnAjxOlhYp2n5ruLiLlroZ9HW_LEoJN-5qPJI60rXMiFvGuHcibvP5txCMhiS9ZPn1wCMYkN43Zkjqbuw1kTi0nXn_v[screenshot.png,width=622,height=433] + +If you have +FakeSMTP running, you should be able to see the email messages sent +through the web application. + +[[which-approach-to-use]] +Which Approach to Use? +~~~~~~~~~~~~~~~~~~~~~~ + +Choosing an +option depends on different factors. However, I would recommend to use +Spring Email Support if you are developing a Spring application. If not, +go with Apache Commons Email, it offers the most intuitive API. Also, +Apache Commons Email jar is lighter than the spring-context-support jar, +as the later includes more than just the email support classes. Using +the JavaMail API directly may be convenient only when you need lower +level interaction with the mailing system. + +You can experiment with the code by downloading the example web applications +from GitHub: + +[source] +.... +$ git clone https://github.com/alejandro-du/java-email-tutorial +$ cd java-email-tutorial +$ cd commons-email-example +# (Or cd spring-mail-example) + +$ mvn clean install +$ mvn jetty:run +.... +  + +Don’t forget to configure run FakeSMTP before using the web application deployed at +http://localhost:8080[http://localhost:8080]. diff --git a/documentation/articles/SendingEventsFromTheClientToTheServerUsingRPC.asciidoc b/documentation/articles/SendingEventsFromTheClientToTheServerUsingRPC.asciidoc new file mode 100644 index 0000000000..329755c9cd --- /dev/null +++ b/documentation/articles/SendingEventsFromTheClientToTheServerUsingRPC.asciidoc @@ -0,0 +1,139 @@ +[[sending-events-from-the-client-to-the-server-using-RPC]] +Sending events from the client to the server using RPC +------------------------------------------------------ +An RPC mechanism can be used to communicate from the client to the +server. In effect, the client can call methods that are executed by the +server component. The server component can then take appropriate action +- e.g updating the shared state or calling event listeners. + +To set up client-server RPC we need to create one interface defining the +RPC methods, and then make use of that interface on both the client and +the server. Place the `MyComponentServerRpc` interface in the client +package: + +[source,java] +.... +package com.example.mycomponent.client; + +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +public interface MyComponentServerRpc extends ServerRpc { + public void clicked(MouseEventDetails mouseDetails); +} +.... + +Note that the RPC methods can not have return values. In this example, +we pass `MouseEventDetails` to get a more complete example, but you +could pass almost any (or no) parameters. + +In the server side `MyComponent` we need to implement the interface, and +register it for use: + +[source,java] +.... +package com.example.mycomponent; + +import com.example.mycomponent.client.MyComponentServerRpc; +import com.example.mycomponent.client.MyComponentState; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.ui.AbstractComponent; + +public class MyComponent extends AbstractComponent { + + private int clickCount = 0; + + private MyComponentServerRpc rpc = new MyComponentServerRpc() { + public void clicked(MouseEventDetails mouseDetails) { + clickCount++; + setText("You have clicked " + clickCount + " times"); + } + }; + + public MyComponent() { + registerRpc(rpc); + } + +/* Previous code commented out for clarity: + @Override + public MyComponentState getState() { + return (MyComponentState) super.getState(); + } + public void setText(String text) { + getState().text = text; + } + public String getText() { + return getState().text; + } +*/ +} +.... + +Here we react to the RPC call by incrementing a counter. We do not make +use of the `MouseEventDetails` (yet). Notice the *important call to +`registerRpc()`* in the added constructor. + +In the client side `MyComponentConnector`, we use `RpcProxy` to get an +implementation of the RPC interface, and call the `clicked()` method +when the widget is clicked: + +[source,java] +.... +package com.example.mycomponent.client; + +// imports removed for clarity +import com.vaadin.terminal.gwt.client.communication.RpcProxy; + +@Connect(MyComponent.class) +public class MyComponentConnector extends AbstractComponentConnector { + + MyComponentServerRpc rpc = RpcProxy + .create(MyComponentServerRpc.class, this); + + public MyComponentConnector() { + getWidget().addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + + final MouseEventDetails mouseDetails = MouseEventDetailsBuilder + .buildMouseEventDetails(event.getNativeEvent(), + getWidget().getElement()); + + rpc.clicked(mouseDetails); + } + }); + } + +/* Previous code commented out for clarity: + @Override + protected Widget createWidget() { + return GWT.create(MyComponentWidget.class); + } + @Override + public MyComponentWidget getWidget() { + return (MyComponentWidget) super.getWidget(); + } + @Override + public MyComponentState getState() { + return (MyComponentState) super.getState(); + } + @OnStateChange("text") + void updateText() { + getWidget().setText(getState().text); + } +*/ +} +.... + +Notice that most of the code is for attaching the click handler and +creating the `MouseEventDetails`, the code for the actual RPC is quite +minimal. + +Compile the widgetset, and the label text should be updated with the +click count whenever you click it (remember that the counting is done on +the server-side). + +Finally, note that you can use multiple RPC interfaces in one component, +allowing for better code separation and reuse. + +You can do the same thing in the other direction, see the article about +server to client RPC for details. diff --git a/documentation/articles/SettingAndReadingCookies.asciidoc b/documentation/articles/SettingAndReadingCookies.asciidoc new file mode 100644 index 0000000000..57310bb04d --- /dev/null +++ b/documentation/articles/SettingAndReadingCookies.asciidoc @@ -0,0 +1,136 @@ +[[setting-and-reading-ookies]] +Setting And Reading Cookies +--------------------------- + +You can easily read and write +http://en.wikipedia.org/wiki/HTTP_cookie[cookies] from both the server +and the client side in Vaadin, with one caveat: Cookies are not possible +if you enable Push using WebSocket (see tickets +http://dev.vaadin.com/ticket/11808[11808] and +http://dev.vaadin.com/ticket/12518[12518]). Begining in Vaadin 7.6, +cookies can be used with the WEBSOCKET_XHR transport type. + +The +https://vaadin.com/api/7.0.3/com/vaadin/server/VaadinRequest.html[VaadinRequest] +class gives easy access to the collection of cookies bundled with each +http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol[HTTP] request. +Each cookie is represented as instances of the +http://docs.oracle.com/javaee/6/api/javax/servlet/http/Cookie.html[javax.servlet.http.Cookie] +class defined by the Java +http://en.wikipedia.org/wiki/Java_Servlet[Servlet]http://www.jcp.org/en/jsr/detail?id=315[spec]. + +To read a cookie on the server side you can request the cookies from the +current request like so: + +[source,java] +.... +// Fetch all cookies +Cookie[] cookies = VaadinService.getCurrentRequest().getCookies(); +.... + +_That will fetch all currently defined cookies. You can then iterate +over them to find the cookie you are looking for._ + +To add a new cookie or update an already defined cookie you can do the +following: + +[source,java] +.... +// Create a new cookie +Cookie myCookie = new Cookie("cookie-name", "cookie-value"); + +// Make cookie expire in 2 minutes +myCookie.setMaxAge(120); + +// Set the cookie path. +myCookie.setPath(VaadinService.getCurrentRequest().getContextPath()); + +// Save cookie +VaadinService.getCurrentResponse().addCookie(myCookie); +.... + +Here is a full example of utilizing cookies on the server side by +storing a a value from a `TextField` in a cookie for later use. + +[source,java] +.... +public class CookieMonsterUI extends UI { + +private static final String NAME_COOKIE = "name"; + +@Override +protected void init(VaadinRequest request) { +final VerticalLayout layout = new VerticalLayout(); layout.setMargin(true); +setContent(layout); + +final TextField nameField = new TextField(); layout.addComponent(nameField); + +// Read previously stored cookie value +Cookie nameCookie = getCookieByName(NAME_COOKIE); + +if (getCookieByName(NAME_COOKIE) != null) { + nameField.setValue(nameCookie.getValue()); +} + +Button button = new Button("Store name in cookie"); button.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + String name = nameField.getValue(); + + // See if name cookie is already set + Cookie nameCookie = getCookieByName(NAME_COOKIE); + + if (nameCookie != null) { + String oldName = nameCookie.getValue(); + nameCookie.setValue(name); + Notification.show("Updated name in cookie from " + oldName + " to " + name); + + } else { + // Create a new cookie + nameCookie = new Cookie(NAME_COOKIE, name); + nameCookie .setComment("Cookie for storing the name of the user"); + Notification.show("Stored name " + name + " in cookie"); + } + + // Make cookie expire in 2 minutes + nameCookie.setMaxAge(120); + + // Set the cookie path. + nameCookie.setPath(VaadinService.getCurrentRequest() .getContextPath()); + + // Save cookie + VaadinService.getCurrentResponse().addCookie(nameCookie); + } + }); + +layout.addComponent(button); + +} + +private Cookie getCookieByName(String name) { + // Fetch all cookies from the request + Cookie[] cookies = VaadinService.getCurrentRequest().getCookies(); + + // Iterate to find cookie by its name + for (Cookie cookie : cookies) { + if (name.equals(cookie.getName())) { + return cookie; + } + } + + return null; + } +} +.... + +Finally if you need to read a cookie from client-side code, you can use +the `Cookies` class like so:  + +[source,java] +.... +// Read name from cookie +String name = Cookies.getCookie("name"); + +// Write new value to cookie +Cookies.setCookie("name", "Some other value"); +.... diff --git a/documentation/articles/SettingAndReadingSessionAttributes.asciidoc b/documentation/articles/SettingAndReadingSessionAttributes.asciidoc new file mode 100644 index 0000000000..c7c042c3f9 --- /dev/null +++ b/documentation/articles/SettingAndReadingSessionAttributes.asciidoc @@ -0,0 +1,89 @@ +[[setting-and-reading-session-attributes]] +Setting and reading session attributes +-------------------------------------- + +Vaadin has a few different ways of storing data that should be +accessible later. Which one you should use depends on the scope of the +data, e.g. how long it should be kept around and what parts of the code +should have access to it. + +1. Store the data as a field in your UI subclass. The data is easily +accesible from components belonging to that UI instance and the data +will be gone when the UI is closed. +2. Store data in the `VaadinServiceSession`. The data is easily +accessible from any UI belonging to the same VaadinServlet or +VaadinPortlet and it will be gone when the session is closed. +3. Store data in the `HttpSession` or `PortletSession` (represented in +Vaadin through `WrappedSession`). The data is easily accessible from any +part of your web application (i.e. your .war) and it will be gone when +the session is invalidated. + +The following example code demonstrates how the data is stored and +retrieved in different ways. + +[source,java] +.... +//Remove comment to preserve UI value when reloading +//@PreserveOnRefresh +public class SettingReadingSessionAttributesUI extends UI { + + private String value; + + private VerticalLayout statusHolder = new VerticalLayout(); + private TextField textField = new TextField(); + + @Override + protected void init(VaadinRequest request) { + addComponent(statusHolder); + addComponent(textField); + addComponent(new Button("Set new values", new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + String value = textField.getValue(); + + saveValue(SettingReadingSessionAttributesUI.this, value); + } + })); + addComponent(new Button("Reload page", new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + getPage().setLocation(getPage().getLocation()); + } + })); + + showValue(this); + } + + private static void saveValue(SettingReadingSessionAttributesUI ui, + String value) { + // Save to UI instance + ui.value = value; + // Save to VaadinServiceSession + ui.getSession().setAttribute("myValue", value); + // Save to HttpSession + VaadinService.getCurrentRequest().getWrappedSession() + .setAttribute("myValue", value); + + // Show new values + showValue(ui); + } + + private static void showValue(SettingReadingSessionAttributesUI ui) { + ui.statusHolder.removeAllComponents(); + ui.statusHolder.addComponent(new Label("Value in UI: " + ui.value)); + ui.statusHolder.addComponent(new Label( + "Value in VaadinServiceSession: " + + ui.getSession().getAttribute("myValue"))); + ui.statusHolder.addComponent(new Label("Value in HttpSession: " + + VaadinService.getCurrentRequest().getWrappedSession() + .getAttribute("myValue"))); + } + +} +.... + +The UI stores and reads the value in three different ways. The UI +instance value gets lost just by reloading the page as a new UI instance +is then created unless the UI has been marked with `@PreserveOnRefresh`. +If you deploy two different `VaadinServlet` instances using the same UI +class, they will only share the `HttpSession` value. diff --git a/documentation/articles/UsingParametersWithViews.asciidoc b/documentation/articles/UsingParametersWithViews.asciidoc new file mode 100644 index 0000000000..dfa29dabde --- /dev/null +++ b/documentation/articles/UsingParametersWithViews.asciidoc @@ -0,0 +1,112 @@ +[[using-parameters-with-views]] +Using parameters with Views +--------------------------- + +When the Navigator API is in use, one can pass "parameters" to Views in +the URI fragment. + +The remainder of the fragment that is left after the (longest) view name +matched is removed, is considered to be "fragment parameters". These are +passed to the View in question, which can then handle the parameter(s). +Basically: `#viewname/parameters`. + +Continuing from the basic navigation example, let's make a View that +displays a message passed as a fragment parameter: + +[source,java] +.... +import com.vaadin.navigator.View; +import com.vaadin.ui.Label; +import com.vaadin.ui.Panel; + +public class MessageView extends Panel implements View { + public static final String NAME = "message"; + + public MessageView() { + super(new VerticalLayout()); + setCaption("Messages"); + } + + @Override + public void enter(ViewChangeEvent event) { + if(event.getParameters() != null){ + // split at "/", add each part as a label + String[] msgs = event.getParameters().split("/"); + for (String msg : msgs) { + ((Layout)getContent()).addComponent(new Label(msg)); + } + } + } +} +.... + +Let's register `MessageView` along with the other Views: + +[source,java] +.... +import com.vaadin.navigator.Navigator; +import com.vaadin.navigator.Navigator.SimpleViewDisplay; +import com.vaadin.server.Page; +import com.vaadin.server.WrappedRequest; +import com.vaadin.ui.UI; + +public class NavigationtestUI extends UI { + + @Override + public void init(VaadinRequest request) { + // Create Navigator, make it control the ViewDisplay + Navigator navigator = new Navigator(this, this); + + // Add some Views + navigator.addView(MainView.NAME, new MainView()); // no fragment + + // #count will be a new instance each time we navigate to it, counts: + navigator.addView(CountView.NAME, CountView.class); + + // #message adds a label with whatever it receives as a parameter + navigator.addView(MessageView.NAME, new MessageView()); + } +} +.... + +Finally, we'll add two labels to the MainView so we don't have to type +in the browsers address-bar to try it out: + +[source,java] +.... +import com.vaadin.navigator.View; +import com.vaadin.server.ExternalResource; +import com.vaadin.ui.Link; +import com.vaadin.ui.Panel; + +public class MainView extends Panel implements View { + + public static final String NAME = ""; + + public MainView() { + + VerticalLayout layout = new VerticalLayout(); + + Link lnk = new Link("Count", new ExternalResource("#!" + CountView.NAME)); + layout.addComponent(lnk); + + lnk = new Link("Message: Hello", new ExternalResource("#!" + + MessageView.NAME + "/Hello")); + layout.addComponent(lnk); + + lnk = new Link("Message: Bye", new ExternalResource("#!" + + MessageView.NAME + "/Bye/Goodbye")); + layout.addComponent(lnk); + setContent(layout); + } + + @Override + public void enter(ViewChangeEvent event) { + + } +} +.... + +Simple! Let's just conclude by noting that it's usually a good idea to +make sure the parameters are URI encoded, or the browser might +disapprove. diff --git a/documentation/articles/UsingPolling.asciidoc b/documentation/articles/UsingPolling.asciidoc new file mode 100644 index 0000000000..1bd9119268 --- /dev/null +++ b/documentation/articles/UsingPolling.asciidoc @@ -0,0 +1,222 @@ +[[using-polling]] +Using Polling +------------- +To set up polling for your UI, you only need to set a poll interval +using `UI.setPollInterval(timeout)`. By doing this the browser will poll +the server each "timeout" ms and retrieve any possibly pending changes. +You can test this in practice by creating a small application which +initially creates a small "please wait" UI and then loads the actual UI +in a background thread. + +[source,java] +.... +public class PollingUI extends UI { + + @WebServlet(value = "/*") + @VaadinServletConfiguration(productionMode = false, ui = Polling7UI.class) + public static class Servlet extends VaadinServlet { + } + + @Override + protected void init(VaadinRequest request) { + setContent(new Label("Loading data, please wait...")); + setPollInterval(1000); + new Thread(new Loader()).start(); + } + + class Loader implements Runnable { + + @Override + public void run() { + // Simulate a heavy database operation + try { + Thread.sleep(4500); + } catch (InterruptedException e) { + } + + // Wrap UI updates in access to properly deal with locking + access(new Runnable() { + @Override + public void run() { + setContent(new Label("This is the real content")); + + // Stop polling once the update is done + setPollInterval(-1); + } + }); + } + } +} +.... + +For more information regarding locking the session, see [Using server +initiated events] + +[[polling-for-multiple-components]] +Polling for multiple components +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you have the situation that several components need polling at some +point you should use some kind of Manager to handle the polling, for it +can only be set UI-wise (which makes perfectly sense) + +A simple `UIPollingManager` which always uses the lowest registered +`intervalTime` could look like this: + +[source,java] +.... +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; + +import com.vaadin.ui.UI; + +public class UIPollingManager +{ + + private Map> pollRequests; + + public UIPollingManager() + { + pollRequests = new WeakHashMap<>(); // Let's use weak references in case someone forgets to unregister properly + } + + /** + * Registers a poll request for the given UI. Sets the pollInterval of this UI to the lowest registered interval. + * @param ui + * @param requestor + * @param pollIntervalInMillis poll interval in milliseconds + */ + public void registerPollRequest(UI ui, Object requestor, int pollIntervalInMillis) + { + Map uiRequests = pollRequests.get(ui); + if (uiRequests == null) + { + uiRequests = new HashMap<>(); + pollRequests.put(ui, uiRequests); + } + + uiRequests.put(requestor, pollIntervalInMillis); + + setPollInterval(ui); + } + + /** + * Removes a poll request for the given UI (if existent). Sets the pollInterval of this UI to the lowest registered interval + * remaining or -1 if no more requests exist for the UI + * @param ui + * @param requestor + */ + public void unregisterPollRequest(UI ui, Object requestor) + { + Map uiRequests = pollRequests.get(ui); + if (uiRequests != null) + { + uiRequests.remove(requestor); + + // Remove the UI from our map if no requests exist anymore + if (uiRequests.size() <= 0) pollRequests.remove(ui); + } + + setPollInterval(ui); + } + + /** + * Removes all poll requests of the given UI and sets the pollInterval to -1 + * @param ui + */ + public void unregisterAllPollRequests(UI ui) + { + pollRequests.remove(ui); + + ui.setPollInterval(-1); + } + + /** + * Sets the pollInterval of the given UI to the lowest registered interval time of this UI + * @param ui + */ + private void setPollInterval(UI ui) + { + Map uiRequests = pollRequests.get(ui); + if (uiRequests != null) + { + ui.setPollInterval(getLowestNumber(uiRequests.values())); + } + } + + /** + * Returns the lowest number of a given Integer-Collection. Returns -1 if no valid Integer is included in the collection. + * @param intervalArray + * @return + */ + private Integer getLowestNumber(Collection intervalArray) + { + Integer lowestNum = null; + + for (Integer i : intervalArray) + { + if (i != null && ( lowestNum == null || i < lowestNum )) lowestNum = i; + } + + if (lowestNum == null) return -1; + else + return lowestNum; + } +} +.... + +The changed example could then look like this: + +[source,java] +.... +public class Polling7UI extends UI { + + private UIPollingManager pollingManager; // Instantiate this via Spring or get it via Singleton or whatever + + @WebServlet(value = "/*") + @VaadinServletConfiguration(productionMode = false, ui = Polling7UI.class) + public static class Servlet extends VaadinServlet { + } + + @Override + protected void init(VaadinRequest request) { + setContent(new Label("Loading data, please wait...")); + Loader loader = new Loader(); + pollingManager.registerPollRequest(this, loader, 1000); + new Thread(loader).start(); + } + + class Loader implements Runnable { + private UI ui; + private UIPollingManager pollingManager; + public Loader( UI ui, UIPollingManager pollingManager ) + { + this.ui = ui; + this.pollingManager = pollingManager; + } + + @Override + public void run() { + // Simulate a heavy database operation + try { + Thread.sleep(4500); + } catch (InterruptedException e) { + } + + final Loader loader = this; + // Wrap UI updates in access to properly deal with locking + access(new Runnable() { + @Override + public void run() { + setContent(new Label("This is the real content")); + + // Stop polling once the update is done + pollingManager.unregisterPollRequest(ui, loader); + } + }); + } + } +} +.... diff --git a/documentation/articles/VaadinTutorialForSwingDevelopers.asciidoc b/documentation/articles/VaadinTutorialForSwingDevelopers.asciidoc new file mode 100644 index 0000000000..1d17e9358b --- /dev/null +++ b/documentation/articles/VaadinTutorialForSwingDevelopers.asciidoc @@ -0,0 +1,952 @@ +[[a-hitchhikers-guide-to-convert-aswing-appto-modern-web-app]] +A hitchhiker's guide to convert a Swing app to modern web app +------------------------------------------------------------- + +[[intro]] +Intro +~~~~~ + +As expressed by Pete Hunt (Facebook, React JS) in JavaOne 2014 Web +Framework Smackdown, if you would be creating a UI toolkit, from a +scratch, it would look nothing like a +https://en.wikipedia.org/wiki/Document_Object_Model[DOM]. Web +technologies indeed are not designed for application development, but +rich text presentation. Markup based presentation has proven to be +superior for more static content like web sites, but _applications_ are +a bit different story. In the early stages of graphical UIs on +computers, UI frameworks didn’t by accident form into “component based” +libraries. Those UI libraries have developed during the decades, but the +the basic concept of component based UI framework is still the most +powerful way to create _applications_. + +But Swing, SWT, Qt and similar desktop UI frameworks have one major +problem compared to web apps: they require you to install special +software on your client machine. As we have learned during the internet +era, this can be big problem. Users have lots of different kinds of +applications that they use nowadays and installing all of them and +especially maintaining those will become a burden for your IT +department. + +Browser plugins like Java’s Applet/Java WebStart support (and there +Swing or JavaFX) and Flash are the traditional workarounds to avoid +installing software locally for workstations. But famous security holes +in those, especially with outdated software, may become a huge problem +and your IT department is nowadays most likely against installing any +kind of third party browser plugins. For them it is much easier to just +maintain one browser application. This is one of the fundamental reasons +why pure web apps are conquering even most complex application domains +nowadays.  + +[[welcome_to_the_8220wonderful8221_world_of_web_apps]] +Welcome to the “wonderful” world of web apps +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +image:img/howvaadinworks2.png[How Vaadin works] Even +for experienced desktop developers it may be a huge jump from the +desktop world to the web development. Developing web applications is +much trickier than developing basic desktop apps. There are lots of +things that makes things complicated, such as client-server +communication, the markup language and CSS used for display, new +programming language for the client side and client-server communication +in many different forms (basic http, ajax style requests, long polling, +web sockets etc.). The fact is that, even with the most modern web app +frameworks, web development is not as easy as building desktop apps. + +Vaadin Framework is an open source Java framework and is the closest +thing to the component based Swing UI development in the mainstream web +app world. Vaadin is a component based UI framework that tries to make +web development as easy as traditional desktop development, maximizing +developers’ productivity and the quality of the produced end user +experience. In a Vaadin application the actual UI logic, written by you, +lives in the server’s JVM. Instead of browser plugins, Vaadin has a +built-in “thin client” that renders the UI efficiently in browsers. The +highly optimized communication channel sends only the stuff that is +really visible on user’s screen to thin client. Once the initial +rendering has been done, only deltas, in both way, are transferred +between the client and the server. + +The architecture of Vaadin Framework provides you an abstraction for the +web development challenges, and most of the time you can forget that +your are building a web application. Vaadin takes care of handling all +the communication, html markup, css and browser differences - you can +concentrate all your energy on your domain problems with clean Java +approach and take advantage of your experience from the desktop +applications. + +Vaadin uses GWT to implement its “thin client” running in the browser. +GWT is another bit similar tool for web development, and its heart is +its Java to JavaScript “compiler”. GWT also has a Swing like UI +component library, but in GWT the Java code is compiled into JavaScript +and executed in the browser. The compiler supports only a subset of Java +and the fact that it is not running in JVM causes some other +limitations, but the concepts are the same in it as well. Running your +code in the browser as a white box also has some security implications. + +[[architectural_differences_you_should_notice]] +Architectural differences you should notice +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Every architectural decision has its pros and consequences and so does +switching from Swing to Vaadin in your UI layer. + +[[one_application_instance_many_users]] +One application instance, many users +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The first thing you’ll notice is that you are now developing your UI +right next to your data. Pretty much all modern business apps, both web +and desktop apps, save their data somehow to a central server. Often the +data is “shielded” with middleware layer, with e.g. EJBs. Now that you +move to Vaadin UI, the EJB, or whatever the technology you use in your +“backend”, is “closer”. It can often be run in the very same application +server as your Vaadin UI, making some hard problems trivial. Using a +local EJB is both efficient and secure. + +Even if you’d still use a separate application server for your EJBs, +they are most probably connected to UI servers using a fast network that +can handle chatty connection between UI and business layers more +efficiently than typical client server communication - the network +requirements by the Vaadin thin client are in many cases less demanding, +so your application can be used over e.g. mobile networks. + +Another thing developers arriving from desktop Java to Vaadin will soon +notice that fields with “static” keyword are quite different in the +server world. Many desktop applications use static fields as “user +global” variables. In Java apps running in server, they are “application +global”, which is a big difference. Application servers generally use a +class loader per web application (.war file), not class loader per user +session. For “user global” variables, use fields in your UI class, +https://vaadin.com/api/com/vaadin/server/VaadinSession.html[VaadinSession], +http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html[HttpSession] +or e.g. +http://docs.oracle.com/javaee/7/api/javax/enterprise/context/SessionScoped.html[@SessionScoped] +CDI bean. + +Web applications in general will be much cheaper for IT departments to +maintain. They have been traditionally run in company’s internal +servers, but the trend of the era is hosting them in PaaS services, in +the “cloud”. Instead of maintaining the application in each users’ +workstation, updates and changes only need to be applied to the server. +Also all data, not just the shared parts, is saved on the server whose +backups are much easier to handle. When your user’s workstation breaks, +you can just give him/her a replacement and the work can continue. + +[[memory_and_cpu_usage_is_centralized_to_server]] +Memory and CPU usage is centralized to server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On the negative side is the fact that some of the computing previously +done by your users workstation is now moved to the server. The CPU hit +is typically negligible, but you might face some memory constraints +without taking this fact into account. On the other hand, the fact that +the application memory and processing happens now mostly on the server, +might be a good thing. The server side approach makes it possible to +handle really complex computing tasks, even with really modest handheld +devices. This is naturally possible with Swing and central server as +well, but with Vaadin approach this comes a free bonus feature. + +A typical Vaadin business app consumes 50-500kB of server memory per +user, depending on your application characteristics. If you have a very +small application you can do with smaller number and if you reference a +lot of data from your UI, which usually makes things both faster and +simpler, you might need even more memory per user. + +The per user memory usage is in line with e.g. Java EE standard JSF. If +you do some basic math you can understand this isn’t an issue for most +typical applications and modern application servers. But, in case you +create an accidental memory leak in application code or a carelessly +load the whole database table into memory, the memory consumption may +become an issue earlier than with desktop applications. Accidentally +referencing million basic database entities from a user session will +easily consume 100-200MB of memory per session. This might still be +tolerable in desktop applications, but if you have several concurrent +users, you’ll soon be in trouble. + +The memory issues can usually be rather easily solved by using paging or +by lazy loading the data from the backend to UI. Server capacity is also +really cheap nowadays, so buying a more efficient server or clustering +your application to multiple application servers is most likely much +cheaper than by making compromises in your architectural design. But in +case each of your application users need to do some heavy analysis with +huge in-memory data sets, web applications are still not the way to go +for your use case. + +If your applications memory usage is much more important than its +development cost (read: you are trying to write next GMail), Vaadin +framework might not be the right tool for your. If you still want to go +to web applications, in this scenario you should strive for completely +(server) stateless application and keep your UI logic in browsers. +http://www.gwtproject.org[GWT] is a great library for this kind of +applications. + +[[basic_component_usage]] +Basic component usage +~~~~~~~~~~~~~~~~~~~~~ + +Basic component usage is something where you’ll really find yourself +comfortable from the day one. APIs are not exactly the same, but they +share the principle. Lets look at a very basic example, lets create a +textfield and a button and just throw the textfield value on button +click to sysout for debugging. + +[source,java] +.... +final JTextField textField = new JTextField(); +JButton button = new JButton(); +button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("You typed: " + textField.getText()); + } +}); +add(textField); +add(button); +.... + +… and the very same thing in Vaadin application looks like this: + +[source,java] +.... +final TextField textField = new TextField(); +Button button = new Button(); +button.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(Button.ClickEvent event) { + System.out.println("You typed: " + textField.getValue()); + } +}); +addComponent(textField); +addComponent(button); +.... + +No need to explain what happens in either of the cases ;-) Typically +when Swing developers start using Vaadin, in basic component usage they +find the methods they are looking for quickly with the help of their +favorite IDE. + +Vaadin http://demo.vaadin.com/sampler/[Sampler] is a demo application +that contains examples of the core components with source code usage +example and references to JavaDocs. It is the favorite reference for +many Vaadin developers. Naturally you can also refer to plain JavaDocs +and our Book of Vaadin, the complete reference manual for Vaadin. + +[[event_handling_and_event_dispatching_thread]] +Event handling and Event dispatching thread +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Like most typical desktop GUI libraries, Swing serializes all access to +UI via so called event dispatching thread. It fires event listeners you +hook to components and if you wish to modify the UI from another thread, +you submit your UI changing tasks to it with +SwingUtilities.invokeAndWait(Runnable) or +SwingUtilities.invokeLater(Runnable). + +In Vaadin there is no similar thread, but naturally parallel UI access +needs to be avoided. Vaadin uses UI (~ browser tab/window) level +locking. Like with Swing apps, the code executed by framework (UI init, +event listeners) is “thread safe”” by default. These code blocks are +usually run in Servlet containers thread that is handling an +HTTP/Websocket request. In case you need to modify a UI from any other +thread, you should use _UI.getCurrent().access(Runnable)_ or +_UI.getCurrent().accessSynchronously(Runnable)_ to ensure there is no +parallel access. + +[[application_bootstrap]] +Application bootstrap +~~~~~~~~~~~~~~~~~~~~~ + +A Vaadin application is basically a +http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServlet.html[HttpServlet] +behind the scenes. In portal environment its is a Portlet. Bootstrapping +a Vaadin application depends a bit on the execution environment and used +helper libraries. + +In Swing applications your execution typically starts from the iconic +https://github.com/mstahv/ejb-swing-vaadin-crud/blob/master/desktop/src/main/java/org/vaadin/swingersclub/SwingApplication.java#L49-L52[main +method] or from an Applet’s init method. In simple Vaadin Servlet +deployment the similar entry point to your code is _UI_ class and its +_init_ method. The counterpart for UI class is browser window or browser +tab. If your Vaadin application is “embedded” into another page, you +should consider it as the “slot” in that host page. One servlet can +handle multiple UIs, mapped to different URLs, but typically you just +have one per application. + +A code snippet below is an example of low level hello world Vaadin +application bootstrap, it introduces a Vaadin servlet as a nested class +using the @WebServlet annotation and a Vaadin UI mapped to it: + +[source,java] +.... +public class MyUI extends UI { + + @WebServlet(urlPatterns = "/*", name = "MyUIServlet") + @VaadinServletConfiguration(ui = MyUI.class, productionMode = false) + public static class MyUIServlet extends VaadinServlet { + } + + @Override + protected void init(VaadinRequest vaadinRequest) { + setContent(new Label("Hello World!")); + } + +} +.... + +But, like with non trivial Swing apps, you might want to delegate some +of this low level stuff to a framework that takes care of servlet, setup +and UI mapping. It is highly suggested to use e.g. +https://vaadin.com/javaee/[Java EE environment] with Vaadin CDI add-on +or https://vaadin.com/spring/[Spring] as a basis for your application. +In these cases you typically end up having different application views +as class files and container specific annotations to hint how those +should be served for the end users. In the example we are using +cdi-helpers add-on that also gives you a basic top level navigation and +application layout for free. + +The following class will be automatically visible in our applications +menu. Not that the screenshot also shows some other views but our “about +view”. + +[source,java] +.... +@CDIView("about") +public class AboutView extends VerticalLayout implements View { + + @PostConstruct + void init() { + addComponent(new Label("Hello World !")); + } + + @Override + public void enter(ViewChangeListener.ViewChangeEvent viewChangeEvent) { + } +} +.... + +image:img/helloworldview.png[image] + +_Screenshot of the hello world view_ + +[[laying_out_components]] +Laying out components +~~~~~~~~~~~~~~~~~~~~~ + +In Swing you are using different Layout implementations that take care +of positioning components in JPanel’s sub classes. You will find +similarly named Layout interface in Vaadin as well, but there is a +conceptual difference. In Vaadin Layout is just a normal component that +whose main feature is to contain other components. + +[[layouts_in_vaadin]] +Layouts in Vaadin +^^^^^^^^^^^^^^^^^ + +As you probably have learned while working with Swing applications, +building layouts is generally a rather complex topic. We believe we have +come up with really powerful and logical API, but understanding the +basic concepts about layouts is something you really want to do before +building any non-trivial application. Check out at least a nice +http://youtu.be/7UxEfaQq4EQ?list=PLcRrh9hGNalnmA1mbDS0NBuq6N3Mnw2u1[tutorial +style webinar] we had last year and also refer to our manual. + +Most commonly used Layout implementations are VerticalLayout, +HorizontalLayout and GridLayout. By combining and configuring them +intelligently you can achieve pretty much everything. CssLayout is also +commonly used, due to its simplicity in browsers DOM. If you plan to +theme your application it will be the favorite of your CSS artist, but +it works also without any CSS at all, pretty much like FlowLayout in +Swing, although you need to use some CSS if you want the flow to be +horizontal. + +One thing related to Layouts is that each component in Vaadin has a +caption and an icon. Most often these properties are handled by the +layout and different layouts handle them in different ways. For example +the FormLayout places caption and icon on the left side of the component +as where HorizontalLayout and VerticalLayout place captions above the +component. Naturally you don’t need to use the built in captions (and +icons), but you can use Label components instead, like with Swing +applications, and manually place them in the desired location. + +To get an overview of Layout components in Vaadin, you can also take a +quick overview of them via our +http://demo.vaadin.com/sampler/#ui/layout[Sampler application]. + +[[custom_layouts]] +Custom layouts +^^^^^^^^^^^^^^ + +The fact that Layout is just a component that contains other components +gives us some nice flexibility. They can easily be reused to make a more +domain specific classes using composition and, in case you can also +master some browser development, it is easy to build completely new +layouts. Even if you want to stick on the safe JVM side, the +http://vaadin.com/directory[Directory] contains lots of different kind +of layout implementations for custom purposes. Check e.g. BorderLayout +(you can probably guess how it works ;-) ), ColumnLayout, +DragAndDropLayouts, PortalLayouts and the handy layout helpers in +Viritin. + +There is also a CustomLayout component in the core distribution, for +which a better describing name would probably be “HtmlTemplateLayout”. +From that you can figure out what it does. If you have a skilled +“designer” in your team who masters html and css, you can use his HTML +templates. Into the markup you just need to specify the “slots” where +you want to place Vaadin components. + +[[visual_view_composition]] +Visual view composition +~~~~~~~~~~~~~~~~~~~~~~~ + +Some Swing developers swear for the name of handwritten layouts and +complete control of your views. Another tribe likes to draft the UIs +with visual tools and then wire it to the application logic using Java. +The same thing in Vaadin world. + +image:https://vaadin.com/documents/10187/8663276/designersetup/c3ddcc59-0b6f-40f2-8bb2-456261b5d7a3?t=1418989464957[image] + +Vaadin Eclipse plugin comes with https://vaadin.com/designer[Vaadin +Designer] that lets you design your UIs in “WYSIWYG” manner. You can add +code manually to your visually designed classes and then later return to +visual positioning if you want. + +The https://vaadin.com/designer[latest version] changed the “master +data” of the layout to be based on HTML5 style markup. This may sound +like a weird decision for some experienced Java developers, but the idea +is that your layout designs and visual appearance can also be edited by +less technical graphical artists, who don’t know anything about Java +programming, but can do amazing tricks with graphics, html, css and +typography. Named components will be naturally available via +auto-generated classes, so customization and wiring to other parts of +your application will still be plain old Java development that you +already master. It is just the auto-generated Java parts that we changed +into markup like format. + +[[binding_data_to_components]] +Binding data to components +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +https://vaadin.com/book/-/page/datamodel.html#datamodel[Binding data] +means the task of moving data between your UI components and your +backend/domain objects, in both directions. Some Swing users are using +advanced data binding libraries like BeansBinding. BeansBinding concepts +could be adapted to Vaadin applications as well, but there are also +really handy built-in helpers into Vaadin. + +There are interfaces called +https://vaadin.com/api/com/vaadin/data/Item.html[Item] and +https://vaadin.com/api/com/vaadin/data/Property.html[Property] (and utility +implementations for those), used by all Vaadin +http://vaadin.com/api/com/vaadin/data/Field.html[Field] components. You +can use those, but most often you’ll use the built in BeanItem +implementation, and typically via BeanFieldGroup helper. BeanFieldGroup +can automatically bind your entities/DTOs to the corresponding +https://vaadin.com/api/com/vaadin/ui/Field.html[Field] components. +Similarly to BeansBinding in Swing development, this saves you from +writing a huge amount of boilerplate code that basically just moves +values from UI to your domain objects and vice versa. + +The BeanFieldGroup in Vaadin also supports by default +http://beanvalidation.org[Bean Validation] annotations you might have +already defined into your domain objects. The same rules can then be +used on the UI layer to automatically perform validation before throwing +your domain objects back to business layer. + +If you have ever used JTable component you are probably familiar with +Swing’s interface called TableModel that is used to provide a way for +JTable to list the actual data into it. In Vaadin the similar task is +delegated to +https://vaadin.com/api/com/vaadin/data/Container.html[Container] +interface that contains Item instances. There are built in container +implementations in the framework, of which BeanItemContainer will most +probably become very familiar to you. It is a simple and efficient way +to list your entities in Vaadin Table and in various select components. + +[[lazy_loading_large_data_sets]] +Lazy loading large data sets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In your Swing apps, if you have listed big data sets into your UI, you +probably know you need to be careful what you load into your +applications memory. Also, as your data is probably shared on the server +in business applications, the network usage between your server and +client may easily become the bottleneck. Typically this is solved by +showing just the top most results of your DB query or using some sort of +“paging” when listing lots of data. + +As we discussed earlier, Vaadin applications UI code has a huge aid from +being executed right next to your data. The data is often already in +your application servers memory or in a DB server that is either in the +same physical server or most likely at least connected with strong +network connection to your application server. This make data accessing +both efficient and simple. + +At the same time the well optimized UI components in Vaadin only send +the essential data through the wire from server to the client. For +example in Table and ComboBox, only the visible parts of the data is +sent to the client side and this ways network usage stays low, even when +(virtually) displaying huge amounts of data. + +In case you can’t (due to scalability, memory usage) load all your data +into servers memory, you’ll have to do similar tricks in Vaadin as well +or you might run out of memory with lots of concurrent users. Limiting +the result set and using paging at UI level is naturally in basic tools +for Vaadin developers as well. + +But as UI components already do lazy loading between your server and +client, you can also extend the lazy loading chain all the way to the +database using “lazy loading” implementations of the +https://vaadin.com/api/com/vaadin/data/Container.html[Container API]. +You can pretty easily write a totally custom version for your specific +use case, but the strongly suggested method is to use helpers like +https://vaadin.com/web/matti/blog/-/blogs/connecting-large-amounts-of-data-to-ui[LazyList] +or https://vaadin.com/addon/lazy-query-container[LazyQueryContainer] +instead. In most lazy loading cases, those are the tools that you really +should use, but in some architectures you can also consider using +https://vaadin.com/api/com/vaadin/data/util/sqlcontainer/SQLContainer.html[SqlContainer] +or https://vaadin.com/addon/vaadin-jpacontainer[JPAContainer] which do +rather optimized lazy loading automatically as well. + +[[structuring_your_ui_code]] +Structuring your UI code +~~~~~~~~~~~~~~~~~~~~~~~~ + +If you have maintained a large Swing application, you probably know it +is possible to write messy code, event with Java and its static typing +and great IDEs. For large desktop applications, especially with large +teams and long maintained projects, you have probably applied some sort +of design patterns like MVC or MVP to structure your UI code. + +The very same applies to Vaadin code as well. In large applications you +most likely want to use some sort of strict rules to structure your +code. In smaller applications it is fine to just separate logical parts +of your UI to different, possibly reusable, classes. + +Thanks to similarities with Vaadin and Swing, you can apply your +existing experience on this topic directly to Vaadin. Implementing a +clean MVP pattern is a part of https://vaadin.com/training[Advanced +Vaadin course], in case you want some proven experiences on the topic. +Also, consider to use tools like http://cdi-spec.org[CDI] or +http://projects.spring.io/spring-framework/[Spring], which may help you +to implement your patterns in even more cleaner manner. + +[[testing]] +Testing +~~~~~~~ + +One of the largest advantages of using well structured UI code is that +it often becomes easier to write tests for your UI logic. By using e.g. +MVP pattern in your code you can write unit tests for your presenter +classes. + +In addition to writing unit tests to your backend and UI logic, it is +good to have full stack integration tests or automated acceptance tests. +http://arquillian.org[Arquillian] is a nice tool to write tests that run +in a e.g. Java EE container with a real DB. + +Another nice helper to implement full end-to-end testing is +https://vaadin.com/add-ons/testbench[Vaadin TestBench]. It is based on +the open source Selenium project and drives real browsers and simulates +user interactions. This way you can test the whole application stack +from browser level to the database. + +[[example_crud_and_its_vaadin_conversion]] +Example CRUD and its Vaadin conversion +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Lets image you have a server that stores your customer data. The +persistency and business logic is hidden behind an EJB and your Swing +based rich client reads and writes data into that via a remote EJB. +There are lots of this kind of applications or bit similar that use more +lower level communication mechanism to the database. + +We will use this kind of example application and look what the different +UI implementations look like. Using this example you can hopefully get a +pretty realistic idea what converting a Swing based Applet or desktop +application into a Vaadin based web application might require and cost. + +The heart of the example is the EJB that talks to the underlying RDBMS. +This part is shared by both Swing and Vaadin UI. The server used in the +example is pretty modern Apache TomEE. Although your application might +be using older technology, the concepts are most likely very similar, +even if you were using lower level RMI, CORBA or even raw DB connection. + +Our example is a pretty trivial CRUD, but the business logic running in +the EJB is typically the most critical part of your application. Luckily +you can most often recycle this part of your application, as such as in +this case, or with some modernization, and just re-write the UI part. +Also at the UI part the programming model will be very familiar, so the +task will be really easy for you and your colleagues - even without any +web development experience. + +In this example we will just use raw Swing and Vaadin APIs in the UI. +Some vice men in the industry have prepared for big changes in +technologies. In case you have done something like this into your UI +code the “Vaadin upgrade” might be even easier. E.g. one of our +customer, when moving from AWT to Swing, wrote a bit more generic +wrappers for their UI component and split all the UI logic to separate +controllers. This was to help transition to yet another UI framework in +the future. Today, from desktop world, you would naturally first think +JavaFX. Instead of going into JavaFX, they wanted to eliminate Java +requirement from their clients totally and go with pure browsers +technologies. + +image:img/ejbswingvaadin.png[Architecture +diagram] + +Architectural overview how a Swing based "thin client +application" backed by an EJB can be transferred to web era using +Vaadin. In the example application we build a both Swing and Vaadin UIs, +connecting to exactly same EJB backend. + +[[application_initialization]] +Application initialization +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you have been working with some larger Swing apps, you are, instead +of starting up a JFrame from your main method like in our example, most +probably using some sort of application framework as a basis. The +https://netbeans.org/features/platform/index.html[NetBeans Platform] is +an example of such. Similarly with Vaadin, it is hardly ever a good idea +to go with raw Vaadin and a servlet container. + +There are couple of nice choices and in this example we are using a +standard Java EE basis and use Vaadin CDI as the “framework” that help +us to bootstrap the UI, and also in the next step to bind it to our +backend. + +As a bonus, when using Vaadin CDI, you need to know even less about +Servlets and web specific stuff. In Vaadin CDI application, the entry +point to your application is the +https://vaadin.com/api/com/vaadin/ui/UI.html[UI class] that you annotate +with _@CDIUI(“”)_. The empty string means the UI’s “deployment path”, +the last part in your url that you use to access your application, which +in our example is the actual “root” of our application. If you want, you +can have multiple UI’s in your application, just map them to different +urls. The Vaadin CDI add-on will “magically” introduce the low level +Servlet and configure your UIs to be displayed via it. + +If you look at +https://github.com/mstahv/ejb-swing-vaadin-crud/blob/master/server/src/main/java/org/vaadin/vaadinui/AppUI.java[the +actual UI class] in the example application, you’ll see it is +practically empty. This is because we are using a yet another extension +(our class extends ViewMenuUI from a +https://vaadin.com/addon/cdi-helpers[cdi-helpers library]) to Vaadin CDI +that creates you a basic top level application layout and view +navigation automatically. This may be just what you need, but in many +complex applications you might want to write a more domain specific +version for this this part. + +The actual meat of the user interface code is written into views, +annotated with CDIView. If you introduce a following class to your +application, it will automatically automatically mapped to +http://yourapp.com/contextpaht/#!about and the cdi-helpers will +automatically register it to your applications main menu. + +[source,java] +.... +@CDIView("about") +public class AboutView extends VerticalLayout implements View { + + @PostConstruct + void init() { + addComponent(new Label("Hello Vaadin World!")); + } + + @Override + public void enter(ViewChangeListener.ViewChangeEvent viewChangeEvent) { + } +} +.... + +If you are not familiar with CDI or managed beans in general, you might +think why I’m doing the addComponent call in the @PostConstruct +annotated init method instead of creating a basic constructor. In this +particular case there wouldn’t be a difference, but in the next step we +will be using dependency injection to connect to our EJB. As +dependencies are not resolved yet during constructor call, it is often +simpler to do all view initialization in @PostConstruct annotated init +method instead. + +The enter method is called by Vaadin each time user enters the view. It +is handy to refresh some some often changing data in it, but most often +you don’t need to do anything in it. + +[[ejb_lookup]] +EJB lookup +^^^^^^^^^^ + +In our desktop Swing example we have an ejb-client available on our +classpath, and when the application first time needs access to the +(remote) EJB, +https://github.com/mstahv/ejb-swing-vaadin-crud/blob/master/desktop/src/main/java/org/vaadin/swingersclub/SwingApplication.java#L145-L166[it +gets resolved] using a JNDI lookup with proper parameters. This is +pretty handy actually, especially as we don’t have any proper security +control in our example. + +In a real world application, if you are not using a remote EJB, client +server communication might be bit trickier, but you most likely have +some sort of remote interface you’ll somehow detect. + +In Vaadin application we could use exactly the same way, but as we chose +a proper Java EE + Vaadin CDI basis for our example application, the +very same procedure can be done in much cleaner and more maintainable +manner. As our UI objects are CDI managed beans, we can simply use @EJB +or @Inject annotation to get the reference to the very same +CustomerFacade. The example below uses simple field injection, but +stricter architects might want you to use constructor or method +injection. + +[source,java] +.... +@Inject +CustomerService service; +.... + +In the further steps we’ll notice that the actual accessing our +stateless EJB is pretty much similar in both cases. + +[[listing_entries_from_the_backend_to_table]] +Listing entries from the backend to Table +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In our example Swing application we are using a +https://github.com/mstahv/ejb-swing-vaadin-crud/blob/master/desktop/src/main/java/org/vaadin/swingersclub/SwingApplication.java#L58[simple +TableModel], based on AbstractTableModel, to bind our customer database +to UI table. We simply +https://github.com/mstahv/ejb-swing-vaadin-crud/blob/master/desktop/src/main/java/org/vaadin/swingersclub/SwingApplication.java#L137-L143[grab +all entities] from the backend to local List instance and create a +TableModel that serves data form the list. For larger table you’d +probably need to implement some sort of paging or just rudely limit the +amount of listed entities. The code snippet from our Swing example is +listed below. The CustomerTableModel is then passed to JTable instance. + +[source,java] +.... +private List customers; + +class CustomerTableModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return customers.size(); + } + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (customers == null) { + customers = getCustomerFacade().findAll(); + } + Customer c = customers.get(rowIndex); + switch (columnIndex) { + case 0: + return c.getFirstName(); + case 1: + return c.getLastName(); + case 2: + return c.getEmail(); + } + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getColumnName(int column) { + return columnNames[column]; + } +} +.... + +In our Vaadin application we are using technically a pretty similar +in-memory table view for the database. The example actually uses a +commonly used helper class from an add-on called Viritin, that just +accepts the list of pojos, but you gain similar result with +BeanItemContainer and raw Table component as well. Creating a basic +BeanItemContainer containing all our customers would look like this: + +[source,java] +.... +BeanItemContainer bic + = new BeanItemContainer<>(Customer.class, facade.findAll()); +.... + +The BeanItemContainer makes bean introspection to detect the available +properties and you can then limit the available columns by configuring +your https://vaadin.com/api/com/vaadin/ui/Table.html[Table] instance. +You can also get to the low level with Vaadin, like with the Swing +example, and implement a custom +https://vaadin.com/api/com/vaadin/data/Container.html[Container] +implementation that you can pass to the Table. Most often the utility +containers are what you want. + +Listing the whole (database) table in a Vaadin user interface this way +is already far more efficient because the most of the data is still only +in your server. The +[Table]https://vaadin.com/api/com/vaadin/ui/Table.html) component only +sends the visible viewport the Vaadin’s “thin client” and when user +scrolls down more rows are fetched from the servers memory. You’ll save +a lots of bandwidth compared to the desktop version. + +However, if we still want to make our Vaadin version better, we could +use lazy loading of data also on the server side. The MTable from the +https://vaadin.com/addon/viritin[Viritin add-on] in the following +example only needs strategies to fetch the total number of entities and +fetching entities in page manner. With Java 8 style constructs a lazy +loading “binding” to our CustomerFacade could look like this: + +[source,java] +.... +MTable table = new MTable( + firstRow -> facade.findRange(firstRow, maxResults), + facade.count(), + maxResults +); +.... + +That scales really well both in client and in server, and uses only a +tiny bit of memory on the server side. There are lots of various lazy +loading container implementations available in the +https://vaadin.com/directory/[Vaadin Directory] and you can naturally +write one yourself as well. + +[[binding_entity_to_a_form_for_editing]] +Binding entity to a form for editing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In our Swing example, we are creating an editor for our domain object in +class called CustomerForm. In it we prepare some JTextField for the +essential properties of the domain model, whose values we copy to domain +object when users clicks the save button. + +[source,java] +.... +JTextField firstName = new JTextField(); +JTextField lastName = new JTextField(); +JTextField email = new JTextField("yourname@yourdomain.com"); +JButton create = new JButton("Create"); +JButton update = new JButton("Update"); + +@Override +public void actionPerformed(ActionEvent e) { + Customer c = editedCustomer; + if (e.getSource() == create) { + c = new Customer(); + } + c.setFirstName(firstName.getText()); + c.setLastName(lastName.getText()); + c.setEmail(email.getText()); + if (e.getSource() == create) { + application.getCustomerFacade().create(c); + } else { + application.getCustomerFacade().edit(c); + } +} +.... + +When an existing entity is set for editing, we set the existing values +for the fields. + +[source,java] +.... +void editCustomer(Customer c) { + this.editedCustomer = c; + firstName.setText(c.getFirstName()); + lastName.setText(c.getLastName()); + email.setText(c.getEmail()); + updateButtonStates(); +} +.... + +Using this kind of low level approach is pretty similar in Vaadin as +well. Instead of JTextField you are just using TextField class from +Vaadin core and instead of getText() method you use getValue() to grab +the value from the field. + +In a real life, in both Vaadin and Swing apps, you probably want to use +your life for something better than writing lots of boilerplate code for +this kind of basic forms. Vaadin comes with a really powerful tool +called BeanFieldGroup to free yourself from writing the “glue code” +between your UI fields and domain object properties. You can use either +use naming convention or a @PropertyId annotation to hint BeanFieldGroup +to do the “two way mapping” automatically. The getter-setter parts of +the above can be written using BeanFieldGroup as follows: + +[source,java] +.... +TextField firstName = new TextField("First name"); +TextField lastName = new TextField("Last name"); +TextField email = new TextField("Email"); + +public void setCustomer(Customer customer) { + this.customer = customer; + BeanFieldGroup bfg + = BeanFieldGroup.bindFieldsUnbuffered(customer, this); +} +.... + +The BeanFieldGroup can also attach automatically constructed validators +to your fields, based on the standard http://beanvalidation.org[Bean +Validation] annotations, that you already might have on your domain +objects. Naturally, you can manually configure validators at UI layer as +well. BeanFieldGroup also provides “UI level buffering”, that might be +handy in case you happen to be using “live objects”. In typical business +apps, the backend is the right level that does the “buffering” for you. + +In our Vaadin example, we are using BeanFieldGroup via an +https://github.com/mstahv/ejb-swing-vaadin-crud/blob/master/server/src/main/java/org/vaadin/vaadinui/CustomerForm.java[AbstractForm +based class]. In addition to bean binding, it provides us with basic +save, reset and delete buttons. In your own application you have the +liberty to go with low level manual binding, automatic binding using +BeanFieldGroup or with a handy helpers like the AbstractForm or your +application specific version of it. The first option has the most +control, the last has the cleanest code and is probably what you want in +most cases. + +[[possible_conversion_strategy_wrappers_for_your_own_ui_framework]] +Possible conversion strategy: wrappers for your own UI framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some Swing developers have created a domain specific wrappers to hide +the actual Swing API from their application code. One of our clients did +this when moving their application from AWT to Swing and then wanting to +prepare for a yet another UI library change in the future. They just +needed to make some changes to their wrappers and then create an +“adapter” for Vaadin UI. + +Whether this kind of wrapper strategy really pays off probably depends +on the characteristics of the application itself. In our recent customer +case it was estimated that even though their application was huge, going +with pure Vaadin solution would have had smaller expenses. Also by +creating your own UI abstraction layer, you will lose some flexibility +and make additional development more expensive. However, the solution +has also other advantages. With this approach it is cheap to maintain +and support both modern Vaadin web client and the legacy Swing app and +still implement fixes and enhancements to only one code base. + +The concept is by no means unique in the industry and SibVisions JVx +framework is based on a similar approach. UI can be implemented just +once can be deployed to both Swing and Vaadin based client applications. + +[[possible-conversion-strategy-gradually-move-to-web-ui]] +Possible conversion strategy: gradually move to web UI +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Instead of rewriting the UI layer in a one big project it might be a +good idea to start moving to web era gradually. You should consider this +kind of approach especially if you have a well designed "backend" layer +and a large application. You could start with screens that are most +often needed on devices without managed software installations, like +tablets, or home computers. Then proceed the conversion on more rarely +used screens. On office computers you could keep using the existing +software, with the full feature set, during the transition period. + +[[example-app-sources]] +Example app sources +^^^^^^^^^^^^^^^^^^^ + +The full sources for the +https://github.com/mstahv/ejb-swing-vaadin-crud[EJB CRUD example with +both Swing and Vaadin UIs] is available via GitHub. diff --git a/documentation/articles/contents.asciidoc b/documentation/articles/contents.asciidoc index eef64dfd93..f0dc2f97b5 100644 --- a/documentation/articles/contents.asciidoc +++ b/documentation/articles/contents.asciidoc @@ -10,7 +10,25 @@ are great, too. [discrete] == Articles -- link:DevelopingPortletsForTheWebspherePortalServer.asciidoc[Developing Portlets for the Websphere Portal Server] +- link:DevelopingPortletsForTheWebspherePortalServer.asciidoc[Developing portlets for the WebSphere Portal Server] - link:ConfigureComboBoxesWisely.asciidoc[Configure ComboBoxes wisely] - link:LettingTheUserDownloadAFile.asciidoc[Letting the user download a file] - link:UsingVaadinInIBMDomino.asciidoc[Using Vaadin in IBM Domino] +- link:VaadinTutorialForSwingDevelopers.asciidoc[Vaadin tutorial for Swing developers] +- link:SettingAndReadingSessionAttributes.asciidoc[Setting and reading session attributes] +- link:EnablingServerPush.asciidoc[Enabling server push] +- link:CleaningUpResourcesInAUI.asciidoc[Cleaning up resources in a UI] +- link:SendingEmailFromJavaApplications.asciidoc[Sending email from Java applications] +- link:OptimizingSluggishUI.asciidoc[Optimizing sluggish UI] +- link:UsingParametersWithViews.asciidoc[Using parameters with views] +- link:ConfiguringPushForYourEnviroment.asciidoc[Configuring push for your environment] +- link:SettingAndReadingCookies.asciidoc[Setting and reading cookies] +- link:UsingPolling.asciidoc[Using polling] +- link:FindingTheCurrentUIAndPageAndVaadinSession.asciidoc[Finding the current UI and page and Vaadin Session] +- link:CreatingAnApplicationThatPreservesStateOnRefresh.asciidoc[Creating an application that preserves state on refresh] +- link:SendingEventsFromTheClientToTheServerUsingRPC.asciidoc[Sending events from the client to the server using RPC] +- link:HandlingLogout.asciidoc[Handling logout] +- link:ScalableWebApplications.asciidoc[Scalable web applications] +- link:RememberToTheSetTheLocale.asciidoc[Remember to the set the locale] +- link:MVCBasicsInITMillToolkit.asciidoc[MVC Basics in IT Mill Toolkit] +- link:CustomizingTheStartupPageInAnApplication.asciidoc[Customizing the startup page in an application] diff --git a/documentation/articles/img/ActivityUML.jpg b/documentation/articles/img/ActivityUML.jpg new file mode 100644 index 0000000000..012469a21b Binary files /dev/null and b/documentation/articles/img/ActivityUML.jpg differ diff --git a/documentation/articles/img/MVCBasicsProject.zip b/documentation/articles/img/MVCBasicsProject.zip new file mode 100644 index 0000000000..02b2e9cc03 Binary files /dev/null and b/documentation/articles/img/MVCBasicsProject.zip differ diff --git a/documentation/articles/img/designersetup.jpg b/documentation/articles/img/designersetup.jpg new file mode 100644 index 0000000000..8837bf0d36 Binary files /dev/null and b/documentation/articles/img/designersetup.jpg differ diff --git a/documentation/articles/img/ejbswingvaadin.png b/documentation/articles/img/ejbswingvaadin.png new file mode 100644 index 0000000000..92acab8be3 Binary files /dev/null and b/documentation/articles/img/ejbswingvaadin.png differ diff --git a/documentation/articles/img/figure3s2.png b/documentation/articles/img/figure3s2.png new file mode 100644 index 0000000000..f74bf03cf8 Binary files /dev/null and b/documentation/articles/img/figure3s2.png differ diff --git a/documentation/articles/img/figure6a.png b/documentation/articles/img/figure6a.png new file mode 100644 index 0000000000..5ee3e86424 Binary files /dev/null and b/documentation/articles/img/figure6a.png differ diff --git a/documentation/articles/img/figure6s.png b/documentation/articles/img/figure6s.png new file mode 100644 index 0000000000..4df3458d1f Binary files /dev/null and b/documentation/articles/img/figure6s.png differ diff --git a/documentation/articles/img/figure7s.png b/documentation/articles/img/figure7s.png new file mode 100644 index 0000000000..7c7ac12517 Binary files /dev/null and b/documentation/articles/img/figure7s.png differ diff --git a/documentation/articles/img/helloworldview.png b/documentation/articles/img/helloworldview.png new file mode 100644 index 0000000000..49a9d0ae9a Binary files /dev/null and b/documentation/articles/img/helloworldview.png differ diff --git a/documentation/articles/img/howvaadinworks2.png b/documentation/articles/img/howvaadinworks2.png new file mode 100644 index 0000000000..47235d8b7f Binary files /dev/null and b/documentation/articles/img/howvaadinworks2.png differ diff --git a/documentation/articles/img/mockapp-ui.png b/documentation/articles/img/mockapp-ui.png new file mode 100644 index 0000000000..dd74f0e33f Binary files /dev/null and b/documentation/articles/img/mockapp-ui.png differ diff --git a/documentation/articles/img/moduleDesign.jpg b/documentation/articles/img/moduleDesign.jpg new file mode 100644 index 0000000000..c35c93493a Binary files /dev/null and b/documentation/articles/img/moduleDesign.jpg differ diff --git a/documentation/articles/img/view.jpg b/documentation/articles/img/view.jpg new file mode 100644 index 0000000000..e14580ed77 Binary files /dev/null and b/documentation/articles/img/view.jpg differ diff --git a/documentation/articles/img/webusers.png b/documentation/articles/img/webusers.png new file mode 100644 index 0000000000..7daeb699f6 Binary files /dev/null and b/documentation/articles/img/webusers.png differ -- cgit v1.2.3