The following JSF page defines a login prompt for a web application:

<f:view>
<h:form>
<h:panelGrid columns=”2″ rendered=”#{!login.loggedIn}”>
<h:outputLabel for=”username”>Username:</h:outputLabel>
<h:inputText id=”username” value=”#{credentials.username}”/>
<h:outputLabel for=”password”>Password:</h:outputLabel>
<h:inputText id=”password” value=”#{credentials.password}”/>
</h:panelGrid>
<h:commandButton value=”Login” action=”#{login.login}” rendered=”#{!login.loggedIn}”/>
<h:commandButton value=”Logout” action=”#{login.logout}” rendered=”#{login.loggedIn}”/>
</h:form>
</f:view>

The Unified EL expressions in this page refer to beans named credentials and login.

The Credentials bean has a lifecycle that is bound to the JSF request:

@Model
public class Credentials {

private String username;
private String password;

public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }

public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }

}

The @Model annotation defined in Built-in stereotypes is a stereotype that identifies the Credentials bean as a model object in an MVC architecture.

The Login bean has a lifecycle that is bound to the HTTP session:

@SessionScoped @Model
public class Login implements Serializable {

@Inject Credentials credentials;
@Inject @Users EntityManager userDatabase;

private CriteriaQuery<User> query;
private Parameter<String> usernameParam;
private Parameter<String> passwordParam;

private User user;

@Inject
void initQuery(@Users EntityManagerFactory emf) {
CriteriaBuilder cb = emf.getCriteriaBuilder();
usernameParam = cb.parameter(String.class);
passwordParam = cb.parameter(String.class);
query = cb.createQuery(User.class);
Root<User> u = query.from(User.class);
query.select(u);
query.where( cb.equal(u.get(User_.username), usernameParam),
cb.equal(u.get(User_.password), passwordParam) );
}

public void login() {

List<User> results = userDatabase.createQuery(query)
.setParameter(usernameParam, credentials.getUsername())
.setParameter(passwordParam, credentials.getPassword())
.getResultList();

if ( !results.isEmpty() ) {
user = results.get(0);
}

}

public void logout() {
user = null;
}

public boolean isLoggedIn() {
return user!=null;
}

@Produces @LoggedIn User getCurrentUser() {
if (user==null) {
throw new NotLoggedInException();
}
else {
return user;
}
}

}

The @SessionScoped annotation defined in Built-in scope types is a scope type that specifies the lifecycle of instances of Login. Managed beans with this scope must be serializable.

The @Inject annotation defined by the Dependency Injection for Java specification identifies an injected field which is initialized by the container when the bean is instantiated, or an initializer method which is called by the container after the bean is instantiated, with injected parameters.

The @Users annotation is a qualifier type defined by the application:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Users {}

The @Produces annotation defined in Declaring a producer method identifies the method getCurrentUser() as a producer method, which will be called whenever another bean in the system needs the currently logged-in user, for example, whenever the user attribute of the DocumentEditor class is injected by the container:

@Model
public class DocumentEditor {

@Inject Document document;
@Inject @LoggedIn User currentUser;
@Inject @Documents EntityManager docDatabase;

public void save() {
document.setCreatedBy(currentUser);
em.persist(document);
}

}

The @Documents annotation is another application-defined qualifier type. The use of distinct qualifier types enables the container to distinguish which JPA persistence unit is required.

When the login form is submitted, JSF assigns the entered username and password to an instance of the Credentials bean that is automatically instantiated by the container. Next, JSF calls the login() method of an instance of Login that is automatically instantiated by the container. This instance continues to exist for and be available to other requests in the same HTTP session, and provides the User object representing the current user to any other bean that requires it (for example, DocumentEditor). If the producer method is called before the login() method initializes the user object, it throws a NotLoggedInException.

Contexts and Dependency Injection JSF example

Leave a Reply

Your email address will not be published. Required fields are marked *