1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
|
---
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")))
|