example.xml
5.16 KB
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
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ ]>
<chapter id="example">
<title>JSF web application example</title>
<para>
Let's illustrate these ideas with a full example. We're going to implement user login/logout for an application
that uses JSF. First, we'll define a request-scoped bean to hold the username and password entered during login,
with constraints defined using annotations from the Bean Validation specification:
</para>
<programlisting role="JAVA"><![CDATA[@Named @RequestScoped
public class Credentials {
private String username;
private String password;
@NotNull @Length(min=3, max=25)
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
@NotNull @Length(min=6, max=20)
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}]]></programlisting>
<para>This bean is bound to the login prompt in the following JSF form:</para>
<programlisting role="JAVA"><![CDATA[<h:form>
<h:panelGrid columns="2" rendered="#{!login.loggedIn}">
<f:validateBean>
<h:outputLabel for="username">Username:</h:outputLabel>
<h:inputText id="username" value="#{credentials.username}"/>
<h:outputLabel for="password">Password:</h:outputLabel>
<h:inputSecret id="password" value="#{credentials.password}"/>
</f:validateBean>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>]]></programlisting>
<para>
Users are represented by a JPA entity:
</para>
<programlisting role="JAVA"><![CDATA[@Entity
public class User {
private @NotNull @Length(min=3, max=25) @Id String username;
private @NotNull @Length(min=6, max=20) String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String setPassword(String password) { this.password = password; }
}]]></programlisting>
<para>
(Note that we're also going to need a <literal>persistence.xml</literal> file to configure the JPA persistence
unit containing <literal>User</literal>.)
</para>
<para>
The actual work is done by a session-scoped bean that maintains information about the currently logged-in user
and exposes the <literal>User</literal> entity to other beans:
</para>
<programlisting role="JAVA"><![CDATA[@SessionScoped @Named
public class Login implements Serializable {
@Inject Credentials credentials;
@Inject @UserDatabase EntityManager userDatabase;
private User user;
public void login() {
List<User> results = userDatabase.createQuery(
"select u from User u where u.username = :username and u.password = :password")
.setParameter("username", credentials.getUsername())
.setParameter("password", credentials.getPassword())
.getResultList();
if (!results.isEmpty()) {
user = results.get(0);
}
else {
// perhaps add code here to report a failed login
}
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user != null;
}
@Produces @LoggedIn User getCurrentUser() {
return user;
}
}]]></programlisting>
<para><literal>@LoggedIn</literal> and <literal>@UserDatabase</literal> are custom qualifier annotations:</para>
<programlisting role="JAVA"><![CDATA[@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface LoggedIn {}]]></programlisting>
<programlisting role="JAVA"><![CDATA[@Qualifier
@Retention(RUNTIME)
@Target({METHOD, PARAMETER, FIELD})
public @interface UserDatabase {}]]></programlisting>
<para>
We need an adaptor bean to expose our typesafe <literal>EntityManager</literal>:
</para>
<programlisting role="JAVA"><![CDATA[class UserDatabaseProducer {
@Produces @UserDatabase @PersistenceContext
static EntityManager userDatabase;
}]]></programlisting>
<para>Now <literal>DocumentEditor</literal>, or any other bean, can easily inject the current user:</para>
<programlisting role="JAVA"><![CDATA[public class DocumentEditor {
@Inject Document document;
@Inject @LoggedIn User currentUser;
@Inject @DocumentDatabase EntityManager docDatabase;
public void save() {
document.setCreatedBy(currentUser);
docDatabase.persist(document);
}
}]]></programlisting>
<para>Or we can reference the current user in a JSF view:</para>
<programlisting role="XML"><![CDATA[<h:panelGroup rendered="#{login.loggedIn}">
signed in as #{currentUser.username}
</h:panelGroup>]]></programlisting>
<para>
Hopefully, this example gave you a taste of the CDI programming model. In the next chapter, we'll explore
dependency injection in greater depth.
</para>
<!--
vim:et:ts=3:sw=3:tw=120
-->
</chapter>