@Secure.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like
We use a "strict" DTD to make IE follow the alignment rules. -->
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<head>
<title>Log In</title>
<link rel="stylesheet" type="text/css" href="${context:css/theapp/login.css}"/>
<t:remove>
<!-- This link allows previewability -->
<link rel="stylesheet" type="text/css" href="../css/theapp/login.css"/>
</t:remove>
</head>
<body>
<div id="page">
<div id="titlesbar">
<h1>Example App</h1>
</div>
<div id="instructions">
Initially, the available login IDs are admin, secofr, and john, <br/>
and the passwords are the same as the login ID.
</div>
<form t:type="form" t:id="login">
<div class="title">
Log In
</div>
<table>
<tr>
<th><t:label for="loginId"/>:</th>
<td><input t:type="TextField" t:id="loginId" size="15" maxLength="12" t:validate="required, maxLength=15"/></td>
</tr>
<tr>
<th><t:label for="password"/>:</th>
<td><input t:type="PasswordField" t:id="password" size="15" maxLength="12" t:validate="required, maxLength=15"/></td>
</tr>
<tr>
<th> </th>
<td class="buttons">
<input type="submit" value="Login"/>
<a t:type="eventlink" t:event="GoHome" href="#">Home</a>
</td>
</tr>
<tr>
<td colspan="2">
<div id="errors">
<t:errors/>
</div>
</td>
</tr>
</table>
</form>
<div id="secure">
A page can be made secure, ie. accessible only by HTTPS, by annotating the page's class with <code>@Secure</code>.<br/>
You will also have to enable HTTPS on your web server, which may require some configuration.<br/>
References:
<a href="http://tapestry.apache.org/https.html">Securing your application with HTTPS</a>,
<a href="http://roneiv.wordpress.com/2008/01/03/jboss-tutorial-how-to-enable-ssl-https-on-jboss-as-well-as-other-nice-to-know-configurations/">How to enable SSL on JBoss</a>.
</div>
</div>
<div id="source">
<t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/pages/theapp/Login.tml"/>
<t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/pages/theapp/Login.java"/>
<t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/commons/IIntermediatePage.java"/>
<t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/css/theapp/login.css"/>
<t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/state/theapp/Visit.java"/>
<t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/base/theapp/SimpleBasePage.java"/>
</div>
</body>
</html>
package jumpstart.web.pages.theapp;
import javax.ejb.EJB;
import jumpstart.business.commons.exception.BusinessException;
import jumpstart.business.domain.security.User;
import jumpstart.business.domain.security.iface.ISecurityFinderServiceLocal;
import jumpstart.util.ExceptionUtil;
import jumpstart.web.base.theapp.SimpleBasePage;
import jumpstart.web.commons.IIntermediatePage;
import jumpstart.web.pages.Index;
import jumpstart.web.pages.theapp.general.Welcome;
import jumpstart.web.state.theapp.Visit;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.Link;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.Form;
import org.apache.tapestry5.corelib.components.TextField;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.slf4j.Logger;
// To make this page accessible only by HTTPS, annotate it with @Secure and ensure your web server can deliver HTTPS.
// See http://tapestry.apache.org/secure.html .
// @Secure
public class Login extends SimpleBasePage implements IIntermediatePage {
// The activation context
@Property
private String loginId;
// Screen fields
@Property
private String password;
// Generally useful bits and pieces
@Persist
private Link nextPageLink;
@Component(id = "login")
private Form form;
@Component(id = "loginId")
private TextField loginIdField;
@Inject
private Logger logger;
@Inject
private ComponentResources componentResources;
@EJB
private ISecurityFinderServiceLocal securityFinderService;
// The code
@Override
public void setNextPageLink(Link nextPageLink) {
this.nextPageLink = nextPageLink;
}
String onPassivate() {
return loginId;
}
void onActivate(String loginId) {
this.loginId = loginId;
}
void onValidateFromLogin() {
if (form.getHasErrors()) {
// We get here only if a server-side validator detected an error.
return;
}
try {
// Authenticate the user
User user = securityFinderService.authenticateUser(loginId, password);
// Store the user in the Visit
setVisit(new Visit(user));
logger.info(user.getLoginId() + " has logged in.");
}
catch (BusinessException e) {
form.recordError(loginIdField, e.getLocalizedMessage());
}
catch (Exception e) {
logger.error("Could not log in. Stack trace follows...");
logger.error(ExceptionUtil.printStackTrace(e));
form.recordError(getMessages().get("login_problem"));
}
}
Object onSuccess() {
if (nextPageLink == null) {
return Welcome.class;
}
else {
componentResources.discardPersistentFieldChanges();
return nextPageLink;
}
}
Object onGoHome() {
componentResources.discardPersistentFieldChanges();
return Index.class;
}
}
package jumpstart.web.commons;
import org.apache.tapestry5.Link;
public interface IIntermediatePage {
void setNextPageLink(Link nextPageLink);
}
body { font-family: Arial, Helvetica, sans-serif; font-size: 12px; font-weight: normal; margin: 0; width: 100%; }
a { text-decoration: none; color: #3D69B6; }
a:hover { text-decoration: underline; }
#page { margin: 0 auto; background-color: #f8f8f8;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f4f4', endColorstr='#ffffff'); /* for IE */
background: -webkit-gradient(linear, left top, left bottom, from(#eaeaea), to(#ffffff)); /* for webkit browsers */
background: -moz-linear-gradient(top, #f2f2f2, #ffffff); /* for firefox 3.6+ */; }
#titlesbar { padding: 16px 0; }
#titlesbar h1 { font-size: 22px; margin: 0px auto 6px; text-align: center; color: #444; }
#instructions { padding: 80px 0 24px; text-align: center; color: #666; }
#login { display: table; margin: auto; text-align: center; padding: 8px 10px; background-color: #fff; width: 280px; font-size: 14px;
border: 1px solid #ddd; border-radius: 6px; -webkit-border-radius: 6px; -moz-border-radius: 6px;
box-shadow: 0 1px 4px rgba(0, 0, 0, .065); -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, .065); -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, .065); }
#login .title { margin: auto; padding: 10px; color: #333; font-size: 16px; font-weight: bold; }
#login table { border-collapse: collapse; border-spacing: 0; width: 100%; }
#login th { color: #666; font-size: 14px; font-weight:normal; text-align: right; }
#login td { width: 60%; padding: 4px; color: #666; font-size: 14px; font-weight: bold; text-align: left; }
#login td.buttons { padding: 8px 2px; margin: auto; text-align: left; font-weight: normal; }
#login td.buttons a { padding-top: 20px; }
#errors { }
#errors div.t-error { margin: 0; border: none; }
#errors div.t-error div.t-banner { display: none; }
#errors div.t-error ul { color: inherit; background-color: inherit; list-style: none; margin: 0; }
#errors div.t-error li { color: red; background-color: inherit; text-align: center; font-weight: normal; }
#secure { padding: 80px 0; text-align: center; color: #666; }
#source { padding: 8px; background-color: #fff; }
package jumpstart.web.state.theapp;
import java.io.Serializable;
import jumpstart.business.domain.security.User;
import jumpstart.business.domain.security.User.PageStyle;
@SuppressWarnings("serial")
public class Visit implements Serializable {
private Long myUserId = null;
private String myLoginId = null;
private PageStyle pageStyle = null;
private String dateInputPattern = null;
private String dateViewPattern = null;
private String dateListPattern = null;
public Visit(User user) {
myUserId = user.getId();
cacheUsefulStuff(user);
}
public void noteChanges(User user) {
if (user == null) {
throw new IllegalArgumentException();
}
else if (user.getId().equals(myUserId)) {
cacheUsefulStuff(user);
}
}
private void cacheUsefulStuff(User user) {
myLoginId = user.getLoginId();
pageStyle = user.getPageStyle();
dateInputPattern = user.getDateInputPattern();
dateViewPattern = user.getDateViewPattern();
dateListPattern = user.getDateListPattern();
}
public Long getMyUserId() {
return myUserId;
}
public String getMyLoginId() {
return myLoginId;
}
public PageStyle getPageStyle() {
return pageStyle;
}
public String getDateInputPattern() {
return dateInputPattern;
}
public String getDateViewPattern() {
return dateViewPattern;
}
public String getDateListPattern() {
return dateListPattern;
}
}
package jumpstart.web.base.theapp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import jumpstart.business.commons.exception.BusinessException;
import jumpstart.business.commons.exception.CannotDeleteIsReferencedException;
import jumpstart.business.commons.exception.DuplicateAlternateKeyException;
import jumpstart.business.commons.exception.DuplicatePrimaryKeyException;
import jumpstart.business.commons.exception.OptimisticLockException;
import jumpstart.business.commons.interpreter.BusinessServiceExceptionInterpreter;
import jumpstart.business.domain.security.User;
import jumpstart.web.state.theapp.Visit;
import org.apache.tapestry5.annotations.SessionState;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
public class SimpleBasePage {
// @SessionState is explained in http://tapestry.apache.org/session-storage.html
@SessionState
private Visit visit;
private boolean visitExists;
private BusinessServiceExceptionInterpreter businessServiceExceptionInterpreter = new BusinessServiceExceptionInterpreter();
@Inject
private Messages messages;
protected Messages getMessages() {
return messages;
}
public Visit getVisit() {
return visit;
}
protected void setVisit(Visit visit) {
this.visit = visit;
}
public boolean isVisitExists() {
return visitExists;
}
public String getDateInputPattern() {
return visitExists ? visit.getDateInputPattern() : User.defaultDateInputPattern;
}
public String getDateViewPattern() {
return visitExists ? visit.getDateViewPattern() : User.defaultDateViewPattern;
}
public String getDateListPattern() {
return visitExists ? visit.getDateListPattern() : User.defaultDateListPattern;
}
public DateFormat getDateInputFormat() {
// If you want to make this static or move it into Visit, first read
// http://thread.gmane.org/gmane.comp.java.tapestry.user/20925
return new SimpleDateFormat(visit.getDateInputPattern());
}
public DateFormat getDateViewFormat() {
// If you want to make this static or move it into Visit, first read
// http://thread.gmane.org/gmane.comp.java.tapestry.user/20925
return new SimpleDateFormat(visit.getDateViewPattern());
}
public DateFormat getDateListFormat() {
// If you want to make this static or move it into Visit, first read
// http://thread.gmane.org/gmane.comp.java.tapestry.user/20925
return new SimpleDateFormat(visit.getDateListPattern());
}
protected String interpretBusinessServicesExceptionForCreate(Exception e) {
String message = "";
BusinessException x = businessServiceExceptionInterpreter.interpret(e);
if (x instanceof DuplicatePrimaryKeyException) {
message = getMessages().get("create_failed_duplicate_primary_key");
}
else if (x instanceof DuplicateAlternateKeyException) {
DuplicateAlternateKeyException d = (DuplicateAlternateKeyException) x;
message = getMessages().format("create_failed_duplicate_alternate_key", d.getTechnicalMessageText());
}
else {
message = x.getMessage();
}
return message;
}
protected BusinessException interpretBusinessServicesException(Exception e) {
return businessServiceExceptionInterpreter.interpret(e);
}
protected String interpretBusinessServicesExceptionForAdd(Exception e) {
String message = "";
BusinessException x = businessServiceExceptionInterpreter.interpret(e);
if (x instanceof OptimisticLockException) {
message = getMessages().get("add_failed_optimistic_lock");
}
else if (x instanceof DuplicatePrimaryKeyException) {
message = getMessages().get("add_failed_duplicate_primary_key");
}
else if (x instanceof DuplicateAlternateKeyException) {
DuplicateAlternateKeyException d = (DuplicateAlternateKeyException) x;
message = getMessages().format("add_failed_duplicate_alternate_key", d.getTechnicalMessageText());
}
else {
message = x.getMessage();
}
return message;
}
protected String interpretBusinessServicesExceptionForChange(Exception e) {
String message = "";
BusinessException x = businessServiceExceptionInterpreter.interpret(e);
if (x instanceof OptimisticLockException) {
message = getMessages().get("change_failed_optimistic_lock");
}
else if (x instanceof DuplicateAlternateKeyException) {
DuplicateAlternateKeyException d = (DuplicateAlternateKeyException) x;
message = getMessages().format("change_failed_duplicate_alternate_key", d.getTechnicalMessageText());
}
else {
message = x.getMessage();
}
return message;
}
protected String interpretBusinessServicesExceptionForRemove(Exception e) {
String message = "";
BusinessException x = businessServiceExceptionInterpreter.interpret(e);
if (x instanceof OptimisticLockException) {
message = getMessages().get("remove_failed_optimistic_lock");
}
else if (x instanceof CannotDeleteIsReferencedException) {
CannotDeleteIsReferencedException c = (CannotDeleteIsReferencedException) x;
message = getMessages().format("remove_failed_is_referenced",
new Object[] { c.getReferencedByEntityName() });
}
else {
message = x.getMessage();
}
return message;
}
protected String interpretBusinessServicesExceptionForDelete(Exception e) {
String message = "";
BusinessException x = businessServiceExceptionInterpreter.interpret(e);
if (x instanceof OptimisticLockException) {
message = getMessages().get("delete_failed_optimistic_lock");
}
else if (x instanceof CannotDeleteIsReferencedException) {
CannotDeleteIsReferencedException c = (CannotDeleteIsReferencedException) x;
message = getMessages().format("delete_failed_is_referenced",
new Object[] { c.getReferencedByEntityName() });
}
else {
message = x.getMessage();
}
return message;
}
}