Update of /cvsroot/struts/dialogs/src/net/jspcontrols/dialogs/samples/wizard/rules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20952/src/net/jspcontrols/dialogs/samples/wizard/rules Added Files: SignupWizard.java StepConfirm.java StepDetails.java StepSignup.java Log Message: --- NEW FILE: SignupWizard.java --- /* * Copyright 2004-2005 Michael Jouravlev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jspcontrols.dialogs.samples.wizard.rules; import net.jspcontrols.wizard.impl.Wizard; import net.jspcontrols.wizard.intf.IWizardStep; import net.jspcontrols.wizard.intf.IWizardTransition; import net.jspcontrols.wizard.impl.WizardTransition; import java.util.Map; /** * This class defines a simple signup wizard. The wizard has three steps * with the second step being optional. * <p> * The first step asks a new user for a login name and a password he would * like to use. Also the first step asks if a user wants to supply additional * information about himself. If yes, the second step is made available, it * allows to input the favorite book and the favorite movie of the user. * The third step simply shows user's selections. * <p> * This class stores some UI-related information like error messages, but * efforts were made to design it agnostic of particular web framework. * * @author Michael Jouravlev */ public class SignupWizard extends Wizard { /************************************************************************** * New User Signup wizard nodes **************************************************************************/ /** * The first step accepts and stores new user name and password. * It also allows for a client to choose to provide additional personal * information. */ final StepSignup stepSignup; /** * Returns first node of Signup wizard: the Signup node * @return the Signup node */ public StepSignup getStepSignup() {return stepSignup;} /** * Details step stores favorite book and movie name. These * values are not required if this step is not selected in the signup * node (not quite how UI-agnostic validation should work, but this * is a demo for a wizard, not for MVC concepts). */ final StepDetails stepDetails; /** * Returns second node of Signup wizard: the Personalization node * @return the Personalization node */ public StepDetails getStepDetails() {return stepDetails;} /** * Confirmation step displays user information and stores it in * application domain accounts. After this step the wizard can be * disposed. */ final IWizardStep stepConfirm; /** * Returns third node of Signup wizard: the Confirmation node * @return the Confirmation node */ public IWizardStep getStepConfirm() {return stepConfirm;} /************************************************************************** * Wizard constructor **************************************************************************/ /** * Constructs a signup wizard. */ public SignupWizard (Map errors) { /** * Wizard controller can either use built-in error message map, * or use an external one. */ if (errors != null) { this.errors = errors; } /******** * Nodes ********/ /* * Nodes do not need to be exposed or to have a separate * identifier. But to use wizard accounts data as javabean properties * in the UI, it is easier to define getters and setters for * references to nodes, instead of looking up nodes by name. */ stepSignup = new StepSignup(this, "Signup Node"); stepDetails = new StepDetails(this, "Details Node"); stepConfirm = new StepConfirm(this, "Confirmation Node"); /* * Starting off the Signup node */ sourceState = stepSignup; /* * Set the current node to source node */ currentState = sourceState; /******** * Edges ********/ /* * Path from identification node to personalization node. * Will be chosen if name and password are valid and a user * elected to enter personal information. */ stepSignup.addOutgoingTransition( new WizardTransition(this, "Signup To Detail", stepDetails) { public boolean validate() { return stepSignup.getPersonalize() && stepSignup.validateNameAndPassword(); } } ); /* * Path from identification node to confirmation node. Will be chosen * if name and password are valid and a user did not elect to enter * personal information. */ stepSignup.addOutgoingTransition( new WizardTransition(this, "Signup To Confirmation", stepConfirm) { public boolean validate() { return stepSignup.validateNameAndPassword(); } } ); /* * Path from personalization node to confirmation node * Will be chosen if both book and movie are non null values. */ stepDetails.addOutgoingTransition( new WizardTransition(this, "Detail To Confirmation", stepConfirm) { public boolean validate() { if ( stepDetails.getSecurityAnswerId() > -1 && stepDetails.getSecurityAnswer() != null && stepDetails.getSecurityAnswer().trim().length() > 0) { return true; } else { wizard.getWizardErrors().put( "loginsignupcontrol.nosecurityinfo", null); return false; } } } ); } /** * This is a simple test of this wizard. The wizard itself does not need * UI interaction. * * @param args command-line params, unused */ public static void main(String[] args) { /* * Create wizard controller */ SignupWizard wiz = new SignupWizard(null); /* * Traverse wizard and display all edges */ System.out.println("Traversing the signup wizard"); wiz.traverse(wiz.getSourceStep()); /* * User name and password not set, try to move forward. * Should stay on the Signup Node */ IWizardStep curNode = null; boolean flag = false; do { System.out.println("\nGo forward"); wiz.forward(); curNode = wiz.getCurrentStep(); System.out.println("Current node: " + curNode.getStateName()); if (curNode instanceof StepSignup) { StepSignup nodeSignup = (StepSignup) wiz.getCurrentStep(); nodeSignup.setName("sysdba"); nodeSignup.setPassword("masterkey"); nodeSignup.setPersonalize(true); } else if (curNode instanceof StepDetails) { StepDetails nodePersonal = (StepDetails) wiz.getCurrentStep(); /* * First time do not enter book and movie, enter on second pass */ if (flag) { nodePersonal.setSecurityAnswerId(1); nodePersonal.setSecurityAnswer("Moscow"); } else { flag = !flag; } } } while (!"Confirmation Node".equals(curNode.getStateName())); do { System.out.println("\nGo back"); wiz.back(); curNode = wiz.getCurrentStep(); System.out.println("Current node: " + curNode.getStateName()); } while (!"Signup Node".equals(curNode.getStateName())); curNode = wiz.getStepByName("Non-existing node"); if (curNode != null) { System.out.println("\nFound node: " + curNode.getStateName()); } else { System.out.println("\nNot Found node: " + "Non-existing node"); } curNode = wiz.getStepByName("Details Node"); if (curNode != null) { System.out.println("Found node: " + curNode.getStateName()); } else { System.out.println("Not Found node: " + "Details node"); } curNode = wiz.getStepByName("Signup Node"); if (curNode != null) { System.out.println("Found node: " + curNode.getStateName()); } else { System.out.println("Not Found node: " + "Signup node"); } } /** * Traverses the wizard from the beginning to the end. Used for testing. * @param node node from which to start traversal */ public static void traverse(IWizardStep node) { IWizardTransition[] srcEdges = node.getOutgoingTransitions(); if (srcEdges == null || srcEdges.length ==0) { } else { for (int i = 0; i < srcEdges.length; i++) { System.out.println( "Edge Name: " + srcEdges[i].getName() + "\n\tSource node: " + srcEdges[i].getSource().getStateName() + "\n\tTarget node: " + srcEdges[i].getTarget().getStateName()); traverse(srcEdges[i].getTarget()); if (srcEdges[i].getSource() != node) { System.out.println("Edge " + srcEdges[i].getName() + " is incorrect"); } } } } } --- NEW FILE: StepConfirm.java --- /* * Copyright 2004-2005 Michael Jouravlev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jspcontrols.dialogs.samples.wizard.rules; import net.jspcontrols.wizard.impl.WizardStep; import net.jspcontrols.dialogs.samples.wizard.accounts.UserAccounts; import net.jspcontrols.dialogs.samples.wizard.rules.SignupWizard; import java.util.Map; /** * Confirmation node of Signup wizard. Being the last node of the wizard, * it submits wizard data to user accounts storage. * * @version 0.1 * @author Michael Jouravlev */ public class StepConfirm extends WizardStep { /** * Creates Confirmation node * * @param value owner wizard object, used to reference wizard-wide * objects like error messages * @param name name of this node. Used to locate node by name, and * as mapping for JSP page */ public StepConfirm(SignupWizard value, String name) { super(value, name); } /** * Instructs the node to clear boolean values. Usually called * before the properties are about to be updated. */ public void resetBooleans() { /* no-op */ } } --- NEW FILE: StepDetails.java --- /* * Copyright 2004-2005 Michael Jouravlev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jspcontrols.dialogs.samples.wizard.rules; import net.jspcontrols.wizard.impl.WizardStep; import net.jspcontrols.dialogs.samples.wizard.rules.SignupWizard; /** * Personalization node of Signup wizard. This is the second and optional node * of the wizard, allows a user to provide additional information like * favorite book and favorite movie * * @version 0.1 * @author Michael Jouravlev */ public class StepDetails extends WizardStep { /************************************************************************** * Business properties: favorite book and movie **************************************************************************/ private String[] securityQuestions = new String[] { "What is your favorite color?", "What is your home city?", "What is your pet's name?", "Who was your childhood hero?" }; public String[] getSecurityQuestions() {return securityQuestions;} /** * Returns security question as string */ public String getSecurityQuestion() { return isStateInPath() && securityAnswerId > -1 ? securityQuestions[securityAnswerId] : null; } /** * Id of security question, this is stored in database */ private int securityAnswerId = -1; /** * Returns id of security question */ public int getSecurityAnswerId() {return securityAnswerId;} /** * Sets security answer id * @param securityAnswerId security answer id */ public void setSecurityAnswerId(int securityAnswerId) { this.securityAnswerId = securityAnswerId; } /** * Additional user info: favorite book */ private String securityAnswer; /** * Returns user favorite book as part of personalization information, * only if the Personalization node is included in the actual path * of the wizard. * * @return favorite book */ public String getSecurityAnswer() {return isStateInPath() ? securityAnswer : null;} /** * Sets the favorite book as part of personalization information. * This method is not to be called by client. * * @param securityAnswer favorite user book */ public void setSecurityAnswer(String securityAnswer) {this.securityAnswer = securityAnswer;} /************************************************************************** * Constructor **************************************************************************/ /** * Creates Personalization node * * @param value owner wizard object, used to reference wizard-wide * objects, like error messages * @param name name of this node */ public StepDetails(SignupWizard value, String name) { super(value, name); } /** * Instructs the node to clear boolean values. Usually called * before the properties are about to be updated. */ public void resetBooleans() { /* no-op */ } } --- NEW FILE: StepSignup.java --- /* * Copyright 2004-2005 Michael Jouravlev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jspcontrols.dialogs.samples.wizard.rules; import net.jspcontrols.wizard.impl.WizardStep; import net.jspcontrols.dialogs.samples.wizard.rules.SignupWizard; /** * Identification node of Signup wizard, the first node of the wizard. * it allows to enter name and password of a new user, and also to choose * an option to provide additional information (the information itself would * be provided on the second step: Personalization) * * @version 0.1 * @author Michael Jouravlev */ public class StepSignup extends WizardStep { /************************************************************************** * Business properties: name and password **************************************************************************/ /** * User name */ private String name; /** * Returns user name stored in the wizard * @return user name */ public String getName() {return name;} /** * Sets user name in the wizard * @param name user name to set in the wizard */ public void setName(String name) {this.name = name;} /** * User password */ private String password; /** * Returns user password stored in the wizard as cleartext. It is * up to the UI layer how to display it. */ public String getPassword() {return password;} /** * Sets user password in the wizard * @param password user password to set in the wizard */ public void setPassword(String password) { this.password = password; } /** * Repeated user password */ private String confirmPassword; /** * Returns repeated user password */ public String getConfirmPassword() {return confirmPassword;} /** * Sets repeated user password in the wizard * @param confirmPassword user password to set in the wizard */ public void setConfirmPassword(String confirmPassword) { this.confirmPassword = confirmPassword; } /************************************************************************** * Wizard flow control property **************************************************************************/ /** * Flag that user wants to supply additional information about himself */ private boolean personalize; /** * Returns true if personalization flag is set. This flag is used * to determine if wizard should display Personalization step. * @return true if a user selected to provide additional information * about himself. */ public boolean getPersonalize() {return personalize;} /** * Sets personalization flag. * @param personalize true if user wants to provide additional * information about himself. */ public void setPersonalize(boolean personalize) {this.personalize = personalize;} /************************************************************************** * Common validation method, called from outgoing edges **************************************************************************/ /** * Validates name and password. Validation is normally performed * in an outgoing edge, but this common functionality is used by * both outgoing edges. * * @return true if name and password conform to basic * name/password requirements */ public boolean validateNameAndPassword() { boolean valid = true; /* * User name should have length of at least three characters. * * We can also verify that login already exists, but this wizard * does it only when wizard is about to be finished, so if a user * cancels it in the middle, the persistent storage is not called. * * Notice typecast to SignupWizard, which defines getErrors() * method. */ if ( name == null || name.length() < 3 ) { valid = false; getWizard().getWizardErrors().put( "loginsignupcontrol.usernametooshort", new String[] {name} ); } /* * User password should have length of at least five characters */ if ( password == null || password.length() < 5 ) { valid = false; getWizard().getWizardErrors().put( "loginsignupcontrol.passwordtooshort", null ); /* * Repeated password should be equal to password */ } else if ( !password.equals(confirmPassword) ) { valid = false; getWizard().getWizardErrors().put( "loginsignupcontrol.passwordnotequal", null ); } return valid; } /************************************************************************** * Constructor **************************************************************************/ /** * Creates Signup node * * @param value owner wizard object, used to reference wizard-wide * objects like error messages * @param name name of this node */ public StepSignup(SignupWizard value, String name) { super(value, name); } /** * Instructs the node to clear boolean values. Usually called * before the properties are about to be updated. */ public void resetBooleans() { setPersonalize(false); } } |