diff options
Diffstat (limited to 'documentation/advanced/advanced-global.asciidoc')
-rw-r--r-- | documentation/advanced/advanced-global.asciidoc | 234 |
1 files changed, 0 insertions, 234 deletions
diff --git a/documentation/advanced/advanced-global.asciidoc b/documentation/advanced/advanced-global.asciidoc deleted file mode 100644 index 94b822235a..0000000000 --- a/documentation/advanced/advanced-global.asciidoc +++ /dev/null @@ -1,234 +0,0 @@ ---- -title: Accessing Session-Global Data -order: 15 -layout: page ---- - -[[advanced.global]] -= Accessing Session-Global Data - -__This section is mostly up-to-date with Vaadin 7, but has some information -which still needs to be updated.__ - -Applications typically need to access some objects from practically all user -interface code, such as a user object, a business data model, or a database -connection. This data is typically initialized and managed in the UI class of -the application, or in the session or servlet. - -For example, you could hold it in the UI class as follows: - - -[source, java] ----- -class MyUI extends UI { - UserData userData; - - public void init() { - userData = new UserData(); - } - - public UserData getUserData() { - return userData; - } -} ----- - -Vaadin offers two ways to access the UI object: with [methodname]#getUI()# -method from any component and the global [methodname]#UI.getCurrent()# method. - -The [methodname]#getUI()# works as follows: - - -[source, java] ----- -data = ((MyUI)component.getUI()).getUserData(); ----- - -This does not, however work in many cases, because it requires that the -components are attached to the UI. That is not the case most of the time when -the UI is still being built, such as in constructors. - - -[source, java] ----- -class MyComponent extends CustomComponent { - public MyComponent() { - // This fails with NullPointerException - Label label = new Label("Country: " + - getUI().getLocale().getCountry()); - - setCompositionRoot(label); - } -} ----- - -The global access methods for the currently served servlet, session, and UI -allow an easy way to access the data: - - -[source, java] ----- -data = ((MyUI) UI.getCurrent()).getUserData(); ----- - -[[advanced.global.passing.problem]] -== The Problem - -The basic problem in accessing session-global data is that the -[methodname]#getUI()# method works only after the component has been attached to -the application. Before that, it returns [parameter]#null#. This is the case in -constructors of components, such as a [classname]#CustomComponent#: - -Using a static variable or a singleton implemented with such to give a global -access to user session data is not possible, because static variables are global -in the entire web application, not just the user session. This can be handy for -communicating data between the concurrent sessions, but creates a problem within -a session. - -The data would be shared by all users and be reinitialized every time a new user -opens the application. - - -[[advanced.global.passing.solutions-overview]] -== Overview of Solutions - -To get the application object or any other global data, you have the following -solutions: - -* Pass a reference to the global data as a parameter - -* Initialize components in [methodname]#attach()# method - -* Initialize components in the [methodname]#enter()# method of the navigation view -(if using navigation) - -* Store a reference to global data using the __ThreadLocal Pattern__ - - -Each solution is described in the following sections. - - -[[advanced.global.passing]] -== Passing References Around - -You can pass references to objects as parameters. This is the normal way in -object-oriented programming. - - -[source, java] ----- -class MyApplication extends Application { - UserData userData; - - public void init() { - Window mainWindow = new Window("My Window"); - setMainWindow(mainWindow); - - userData = new UserData(); - - mainWindow.addComponent(new MyComponent(this)); - } - - public UserData getUserData() { - return userData; - } -} - -class MyComponent extends CustomComponent { - public MyComponent(MyApplication app) { - Label label = new Label("Name: " + - app.getUserData().getName()); - - setCompositionRoot(label); - } -} ----- - -If you need the reference in other methods, you either have to pass it again as -a parameter or store it in a member variable. - -The problem with this solution is that practically all constructors in the -application need to get a reference to the application object, and passing it -further around in the classes is another hard task. - - -[[advanced.global.attach]] -== Overriding [methodname]#attach()# - -The [methodname]#attach()# method is called when the component is attached to -the UI through containment hierarchy. The [methodname]#getUI()# method always -works. - - -[source, java] ----- -class MyComponent extends CustomComponent { - public MyComponent() { - // Must set a dummy root in constructor - setCompositionRoot(new Label("")); - } - - @Override - public void attach() { - Label label = new Label("Name: " + - ((MyUI)component.getUI()) - .getUserData().getName()); - - setCompositionRoot(label); - } -} ----- - -While this solution works, it is slightly messy. You may need to do some -initialization in the constructor, but any construction requiring the global -data must be done in the [methodname]#attach()# method. Especially, -[classname]#CustomComponent# requires that the -[methodname]#setCompositionRoot()# method is called in the constructor. If you -can't create the actual composition root component in the constructor, you need -to use a temporary dummy root, as is done in the example above. - -Using [methodname]#getUI()# also needs casting if you want to use methods -defined in your UI class. - - -[[advanced.global.threadlocal]] -== ThreadLocal Pattern - -((("ThreadLocal pattern", id="term.advanced.global.threadlocal", range="startofrange"))) - - -Vaadin uses the ThreadLocal pattern for allowing global access to the -[classname]#UI#, and [classname]#Page# objects of the currently processed server -request with a static [methodname]#getCurrent()# method in all the respective -classes. This section explains why the pattern is used in Vaadin and how it -works. You may also need to reimplement the pattern for some purpose. - -The ThreadLocal pattern gives a solution to the global access problem by solving -two sub-problems of static variables. - -As the first problem, assume that the servlet container processes requests for -many users (sessions) sequentially. If a static variable is set in a request -belonging one user, it could be read or re-set by the next incoming request -belonging to another user. This can be solved by setting the global reference at -the beginning of each HTTP request to point to data of the current user, as -illustrated in Figure <<figure.advanced.global.threadlocal.sequentiality>>. - -[[figure.advanced.global.threadlocal.sequentiality]] -.Switching a static (or ThreadLocal) reference during sequential processing of requests -image::img/threadlocal-sequentiality-hi.png[] - -The second problem is that servlet containers typically do thread pooling with -multiple worker threads that process requests. Therefore, setting a static -reference would change it in all threads running concurrently, possibly just -when another thread is processing a request for another user. The solution is to -store the reference in a thread-local variable instead of a static. You can do -so by using the [classname]#ThreadLocal# class in Java for the switch reference. - -[[figure.advanced.global.threadlocal.concurrency]] -.Switching [classname]#ThreadLocal# references during concurrent processing of requests -image::img/threadlocal-concurrency-hi.png[] - -(((range="endofrange", startref="term.advanced.global.threadlocal"))) - - - |