|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV |
TOP THREE LINKS YOU MUST CLICK ON Cover Story: Personalize Your Web Applications
Reusable components can eliminate personalization code from your applications
By: Daniel Vlad
Dec. 9, 2004 12:00 AM
Personalization, a recurring requirement in most corporate Web applications, can be a very effective tool for streamlining Web applications and enhancing the Web user's experience. In many cases, personalization and security requirements go hand in hand; they can be dictated by corporate security principles and regulations that exist in banks, insurance companies, and any other organizations. This article targets enterprise architects and developers who are willing to invest a little time to develop a set of easy-to-use, reusable personalization components that are powerful enough to meet the needs of many enterprise applications. The personalization components that we describe here are based on rules declared and configured in an XML file. Personalizing Web applications with these components requires writing little or no Java code. Web pages are personalized using JSP custom tags, shifting the complex task of application personalization from the J2EE developers to Web page designers. Two Typical Examples Billing information is typically classified as sensitive information. In our example we require that only a subset of employees, account specialists and account managers, should be permitted to view the banking information. However, for operational reasons, all employees need to have access to nonsensitive account data, such as customer name and address. In addition, we require that account maintenance functions, such as terminating or editing accounts, should be available to account managers only. This example is typical for many applications that provide role-based Web access to corporate data. 2. Personalized Shopping Site How would you develop these examples? Coding the personalization rules directly into the applications should not be an insurmountable problem for an experienced developer. However, in an agile enterprise rules change, sometimes very quickly. In the shopping site example we want to have the flexibility to change the promotion rules quickly, lowering the $1,000 limit to $500, for example. If this rule is hard-coded in your application, and especially if it's used several times in various parts of the application, you'll probably need to make substantial code changes, test the application for consistency, repackage it, and redeploy it on your application server. A framework based on components that centralizes the management of personalization rules and decouples these rules from the rest of the application suddenly sounds like a good idea. Designing the Personalization Components The central abstraction in our design is a personalization rule. We define a personalization rule as an object that can be evaluated as true or false; the outcome of the evaluation depends on user-related data and on the rule's configuration parameters. To allow for maximum flexibility and to avoid the hard-coding of the rule parameters in the application, the rules need to be configured externally. To simplify JSP development, we want to be able to evaluate personalization rules on Web pages using tags from a JSP custom tag library. At runtime the appearance of the page will depend upon the outcome of the evaluations. Personalization Rules In addition to the isRuleSatisfied() method, the PersonalizationRule interface also contains setters/getters for the rule name and rule properties.
public interface PersonalizationRule {
public String getRuleName();
public void setRuleName(String ruleName);
public String getProperty(String name);
public void setProperty(String name, String value);
public boolean isRuleSatisfied(HttpServletRequest req);
}
Implementations of this interface provide concrete behavior. Representing a rule by an interface gives us a great deal of flexibility in implementing personalization rules that match the requirements of the application. XML Configuration File
<personalization-rules>
<rule name=" ... " classname=" ... ">
<property>
<name> ... </name>
<value> ... </value>
</property>
... other properties ...
</rule>
... other rules ...
</personalization-rules>
For each personalization rule the XML document defines a rule name, and an implementation class name followed by a number of configuration properties in a name/value format. Example: Personalization Based on Security Roles To configure the rule we define a property named "roles"; the value of the property is a comma-separated list of security roles.
<rule name="rule1" classname="RolePersonalizationRule">
<property>
<name>roles</name>
<value>role1,role2,role3</value>
</property>
...
</rule>
To code the class we need to implement the methods specified in the PersonalizationRule interface. In the isRuleSatisfied method we parse the comma-separated list of roles using java.util.StringTokenizer, and check each individual role using the isUserInRole() method of the HttpServletRequest. If a match is found, we return true. If the user doesn't belong to any of the roles, we return false.
// Parse comma-separated list of roles
String roleToCheck= null;
StringTokenizer st=
new StringTokenizer(rolesStr, ",");
while (st.hasMoreTokens()) {
roleToCheck= st.nextToken().trim();
// Check each individual role
if (req.isUserInRole(roleToCheck))
return true;
}
return false;
To complete the class we also need to implement the getters and setters for the rule name and properties. The properties can be stored in a Map instance. Helpful design advice: You can place the implementation of the getter and setter methods into an abstract class and have all your rule classes inherit these methods, so you don't have to code them more than once. Parsing the Personalization XML File Developers have a multitude of choices when it comes to parsing XML files. SAX and DOM are powerful and flexible APIs; however, they require a fair amount of coding. Programmers often utilize higher-level APIs to simplify their XML parsing code. To parse the personalization XML file we use the Jakarta Digester, a popular open source utility, very powerful in parsing XML and populating Java objects from XML documents. Factory for Rules
private synchronized void initializeRules()
throws PersonalizationException {
if (rules == null) {
parser= new PersonalizationRuleParser();
rules= parser.parse(fileName);
}
}
The factory exposes a public method for retrieving a rule by name, getRule(String ruleName). If no rule object is found or if the object found does not implement the PersonalizationRule interface, the method throws an exception. Personalization Custom JSP Tags Custom JSP Tags to Display User Attributes To display the username we need to develop a UserTag that extends javax.servlet.jsp.tagext.TagSupport and provides an implementation for the doStartTag() method (see Listing 4). The method will invoke the getRemoteUser() method of the HttpServletRequest object and it will write out the result using the JspWriter (see Listing 5). The UserTag can be easily adapted to display other user attributes besides the username. We can use the username to look up the user data and print it out on the JspWriter using the same technique as in the code fragment in Listing 5. We can either create new tags for each user attribute or, even better, reuse the UserTag by enhancing it with an attribute to specify which user data to display. Helpful design advice: To improve application performance and reduce the number of database or LDAP calls, you can retrieve the user-related data once and store it in a "User" object that can be placed in the user's Http session. Each rule has access to the request object and implicitly to the session, therefore it can retrieve the user object, get the user data, and use it in the evaluation of the rule. Custom JSP Tags to Include or Exclude Web Content Both tags define a required attribute "rule" to specify the name of the rule to be evaluated. The doStartTag() method of the IncludeTag contains code to include the body of the tag when the specified rule evaluates as true and to skip the body when the rule evaluates as false.
public int doStartTag() throws JspException {
if (isRuleSatisfied()) {
return (EVAL_BODY_INCLUDE);
} else {
return (SKIP_BODY);
}
}
The ExcludeTag is coded in a similar manner; the only difference is the reversing of the return values in the if/else statement. Configuring and Using the Personalization Custom Tag Library <%@ taglib uri="/WEB-INF/personalization.tld" prefix="personalize" %> Using the tags is straightforward. To print the username: <personalize:user/> To include JSP content (excluding is similar):
<personalize:include rule="MyRule">
... Web content to be included here ...
</personalize:include>
Using Personalization Rules Programmatically UML Class Diagram Implementing the Personalized Account Maintenance Example Personalizing the Application
All personalization rules in this example are based on security roles. We need to configure the container-managed security environment for the Web application. In the web.xml deployment descriptors we have to define the following security-related information:
Running the Application Implementing the Personalized Shopping Site Example
<personalization-rules>
<rule name="displayCoupon"
classname=" HighValueCustomerRule ">
<property>
<name>minOrders</name>
<value>1000.00</value>
</property>
<property>
<name>period</name>
<value>365</value>
</property>
</rule>
</personalization-rules>
In the isRuleSatisfied method of the HighValueCustomerRule we get the userId (HttpServletRequest.getRemoteUser()) and use it to retrieve the total purchase amount for the specified period from the order database (the amount can also be retrieved by the controller in advance and cached in the user object). In the isRuleSatisfied we return true if the total is larger than the minOrder, and false if it isn't. In the JSP we need to add the following: <personalize:include rule="displayCoupon"> <img src="coupon.jpg"> </personalize:include> The rules are now easy to maintain. If we decide to lower the minimum purchase amount to $500 instead of $1,000, all we need to do is update the value in the personalization.xml file. Even radical changes that require replacing the entire HighValueCustomerRule with a different rule can be easily implemented when working within this framework. If the same rules are used multiple times in an application, centralizing the configuration also ensures the consistency of the application logic. Summary For most corporate Web applications, with the notable exception of portals, CRM, and other similarly complex applications, you might be better off building your own reusable personalization components or framework. The components shown here could provide a solid foundation for your personalization projects. Give them a try. References YOUR FEEDBACK
LATEST JAVA STORIES & POSTS
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK SPONSORED BY INFRAGISTICS
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||