ovidiu 2002/09/05 17:02:16 Added: src/webapp/samples/flow/examples/prefs prefs.js sitemap.xmap src/webapp/samples/flow/examples/prefs/logic User.java UserRegistry.java src/webapp/samples/flow/examples/prefs/pages login.xsp registrationSuccessful.xsp userInfo.xsp welcome.xsp Log: Simple example of how to handle user login and preferences using the control flow layer. Revision Changes Path 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/prefs.js Index: prefs.js =================================================================== /* prefs.js This file is the central controller piece in the preferences application. It receives the requests from the client browser (the View in the MVC pattern), and coordinates with the Model (written in Java, in the logic/ directory) to do the business logic. Author: Ovidiu Predescu <[EMAIL PROTECTED]> Date: August 30, 2002 */ // The global user registry, through which we add new users or access // existing ones. var userRegistry = Packages.samples.flow.prefs.logic.UserRegistry.getUserRegistry(); var user = null; // This top-level function is called from the sitemap to start the // process of registering a user. // // This function takes care of all the steps required during the // registration of a new user. It is the controller is the MVC // pattern, an intermediary between the View, in our case the client's // browser, and the Model, in the case of this particular function the // code that maintains the registered users. // // The function collects the necessary information from the View, and // calls the Model to do the necessary work of checking whether the // user exists or not, and registering the new user. function registerUser() { var check = false; var errorMsg = null; var login = ""; var password = ""; var firstName = ""; var lastName = ""; var email = ""; while (true) { // Present the user with addUser page. `check' indicates the XSP // template that it needs to check the registration parameters, // and print an indicator close to where the errors // are. `errorMsg' if not null is printed at the top of the page // as an error message. print ("calling registerUser"); sendPage("userInfo.html", { "check" : check, "errorMsg" : errorMsg, "title": "New User Registration", "button" : "Register", "login" : login, "password" : password, "firstName" : firstName, "lastName" : lastName, "email" : email}); check = false; errorMsg = null; login = cocoon.request.get("login"); password = cocoon.request.get("password"); firstName = cocoon.request.get("firstName"); lastName = cocoon.request.get("lastName"); email = cocoon.request.get("email"); if (login == "" || password == "" || firstName == "" || lastName == "" || email == "") { check = true; errorMsg = "Please correct the marked errors before continuing"; continue; } // Check for the existence of an already registered user with the // same login name. There is a possibility of a race condition // here, with another user registering with the same login id // between this check and the creation of a new user few lines // below. We ignore this problem in this example. var existingUser = userRegistry.isLoginNameTaken(login); if (!existingUser) { user = new Packages.samples.flow.prefs.logic.User(login, password, firstName, lastName, email); userRegistry.addUser(user); break; } else { // TODO: I18N errorMsg = "Login name '" + login + "' is already in use, please choose another name"; } } // The user has successfully registered, so we consider (s)he to be // already logged in. At this point we want to create a session, so // that all the JavaScript global variables are shared among // invocations of top-level functions. Up until this point, each // invocation had a separate global scope for the variables. cocoon.createSession(); // Here we just send a response to the client browser and we don't // wait for any response. This is the last page generated by this // top-level function. In general is good to make sure a top-level // function, e.g. one that's invoked directly from the sitemap using // <map:call function="..."> sends a response page to the client at // all the exit points. Otherwise the user will get a blank page and // will be really confused. // // In the case of this particular function, this is the only exit // point. sendPageAndContinue("registrationSuccessful.html", {"firstName" : firstName, "lastName" : lastName}); } // This top-level function is used for user login. function login(errorMsg) { var login = ""; var password = ""; print("login function called"); while (true) { sendPage("login.html", {"errorMsg" : errorMsg, "login" : login, "password" : password}); errorMsg = null; login = cocoon.request.getParameter("login"); password = cocoon.request.getParameter("password"); print ("got login = " + login + ", passwd = " + password); user = userRegistry.getUserWithLogin(login, password); print ("got user = " + user); if (user != null) break; else { // TODO: I18N errorMsg = "No such user or bad password"; } } print ("login successful as user " + user + " using password " + password); // The user has successfully signed in. At this point we want to // create a session, so that all the JavaScript global variables are // shared among invocations of top-level functions. Up until this // point, each invocation had a separate global scope for the // variables. cocoon.createSession(); // We send to the user a welcome page which contains links back to // what (s)he can do. These links essentially point to other top // level functions in this script. sendPageAndContinue("welcome.html", {"firstName" : user.firstName, "lastName" : user.lastName}); } // This function is called to edit the preferences of an already // registered user. If this function was called without the user being // logged in first, the 'user' global variable is null. When this // happens the user is redirected to the login page first. function edit() { if (user == null) login("Please login before continuing"); var login = user.login; var password = user.password; var firstName = user.firstName; var lastName = user.lastName; var email = user.email; var errorMsg = ""; var check = false; while (true) { // Present the user with addUser page. `check' indicates the XSP // template that it needs to check the registration parameters, // and print an indicator close to where the errors // are. `errorMsg' if not null is printed at the top of the page // as an error message. print ("presenting user info"); sendPage("userInfo.html", { "check" : check, "errorMsg" : errorMsg, "title": "Edit account", "button" : "Change", "cancel" : true, "login" : login, "password" : password, "firstName" : firstName, "lastName" : lastName, "email" : email}); if (cocoon.request.get("cancel")) break; check = false; errorMsg = null; login = cocoon.request.get("login"); password = cocoon.request.get("password"); firstName = cocoon.request.get("firstName"); lastName = cocoon.request.get("lastName"); email = cocoon.request.get("email"); if (login == "" || password == "" || firstName == "" || lastName == "" || email == "") { check = true; errorMsg = "Please correct the marked errors before continuing"; continue; } else { // Save the changes the user made in the User object user.login = login; user.password = password; user.firstName = firstName; user.lastName = lastName; user.email = email; break; } } sendPageAndContinue("welcome.html", {"firstName" : user.firstName, "lastName" : user.lastName}); } function logout() { user = null; login("You're successfully logged out. Please log in to continue"); } 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/sitemap.xmap Index: sitemap.xmap =================================================================== <?xml version="1.0"?> <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0"> <map:components> <map:generators default="file"/> <map:transformers default="xslt"/> <map:readers default="resource"/> <map:serializers default="html"/> <map:matchers default="wildcard"/> <map:flow-interpreters default="JavaScript"/> </map:components> <map:resources> <map:resource name="flow"> <map:script src="prefs.js"/> </map:resource> </map:resources> <map:pipelines> <map:pipeline> <map:match pattern="kont/*"> <map:continue with="{1}"/> </map:match> <map:match pattern=""> <map:redirect-to uri="login/"/> </map:match> <map:match pattern="login/"> <map:call function="login"/> </map:match> <map:match pattern="register/"> <map:call function="registerUser"/> </map:match> <map:match pattern="edit/"> <map:call function="edit"/> </map:match> <map:match pattern="logout/"> <map:call function="logout"/> </map:match> </map:pipeline> </map:pipelines> </map:sitemap> 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/logic/User.java Index: User.java =================================================================== /* User.java Representation of a user. Author: Ovidiu Predescu <[EMAIL PROTECTED]> Date: August 28, 2002 */ package samples.flow.prefs.logic; public class User { String login; String password; String firstName; String lastName; String email; public User(String login, String password, String firstName, String lastName, String email) { this.login = login; this.password = password; this.firstName = firstName; this.lastName = lastName; this.email = email; } public int hashCode() { return login.hashCode(); } public boolean equals(Object obj) { User anotherUser = (User)obj; return anotherUser.login.equals(login); } /** * Sets the value of login * * @param argLogin Value to assign to this.login */ public void setLogin(String argLogin) { this.login = argLogin; } /** * Gets the value of login * * @return the value of login */ public String getLogin() { return this.login; } /** * Gets the value of password * * @return the value of password */ public String getPassword() { return this.password; } /** * Sets the value of password * * @param argPassword Value to assign to this.password */ public void setPassword(String argPassword) { this.password = argPassword; } /** * Gets the value of firstName * * @return the value of firstName */ public String getFirstName() { return this.firstName; } /** * Sets the value of firstName * * @param argFirstName Value to assign to this.firstName */ public void setFirstName(String argFirstName) { this.firstName = argFirstName; } /** * Gets the value of lastName * * @return the value of lastName */ public String getLastName() { return this.lastName; } /** * Sets the value of lastName * * @param argLastName Value to assign to this.lastName */ public void setLastName(String argLastName) { this.lastName = argLastName; } /** * Gets the value of email * * @return the value of email */ public String getEmail() { return this.email; } /** * Sets the value of email * * @param argEmail Value to assign to this.email */ public void setEmail(String argEmail) { this.email = argEmail; } } 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/logic/UserRegistry.java Index: UserRegistry.java =================================================================== /* UserRegistry.java Maintains a list of registered users. Author: Ovidiu Predescu <[EMAIL PROTECTED]> Date: August 28, 2002 */ package samples.flow.prefs.logic; import java.util.HashMap; import java.util.Map; /** * Maintains a list of registered users. This is a very simple class, * there is no persistence of the users, but such thing should be easy * to add. * * @author <a href="mailto:[EMAIL PROTECTED]">Ovidiu Predescu</a> * @since August 28, 2002 */ public class UserRegistry { static UserRegistry userRegistry = new UserRegistry(); Map registeredUsers = new HashMap(); public static UserRegistry getUserRegistry() { System.out.println("UserRegistry: obtaining user registry = " + userRegistry); return userRegistry; } protected UserRegistry() { } public synchronized boolean addUser(User user) { if (registeredUsers.containsKey(user.getLogin())) return false; registeredUsers.put(user.getLogin(), user); return true; } public boolean removeUser(User user) { return registeredUsers.remove(user) != null; } /** * Checks is a particular login name is taken or not. * * @param loginName a <code>String</code> value * @return true if <code>loginName</code> is taken, false otherwise */ public boolean isLoginNameTaken(String loginName) { return registeredUsers.get(loginName) != null; } /** * Returns the {@link User} object which represents an user. Note that * we require a password to be present, to avoid presenting private * information to anyone. * * @param loginName a <code>String</code> value * @param password a <code>String</code> value * @return an <code>User</code> value */ public User getUserWithLogin(String loginName, String password) { User user = (User)registeredUsers.get(loginName); if (user == null) return null; return password.equals(user.getPassword()) ? user : null; } } 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/pages/login.xsp Index: login.xsp =================================================================== <?xml version="1.0"?> <!-- Author: Ovidiu Predescu "[EMAIL PROTECTED]" Date: August 30, 2002 --> <xsp:page language="java" xmlns:xsp="http://apache.org/xsp" xmlns:jpath="http://apache.org/xsp/jpath/1.0" > <document> <header> <title>Login</title> <authors> <person name="Ovidiu Predescu" email="[EMAIL PROTECTED]"/> </authors> </header> <body> <s1 title="Login"> <jpath:if test="errorMsg"> <strong><jpath:value-of select="errorMsg"/></strong> </jpath:if> <form><xsp:attribute name="action"><xsp:expr>"../kont/" + <jpath:continuation/></xsp:expr></xsp:attribute> <p>Login name: <input type="text" name="login"> <xsp:attribute name="value"><jpath:value-of select="login"/></xsp:attribute> </input> </p> <p>Password: <input type="password" name="password"/></p> <input type="submit" name="submit" value="Login"/> <p>Not yet registered? <link href="../register/">Register now!</link></p> </form> </s1> </body> </document> </xsp:page> 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/pages/registrationSuccessful.xsp Index: registrationSuccessful.xsp =================================================================== <?xml version="1.0"?> <!-- Author: Ovidiu Predescu "[EMAIL PROTECTED]" Date: August 30, 2002 --> <xsp:page language="java" xmlns:xsp="http://apache.org/xsp" xmlns:jpath="http://apache.org/xsp/jpath/1.0" > <document> <header> <title>New User Registration</title> <authors> <person name="Ovidiu Predescu" email="[EMAIL PROTECTED]"/> </authors> </header> <body> <s1 title="Registration successful!"> <p>Congratulations <strong><jpath:value-of select="firstName"/> <jpath:value-of select="lastName"/></strong>! You've successfully registered as a new user.</p> <p>| <link href="../edit/">Edit my preferences</link> | <link href="../logout/">Logout</link> |</p> </s1> </body> </document> </xsp:page> 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/pages/userInfo.xsp Index: userInfo.xsp =================================================================== <?xml version="1.0"?> <!-- Author: Ovidiu Predescu "[EMAIL PROTECTED]" Page to show the user information. This page is used for both user registration and editing the user information, depending on the information passed down in the page. Date: August 30, 2002 --> <xsp:page language="java" xmlns:xsp="http://apache.org/xsp" xmlns:jpath="http://apache.org/xsp/jpath/1.0" > <document> <header> <title><jpath:value-of select="title"/></title> <authors> <person name="Ovidiu Predescu" email="[EMAIL PROTECTED]"/> </authors> </header> <body> <s1> <xsp:attribute name="title"><jpath:value-of select="title"/></xsp:attribute> <jpath:choose> <jpath:when test="errorMsg"> <p><strong><jpath:value-of select="errorMsg"/></strong></p> </jpath:when> <jpath:otherwise> <p>Please enter the following data</p> </jpath:otherwise> </jpath:choose> <form><xsp:attribute name="action"><xsp:expr>"../kont/" + <jpath:continuation/></xsp:expr></xsp:attribute> <p> <jpath:choose> <jpath:when test="check and firstName = ''"> <strong>First name cannot be empty</strong> </jpath:when> <jpath:otherwise> First name: </jpath:otherwise> </jpath:choose> <input type="text" name="firstName"> <xsp:attribute name="value"><jpath:value-of select="firstName"/></xsp:attribute> </input> </p> <p> <jpath:choose> <jpath:when test="check and lastName = ''"> <strong>Last name cannot be empty</strong> </jpath:when> <jpath:otherwise> Last name: </jpath:otherwise> </jpath:choose> <input type="text" name="lastName"> <xsp:attribute name="value"><jpath:value-of select="lastName"/></xsp:attribute> </input> </p> <p> <jpath:choose> <jpath:when test="check and email = ''"> <strong>Email address cannot be empty</strong> </jpath:when> <jpath:otherwise> Email address: </jpath:otherwise> </jpath:choose> <input type="text" name="email"> <xsp:attribute name="value"><jpath:value-of select="email"/></xsp:attribute> </input> </p> <p> <jpath:choose> <jpath:when test="check and login = ''"> <strong>Login name cannot be empty</strong> </jpath:when> <jpath:otherwise> Login name: </jpath:otherwise> </jpath:choose> <input type="text" name="login"> <xsp:attribute name="value"><jpath:value-of select="login"/></xsp:attribute> </input> </p> <p> <jpath:choose> <jpath:when test="check and password = ''"> <strong>Password cannot be empty</strong> </jpath:when> <jpath:otherwise> Password: </jpath:otherwise> </jpath:choose> <input type="password" name="password"> <xsp:attribute name="value"><jpath:value-of select="password"/></xsp:attribute> </input> </p> <input type="submit" name="submit"> <xsp:attribute name="value"><jpath:value-of select="button"/></xsp:attribute> </input> <jpath:if test="cancel"> <input type="submit" name="cancel" value="Cancel"/> </jpath:if> </form> </s1> </body> </document> </xsp:page> 1.1 xml-cocoon2/src/webapp/samples/flow/examples/prefs/pages/welcome.xsp Index: welcome.xsp =================================================================== <?xml version="1.0"?> <!-- Author: Ovidiu Predescu "[EMAIL PROTECTED]" Date: August 30, 2002 --> <xsp:page language="java" xmlns:xsp="http://apache.org/xsp" xmlns:jpath="http://apache.org/xsp/jpath/1.0" > <document> <header> <title>Welcome!</title> <authors> <person name="Ovidiu Predescu" email="[EMAIL PROTECTED]"/> </authors> </header> <body> <s1 title="Welcome back!"> <p>Welcome back, <strong><jpath:value-of select="firstName"/> <jpath:value-of select="lastName"/></strong>!</p> <p>| <link href="../edit/">Edit my preferences</link> | <link href="../logout/">Logout</link> |</p> </s1> </body> </document> </xsp:page>
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]