设为首页】 【加入收藏】 【网站地图】 【商品折扣
娱乐一生 娱乐明星
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
首页  |  java  |  .NET  |  C/C++  |  网页技术  |  php  |  asp  |  delphi  |  VC  |  VB开发  |  游戏开发  |  软件工程  |  Power Builder  |  Linux开发  |  Windows开发技巧
当前位置:首页 >> JAVA与XML >> Cover Story: Personalize Your Web Applications @ JDJ

Cover Story: Personalize Your Web Applications @ JDJ -

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
1.  Personalized Customer Account Maintenance Application
Suppose we're developing a Web application for viewing and maintaining customer account information. The account is defined by an account ID; customer information such as name, address, and phone number; and billing information such as a bank account.

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
Here we want to develop a personalized shopping site that recognizes high-value customers and rewards them for their loyalty. At checkout we want to display a coupon for 10% off the next order to customers who purchased $1,000 worth of merchandise over the past 365 days (one year).

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
When it comes to personalization, different applications can have different requirements. In general, any user-related data can be used to personalize an application. It's important to recognize this early in our design so we can construct components that are as general as possible.

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
We represent a rule by an interface, PersonalizationRule. At a minimum the interface needs to provide a public method, boolean isRuleSatisfied(), which returns true if the user's data satisfy the rule, and false otherwise. To enable the rule to make a personalization decision, we need to supply it with user data, or at least with a mechanism for retrieving this data from an external database or directory. The HttpServletRequest provides us with the means for identifying users; we can either invoke its getRemoteUser() method (and rely on container-managed security) or we can retrieve the user authentication information stored in the request by third-party authorization systems. The user ID can then be used to look up or retrieve any user-related data from a database, LDAP, etc.

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
An XML configuration file with the following structure is perfect for configuring personalization rules:

<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
As an example that will be used in the implementation of the Account Maintenance example, we can develop a RolePersonalizationRule class (see Listing 1) that is evaluated as true only if the user belongs to a supplied list of 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
The parsing of the configuration file is performed by a utility, PersonalizationRuleParser (see Listing 2). The parse (String filename) method of this class is responsible for parsing the personalization XML file, and instantiating and configuring the rule objects.

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
We need to create a factory to manage the rules (see Listing 3). The factory invokes a method, initializeRules(), that invokes the PersonalizationRuleParser utility to parse the rules. The rules returned by the parser are cached in a static Map variable, rules. The initialization method is synchronized for thread-safety, thus guaranteeing that the parsing occurs only once.

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
The classes created up to this point can already be used to make personalization decisions programmatically. However, to simplify the development of personalized JSP pages we need to create a number of custom tags.

Custom JSP Tags to Display User Attributes
A first class of tags that we can create contains tags that display user information, such as username, name, department, and address.

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
The second category of tags that can be defined consists of tags for including (IncludeTag, see Listing 6) or excluding (ExcludeTag) Web content based on the outcome of the evaluation of the rules.

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
To use the custom tags we need to register them in a tag library descriptor (tld) file and declare the library in the JSP:

<%@ 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
Personalization rules can also be used programmatically, outside of the JSP pages. This comes in handy when we need to make personalization decisions in a servlet controller, for example, to redirect different groups of users to different Web pages. To evaluate a personalization rule programmatically, we just need to retrieve the rule from the factory and call the rule's isRuleSatisfied method.

UML Class Diagram
To summarize, Figure 1 shows a UML class diagram for the personalization components we have just created.

Implementing the Personalized Account Maintenance Example
It's time now to implement the examples described earlier in the article with our personalization components; we will start with the personalized account maintenance application. To implement the application, in the data access layer we retrieve the account information from a database and populate an Account transfer object (JavaBean). The bean is returned to the servlet controller (or Action, if you are using Struts), which binds the Account bean to the HttpRequest before forwarding the request to the JSP. The JSP retrieves the bean and displays its attributes on the page.

Personalizing the Application
The JSP needs to display the following Web content:

  1. General account information that can be viewed by all authenticated users.
  2. Bank account information that can be viewed only by account specialists and account managers. In the personalization XML file we define a personalization rule "ViewBankRule" of the RolePersonalizationRule type (we need to specify the fully qualified name of the implementation class):

    <rule name="ViewBankRule" 
      classname="com.pers.RolePersonalizationRule">
      <property>
        <name>roles</name>
        <value>Account Manager,Account Specialist</value>
      </property>
    </rule>
    

    In the JSP we need to pass the rule to the personalize:include tag for evaluation:

    <personalize:include rule="ViewBankRule">
        bank information here
    </personalize:include>
    

  3. Account maintenance functions that should be displayed to account managers only. Similarly, we define a rule "EditAccountRule"; we configure the "roles" properties with the value "Account Manager"; and we surround the Web content with the personalize:include tag:

    <personalize:include rule="EditAccountRule">
        account maintenance functions here
    </personalize:include>
    

  4. Finally, to display a personalized greeting in the JSP page, we use the user tag:

    Welcome <personalize:user />
    
Container-Managed Security Configuration
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:

  1. Security roles needed by the application: employee, account specialist, and account manager.
  2. Security constraints to exclude nonemployees from accessing the application and prohibit nonmanagers from accessing the URIs associated with the account maintenance actions.
  3. Login configuration for the Web application, for example, basic authentication.
The last piece of the security configuration puzzle is to configure the Web container (Tomcat in our case) to use a "database" of usernames/passwords (security realm) for user authentication. To keep it simple, we use MemoryRealm, an in-memory representation of a database of usernames/passwords provided by Tomcat for development and test purposes. At runtime, Tomcat loads the usernames and passwords from the MemoryRealm XML configuration file (tomcat-users.xml) in memory, and uses this data to authenticate users.

Running the Application
After logging into the application and passing the security constraints enforced by the Web container, the user views a personalized application (see Figures 2-4).

Implementing the Personalized Shopping Site Example
To be able to selectively display the 10% discount coupon, we can define a rule named displayCoupon and implement it using a personalization rule class HighValueCustomerRule. The minimum purchase amount needed for the promotion to kick in and the time period in days are entered as configuration parameters in the XML file:

<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="http://www.chinaitpower.com/A200508/2005-08-10/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
Personalizing Web applications in a consistent manner can be challenging. Vendor personalization engines can be very powerful; however, they can also be extremely expensive and difficult to work with.

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

  • Apache Jakarta Digester: http://jakarta.apache.org/commons/digester/
  • Container-managed security, see the Servlet 2.3 specifications: www.jcp.org/aboutJava/communityprocess/final/jsr053/
  • Tomcat: http://jakarta.apache.org/tomcat/index.html
  • Tomcat 4.1 MemoryRealm configuration: http://jakarta.apache.org/tomcat/tomcat-4.1-doc/realm-howto.html#MemoryRealm


  •  

    娱乐图摘

    更多 >>

    靓丽清纯美女meimei

    美女私房全裸照
    导演劝女演员脱衣服(视频)

    大胆火辣人体艺术写真(图)

    黑丝妹妹热辣诱惑-丝袜美女妹妹

    PLMM 漂亮妹妹图集-妹妹图库

    全球美女图库-美女集中营

    52MM 我爱漂亮妹妹-制服妹妹诱惑

    图王图库-世界美女明星图片资料库
    美女写真集锦

    激情两性-解密性生活
    浴室MM湿身内衣诱惑
    邻家小妹洗澡被偷拍(视频)

    热点文章

    更多

    · Eclipse Plugins Exposed, Part
    · Enterprise Web Services Securi
    · Portlets and Portals Design Ov
    · 实现电子商务的可伸缩性和高可用性--BEA WebLogic
    · Getting the Most from the MX C
    · XML DTD for EJB Deployment Des
    · A Dozen Ways to Get the Testi
    · XQuery Not Necessarily the Dea
    · AXIS学习笔记(一)
    · Java程序文件格式设计

    热点文章

    更多