View Javadoc

1   package org.appfuse.webapp.pages;
2   
3   import de.agilecoders.wicket.webjars.request.resource.WebjarsJavaScriptResourceReference;
4   import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
5   import org.apache.wicket.markup.head.IHeaderResponse;
6   import org.apache.wicket.markup.head.JavaScriptHeaderItem;
7   import org.apache.wicket.markup.head.OnLoadHeaderItem;
8   import org.apache.wicket.markup.html.*;
9   import org.apache.wicket.markup.html.basic.Label;
10  import org.apache.wicket.markup.html.form.*;
11  import org.apache.wicket.markup.html.form.validation.FormComponentFeedbackBorder;
12  import org.apache.wicket.model.Model;
13  import org.apache.wicket.model.StringResourceModel;
14  import org.apache.wicket.request.Url;
15  import org.apache.wicket.request.cycle.RequestCycle;
16  import org.appfuse.Constants;
17  import org.appfuse.webapp.pages.components.PlaceholderBehavior;
18  import org.appfuse.webapp.pages.components.RequiredBehavior;
19  import org.wicketstuff.annotation.mount.MountPath;
20  
21  import java.util.Map;
22  
23  /**
24   * A login page.
25   *
26   * @author Marcin ZajÄ…czkowski, 2010-09-02
27   */
28  @MountPath("login")
29  public class Login extends AbstractWebPage {
30  
31      private TextField<String> usernameField;
32      private TextField<String> passwordField;
33      private CheckBox rememberMeCheckBox;
34  
35      @Override
36      protected void onInitialize() {
37          super.onInitialize();
38  
39          add(createPageTitleTag("login.title"));
40  
41          //TODO: MZA: Add login hint with: http://code.google.com/p/visural-wicket/
42  
43          Form<Void> loginForm = createLoginForm();
44          add(loginForm);
45  
46          loginForm.add(createFeedbackPanel());
47          loginForm.add(createPageHeading("login.heading"));
48          createAndAddToLoginFormUsernameAndPasswordFields(loginForm);
49          loginForm.add(createRememberMeGroup());
50          add(createSignupLabel());
51  
52      }
53  
54      private void createAndAddToLoginFormUsernameAndPasswordFields(Form<Void> loginForm) {
55          //Border to add red asterisk on error, FormComponentFeedbackIndicator could be used for something more.
56          //TODO: MZA: Take a look at FormComponentFeedbackBorder markup (its wicket:body) as a hint for required label
57          //TODO: MZA: How to change a background color of an input with validation error?
58          loginForm.add(new FormComponentFeedbackBorder("border").add(
59                  (usernameField = new RequiredTextField<String>("username", Model.of("")))));
60          usernameField.add(new PlaceholderBehavior(getString("label.username")));
61          usernameField.add(new RequiredBehavior());
62          loginForm.add(passwordField = new PasswordTextField("password", Model.of("")));
63          passwordField.add(new PlaceholderBehavior(getString("label.password")));
64          passwordField.add(new RequiredBehavior());
65      }
66  
67      private Form<Void> createLoginForm() {
68          return new Form<Void>("loginForm") {
69              @Override
70              protected void onSubmit() {
71                  authenticateUser();
72              }
73          };
74      }
75  
76      //TODO: MZA: Move to if needed somewhere else
77      @SuppressWarnings("unchecked")
78      private Object getValueForKeyFromConfigOrReturnNullIfNoConfig(String configProperty) {
79          Map<String, Object> config = (Map<String, Object>)getServletContext().getAttribute(Constants.CONFIG);
80          if (config == null) {
81              log.warn("{} context attribute is null.", Constants.CONFIG);
82              return null;
83          } else {
84              return config.get(configProperty);
85          }
86      }
87  
88      @Override
89      public void renderHead(IHeaderResponse response) {
90          super.renderHead(response);
91          addLoginJavaScriptToResponse(response);
92          addInitDataOnLoadJavaScriptToResponse(response);
93      }
94  
95      private void addLoginJavaScriptToResponse(IHeaderResponse response) {
96          response.render(JavaScriptHeaderItem.forReference(
97                  new WebjarsJavaScriptResourceReference("jquery-cookie/current/jquery.cookie.js")));
98          response.render(JavaScriptHeaderItem.forUrl("scripts/login.js"));
99      }
100 
101     private void addInitDataOnLoadJavaScriptToResponse(IHeaderResponse response) {
102         response.render(OnLoadHeaderItem.forScript("initDataOnLoad()"));
103     }
104 
105     private WebMarkupContainer createRememberMeGroup() {
106         WebMarkupContainer rememberMeGroup = new WebMarkupContainer("rememberMeGroup");
107         rememberMeGroup.add(createRememberMeCheckboxInsideLabel());
108 
109         boolean isRememberMeEnabled = isRememberMeEnabled();
110         rememberMeGroup.setVisible(isRememberMeEnabled);
111         //TODO: MZA: How does RememberMe work? I don't see any cookie.
112         return rememberMeGroup;
113     }
114 
115     private FormComponentLabel createRememberMeCheckboxInsideLabel() {
116         //TODO: MZA: A trick to have an input component inside a label - pack into a new component if needed somewhere else
117         // https://cwiki.apache.org/WICKET/form-control-labels.html
118         //TODO: MZA: How to keep fields? As class property? Local variable? just assign to a parent?
119         rememberMeCheckBox = new CheckBox("rememberMe", new Model<Boolean>(Boolean.FALSE));
120         FormComponentLabel rememberMeLabel = new FormComponentLabel("rememberMeLabel", rememberMeCheckBox);
121         Label rememberMeLabelSpan = new Label("rememberMeLabelSpan", getString("login.rememberMe"));
122         rememberMeLabelSpan.setRenderBodyOnly(true);
123         rememberMeLabel.add(rememberMeLabelSpan);
124         rememberMeLabel.add(rememberMeCheckBox);
125         return rememberMeLabel;
126     }
127 
128     private boolean isRememberMeEnabled() {
129         Boolean isRememberMeEnabled = (Boolean)getValueForKeyFromConfigOrReturnNullIfNoConfig("rememberMeEnabled");
130         return isRememberMeEnabled != null ? isRememberMeEnabled : false;
131     }
132 
133     private Label createSignupLabel() {
134         String absoluteSignupLink = RequestCycle.get().getUrlRenderer().renderFullUrl(
135                 Url.parse(urlFor(Signup.class, null).toString()));
136         //TODO: MZA: There should be some better way to use URL inside a label (if not, make it an util method)
137         String signupLabelText = new StringResourceModel("login.signup", this, null, new Object[] {
138                 absoluteSignupLink}).getString();
139         Label signupLabel = new Label("signupLabel", signupLabelText);
140         signupLabel.setEscapeModelStrings(false);
141         return signupLabel;
142     }
143 
144     private void authenticateUser() {
145         AuthenticatedWebSession session = AuthenticatedWebSession.get();
146         if (session.signIn(usernameField.getModelObject(), passwordField.getModelObject())) {
147             setDefaultResponsePageIfNecessary();
148         } else {
149             error(getString("errors.password.mismatch"));
150         }
151     }
152 
153     private void setDefaultResponsePageIfNecessary() {
154         continueToOriginalDestination();
155         setResponsePage(getApplication().getHomePage());
156     }
157 }