Novell is now a part of Micro Focus

Novell OnDemand Services: Architecture and Customization

Articles and Tips: article

Kelly Bradford
Sr. Software Engineer
Novell, Inc.
kbradford@novell.com

James Albright
Software Engineer
Novell, Inc.
jalbright@novell.com

M. Troy Martin
Development Manager
Novell Products Group
tmartin@novell.com

01 Jan 2001


This AppNote introduces Novell OnDemand Services, a solution based on NDS eDirectory that enables you to offer access to electronic goods and services directly over the Internet on a for-fee basis. More than a mere online catalog, OnDemand Services makes it possible to provide value-added services-such as application delivery, disk space leasing, digital certificates, and self-serve classified ads-directly to your customers' desktops.

Introduction

Novell OnDemand Services is a solution based on NDS eDirectory that enables you to offer access to electronic goods and services directly over the Internet on a for-fee basis. Any electronic content or service imaginable can be dispensed from a Web page using OnDemand Services. In essence, Novell OnDemand Services turns NDS eDirectory into a virtual vending machine.

OnDemand Services consists of three parts:

  • The DirCommerce engine provides interfaces to credit card authentication networks and billing services and controls the users access to electronic content.

  • The OnDemand Web application manages user authentication, provides a web environment for users to purchase access to electronic content, and provides a delivery mechanism once access to the electronic content has been obtained.

  • The Novetrix DeFrame solution provides a "thin client" solution for delivering Win32 applications to users.

This AppNote gives an overview of Novell's OnDemand Services architecture and explains how to customize it to meet your individual requirements.

OnDemand Services Architecture

OnDemand Services is implemented as a domain framework in the Novell Route 66 (Novell MVC Beans for eBusiness) architecture. Novell's Route 66 architecture comes from research done by IBM on Internet Web applications. The Route 66 architecture is an implementation of IBM's Java Web application model. This application model is a browser/web server implementation of the Model View Controller (MVC) design pattern.

Design Patterns

In the book "Design Patterns: Elements of Reusable Object-Oriented Software" (Erich Gamma et al, 1995, Addison-Wesley, ISBN 0201633612), design patterns are described as follows: "Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice."

Design patterns are a conglomeration of designs and research to solve problems that come up over and over again. These problems may be implemented using different programming languages, databases, operating systems, and so on, but the underlying problem is still the same.

MVC Design Pattern

The Model View Control (MVC) design pattern is one of those recurring problems. Before MVC, the application, the screen representation of the data, and the user input mechanisms were all lumped together into a single application architecture. MVC decouples these functions into distinct units of functionality that can be modified independently from the rest of the application.The three main pieces of the MVC architecture are:

  • Model. The components that expose the business logic for a particular application or service.

  • View. The representation of the application information to a user interface device.

  • Control. Defines the way the user interface reacts to user input.

A simplified example of the MVC pattern could be an application (Model) that reads information from a database, and then displays it to a user's screen (View). The view of the information could be a table, a bar graph, or a pie chart, depending on which view choice the user has selected (Controller).

Web Application Model

Through the research and development efforts of IBM, the MVC design pattern was applied to the Internet. Out of these efforts came the Web Application Model. IBM recommends using servlets to control the application, a series of command beans for the application business logic, and a series of JavaServer Pages (JSPs) which display the view of the application to the user's web browser (see Figure 1).

In the MVC Web Application Model, the user input, modeling of the external world, and visual feedback to the user are explicitly separated and handled by three types of objects, each specialized for its task.

Below is a summary of the Web Application Architecture, broken down by MVC component:

  • Model. The Web Application Model implements the MVC "Model" component by defining the concept of Command Beans. Command Beans are discrete components that encapsulate a single business logic function. Examples of Command Beans are AddUserToDatabase, ReadStock- Information, UpdatePassword, and so on.

  • View. The Web Application Model implements the MVC "View" component through the use of JavaServer Pages. JavaServer Pages are used to dynamically build an HTML page, which can format the data resulting from the execution of one or more Command Beans. JavaServer pages are essentially HTML pages with certain java scripting tags (not to be confused with JavaScript tags) which allows the page to display content dynamically.

  • Control. The Web Application Model implements the MVC "Control" component through the use of Java Servlets. Java Servlets represent the object that accepts an HTTP request from a browser. The Java Servlet is responsible for turning a standard request into a task, which may execute one or more commands and forwards the user to one of many possible JavaServer Pages.

A simple scenario could be as follows (see Figure 2): From a browser, a user clicks on a link on a Web page that will bring up the current value of a certain stock. The information from the click is sent as a browser request to the Interaction Controller, which in this case is implemented as a Java Servlet. The Java Servlet accesses the appropriate business logic components, implemented as command beans, which read information from external data sources, such as a database or directory.

After the information has been obtained and calculated, it is handed off to the UI logic, which in this case is the JavaServer Page, for formatting. The JavaServer Page could build a table with current stock information, and a graph that shows the stock information over the past few months.

In this scenario, having the Internet Web application decoupled using MVC, any component can be easily removed and replaced with a different implementation. For example, the command beans can be replaced with beans that read information from a database, a directory, a flat file, or some other data source. The JSP interface can be easily modified to give a different representation of the data, such as displaying a pie chart, a graph, and so on.

The process flow of a typical Java-based Web application.

Route 66 (MVC Beans for eBusiness)

Novell OnDemand Services architecture is based on Novell's implementation of IBM's Web Application Model. This implementation of IBM's Web Application Model is code-named 'Route 66,' or 'the highway of the Internet.' Novell's Route 66 architecture is one of the many components that make up the Novell DENIM (Directory Enabled Net Infrastructure Model) story. By implementing Novell's Route 66 architecture, OnDemand Services gains the benefits of greater flexibility and easier customization.

The Novell Route 66 architecture implements pieces of IBM's Web Application Architecture as follows:

Model

  • Command Beans

  • Data Beans

View

  • JavaServer Pages

  • Format Beans

Controller

  • TaskServlet

  • Tasks

Model Components: Command Beans

As stated earlier, Command Beans are Java Beans that not only encapsulate a single business logic task, but also provide a stable boundary between business logic and user interface. A Command Bean is created, initialized by having specific properties set, executed by calling the bean's 'perform' method, and the results are accessed through the bean's accessor methods. This programming model helps to isolate changes in the Web application by factoring the business logic into fine-grained components that are easily managed and less reliant on other components. This model also allows easier distribution of processing using serialization to send the bean over IIOP, HTTP, and other protocols to a remote server that executes the logic and returns with the results.

Novell's Route 66 architecture defines the Command interface, which provides the primary interface for building Command Beans. It consists of three methods: isReadyToCallPerform(), perform(), and reset(). A bean implementing the Command Bean interface can be in one of the following states during its lifecycle:

  • New. The Command Bean is in this state immediately after creation. In this state, the isReadyToCallPerform method will return FALSE and the "get" accessor methods should not be called.

  • Initialized. The Command Bean is in this state after all required input properties have been set. In this state, the isReadyToCallPerform method will return TRUE but the "get" accessor methods still should not be called.

  • Executed. The Command Bean is in this state after the perform method has been called. In this state, the isReadyToCallPerform method will return TRUE and the "get" accessor methods may be called.

A JSP/servlet executes the command bean in the following way:

  1. The JSP/servlet instantiates the Command Bean.

  2. All applicable input properties are set using the bean's 'set' accessor methods.

  3. The JSP/servlet calls the perform method of the Command Bean.

  4. The perform method sets the Command Bean's output properties, using the results from executing the underlying business logic.

  5. Control flows to the MVC View component, probably a JavaServer Page, which is now free to query, format, and display the output properties of the Command Bean.

Model Components: Data Beans

Data Beans, as the name implies, contain only information or data and do not contain any business logic. Data Beans are used in Novell's Route 66 architecture as a means to pass information from a Command Bean, to a Format Bean or a JavaServer Page (JSP). Data Beans are accessed through 'setter' and 'getter' accessor methods. An example of a Data Bean could be a Java Bean that represents a single row in a database table.

View Components: JavaServer Pages

As stated earlier, the view components of a Web application are responsible for generating the interface, or HTML pages, that will be returned to the client. When one or more Command Beans have been executed, data can be retrieved from them and formatted for viewing in an HTML page. Simple data formatting can be done using standard HTML tags. More complex data formatting is done using Format beans to take the data set and return formatted HTML.

View Components: Format Beans

Format Beans support JavaServer Pages and help format various types of dynamic or complex data. Complex data formatting is easily done using one or more Format Beans. It could be something as simple as converting data from a NDS path object to a Java string, or as complicated as receiving multiple data types to create a custom type of table or chart. An example of a Format Bean in OnDemand Services is the CommerceEmailNotifyFormat bean.This Format Bean extracts information from a CommercePurchase data bean and formats it into a purchase receipt which can be e-mailed to the user using the SendEmailJava command bean.

Controller Components: TaskServlet

The TaskServlet is the heart and soul of the framework. It controls when to execute which Command Beans for what purpose, as well as how the returning results will be formatted or displayed to the end user. The TaskServlet for OnDemand is DefaultOnDemandServlet. The important functions of this servlet are as follows:

  • Connects to a Directory as Admin-equivalent using an SAS Service object so it can perform certain task on behalf of the user

  • Receives all requests from the users

  • Manages user Directory authenticated identities

  • Verifies user authentication

  • Initializes the list of registered tasks it can perform

  • Executes tasks according to each user request

Controller Components: Tasks

As pointed out earlier, a task represents the handling of a single HTTP (browser) request from an end-user. The task obtains the needed information (parameters) for a command, at which time the task will instantiate a command, set the command's attributes, and execute the command. After executing one or more commands, the task will set the request attributes with information obtained from the commands, at which time it forwards the user to a Java Server Page (JSP). The code segment below (see Code 2) shows a task that will display a user's current valid purchases and display them on the user's browser.

A task is an inner class within the task servlet DefaultOnDemandServlet. OnDemand tasks typically extend OnDemandTask to inherit the functionality of a Task object. The task will generally set and execute one or more Command Beans, after which it will pass the results on to a JSP for presentation.

A task which requires the authentication of the user should implement AuthTask. This forces a user to be presented with authentication credentials if the user hasn't already been authenticated. A task can obtain the user's authenticated identity using the getAuthSessionObj method. The task passes the necessary information into a command, like ListCommercePackagesPurchased, and then calls the perform method. After the command has been executed, the task passes resulting information to a JSP for display. In the code below (see Code 3), the whole Command Bean is passed and the JSP will extract the needed information for display from the Command Bean's output accessor methods.

OnDemand Domain Framework

The purpose of a Domain Framework is to abstract functionality required by many Web applications into a common design, thereby expediting time to market and minimizing development resources. The purpose of the OnDemand Domain Framework is to provide a ready-made framework for customers to sell, lease, and distribute electronic content. The OnDemand Domain Framework includes billing, application provisioning, disk space rental, creation of digital certificates, electronic content distribution, and self-serve classified ads based on Novell Directory Services. A framework is just the beginning-it's not a complete application, and thus it allows the flexibility for including new innovations.

We will now discuss how to use the OnDemand Domain Framework to implement your own personal eCommerce web site. As stated before, the MVC model gives you greater flexibility to change and adapt to meet your requirements. With Command Beans, you can add to or change the business logic; Format Beans allow you to change the look and feel of your Web site; and it's all controlled through the TaskServlet.

OnDemand Services Customization

Here are some things that can be customized with OnDemand Services:

  • Registering a task

  • Writing a task

  • Writing a JavaServer Page

  • Writing a command

  • Writing a Data Bean

Registering a Task

Code segment 1 shows how to register your task in the DefaultTaskServlet. A task is an inner class, within the task servlet, which contains Command and Format Beans to fulfill the given request from the user. To register a task, use the addTask method. The first parameter is the name of the task. The second parameter is the new instantiated task. Once a task has been registered with the servlet, it can be accessed by using the task name on the request line. For example, https:\\myASP\OnDemand\listUserPurchases?parms

Code 1

-- Code Sample 1 ---
-- registering a task --

// ***********************************************
// This is where tasks are registered with servlet
// ***********************************************
public void initTasks() {
    addTask("default", new DefaultTask());
    addTask("signup", new SignupTask());
    addTask("signup-submit", new SignupSubmitTask());
    addTask("login-submit", new LoginSubmitTask());
    addTask("logout", new LogoutTask());
		
		// you can simply add your own task
    // Task are inner classes with in DefaultOnDemandServlet.java
    // Here we are adding a task to list user purchases.
    // The first parameter is the name of the task.
    // The second parameter is the new instatatiated task.
    // To access this task the request attribute from the browser
    // would be https:\\myASP\OnDemand\listUserPurchases?parms...
    addTask("listUsersPurchases", new ListUserPurchasesTask());
}

Writing a Task

As pointed out earlier, a task represents the handling of a single HTTP (browser) request from an end-user. The task obtains the needed information (parameters) for a command, at which time the task will instantiate a command, set the command's attributes, and execute the command. After executing one or more commands, the task will set the request attributes with information obtained from the commands. Then it will forward the user to a Java Server Page (JSP). Code segment 2 below shows a task that will display a user's current valid purchases and display them on the user's browser.

Code 2

-- Code Sample 2 ---
-- Example of creating/writing a task --

// Task class to list the active purchases that a user has access to.
public class ListUserPurchasesTask extends OnDemandTask implements AuthTask {
    public void exec(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException,IOException,CommerceCommandException
{
    // ***********************************************
    // Get Authenticated User Identity
    // ***********************************************
    CommerceIdentity ciUser = (CommerceIdentity)getAuthSessionObj(request);
    
    // New up command ListCommercePackagesPurchased
    // This command returns a list of active purchases a user has access to.
    // There are two constructors -this sets all the required attributes 
    // at once.
    // The other one uses setter methods
    ListCommercePackagesPurchased list = 
new ListCommercePackagesPurchased(ciUser, strTree, ciUser.getUserFullName());
    // execute the command
    list.perform();
        
    // Get Commerce Categories to display across the top
    getDefaultCommerceCategories(ciUser, request);
    
    // ***********************************************
    // Set attributes for JSP pages
    // ***********************************************
    request.setAttribute("users_purchases", list);
    request.setAttribute("username", ciUser.getUser());
    
    // Turn the control over to the JSP for displaying 
    // the results to the end user.
    callPage("user_purchases.jsp", request, response);
    }
}

Writing a JavaServer Page

Code segment 3 shows an example of writing a JavaServer Page.

Code 3

-- Code Sample 3 ---
-- Example of a JSP --
//---- user_purchases.jsp

<%@page errorPage="error.jsp"%>
<HTML>
<HEAD>
<TITLE>List User Purchases</TITLE>
</head>
<BODY BGCOLOR="#ffffff" LINK="#0000ff" VLINK="#800080" TEXT="#000000"
LEFTMARGIN=0 MARGINWIDTH="0" MARGINHEIGHT="0">
<%@include file="top.txt"%>
<!-- Service content belongs here -->
<font face=arial>

<%@page import="com.novell.web.command.beans.commerce.*"%>
<
 ListCommercePackagesPurchased list = 
(ListCommercePackagesPurchased)request.getAttribute("users_purchases");
 int nPurchaseCount = list.getCommercePackageCount(); 
%>

<h2>Account: <%=request.getAttribute("username")%></h2>

<%if(nPurchaseCount < 0){%>
    The following items are your current active purchases:<p>
    <table width=600 border=1 cellpadding=5 cellspacing=0>
    <tr>
    <th> font face=arial>Package Name</font></th>
    <th> font face=arial>Purchase Date</font></th>
    <th> font face=arial>Cost</font></th>
    </tr>
    
    <%<
            // Extract packages & make purchases &
            for(int i=0; i<nPurchaseCount; i++){ <
                CommerceUserPurchase upr = list.getCommerceUserPurchase(i);
                String strPackage    = upr.getPackageName();
    %>>
            <tr>
                <td align=left> font face=arial><%=strPackage%></font></td>
                <td align=center> font face=arial><%=strDate%></font></td>
                <td align=right> font face=arial><%=strCost%></font></td>
            </tr>
    <%}<
}else{%>>
    No purchases for the given date range.
<%}%>

</font>
<!-- Service content ends here -->
<%@include file="bottom.txt"%>
</BODY>
</HTML>

Writing a Command

As discussed previously, a command contains the business logic that needs to be performed. Each command performs one distinct unit of functionality. For example, to purchase an object may require multiple commands. The command could first gather credit card information and place the data into the credit card data bean. Next it could make the actual purchase, follow up by performing an external function such as a snap-in that executes some native code, and then send an e-mail notification of the purchase to the user. Code segment 4 shows an example of a sequence of commands.

Code 4

-- Code Sample 4 ---
-- Purchasing code from DefaultOnDemandServlet --

public class EnableSubmitTask extends OnDemandTask implements AuthTask {
     public void exec(HttpServletRequest request, HttpServletResponse response) 
     throws ServletException,IOException,CommerceCommandException {
// ***********************************************
     // Get Authenticated User Identity
     // ***********************************************
     CommerceIdentity ciUser = (CommerceIdentity)getAuthSessionObj(request);

     // ***********************************************
     // Get needed parameters
     // ***********************************************
     String strPackageDN = getParameter(request, "package", true, false, true,
null);
     String strPaymentType = getParameter(request, "Payment_type", true, false,
false, "");

     // ***********************************************
     // Begin PurchaseCommercePackage command
     // ***********************************************
     PurchaseCommercePackage purchaseCommercePackage = new
     PurchaseCommercePackage(ciServer, strTree, strPackageDN,
	 ciUser.getUserFullName(), nDecimalPlaces);

     // Defined outside of strPaymentType.equals("CC") so it can be rolled back
     // on snapin execution failure
     AuthNetCreditCard authNet = null;

     if (strPaymentType.equals("CC")) {
     ReadAuthNetService readAuthNet = new ReadAuthNetService(ciServer, 
strTree,strCmrcService);
     readAuthNet.perform();
     
        
     // ***********************************************
     // Get additional needed parameters for Credit Card
     // ***********************************************
     authNet = new AuthNetCreditCard(readAuthNet.getAccountID(), 
         readAuthNet.getAccountPassword(), readAuthNet.getAuthorizeNetURL(),
         getParameter(request, "CC_Name_First", true, false, true, null), 
         getParameter(request, "CC_Name_Last", true, false, true, null),
         getParameter(request, "CC_Address_Street", true, false, true, null),
         getParameter(request, "CC_Address_City", true, false, true, null),
         getParameter(request, "CC_Address_State", true, false, true, null),
         getParameter(request, "CC_Address_Zip", true, false, true, null),
         getParameter(request, "CC_Address_Country", true, false, true, null),
         getParameter(request, "CC_Email", true, false, true, null),
         getParameter(request, "CC_Phone", true, false, true, null),
         getParameter(request, "CC_Number", true, false, true, null),
         getParameter(request, "CC_Expiration_Month", true, false, true, null),
         getParameter(request, "CC_Expiration_Year", true, false, true, null),
         null, null, 0, null);  // These parameters are used by the
PurchaseCommercePackage command

     authNet.setProductionFlag(bProductionMode);
     purchaseCommercePackage.setCreditCardClass(authNet);
}

     /* Perform Purchase Command */
     purchaseCommercePackage.perform();

     String strSnapinString  =  purchaseCommercePackage.getSnapinString();

     if ("".equals(strSnapinString) == false) {
     try {
         // Execute the snapin
         new ExecuteCommerceSnapin(ciServer,ExecuteCommerceSnapin.SNAPIN_CREATE,
         purchaseCommercePackage.getSnapinString(), ciUser.getUserFullName()).
perform();
     }
     // This will rollback the purchase
     catch(CommerceCommandException e) {
         RollbackCommercePurchase rollback = new RollbackCommercePurchase
(ciServer, strTree,
             purchaseCommercePackage.getPurchaseDN());
         if (authNet != null) rollback.setCreditCardClass(authNet);
         rollback.perform();

         throw e; // Re-thow exception up the ranks
}
}

     try {
         // Send email confirmation
         new SendEmail(strEmailServer, strEmailFrom, purchaseCommercePackage.
getPurchaserEmail(), strEmailSubject, 
         (new CommerceEmailNotifyFormat()).format
(purchaseCommercePackage.getCommercePurchase())).perform();
     }
     catch (CommerceCommandException e) {
         // Don't do anything, the mail server may be down
     }

     // ***********************************************
     // Forward information to JSP page
     // ***********************************************
     callPage("enable_results.jsp", request, response);
     }
}

If the default tasks do not provide all the functionality that needs to be performed, they can be modified by adding or removing Command and Format Beans. For example, if you want to use a different credit card clearinghouse, you simply replace the AuthNetCreditCard bean with the new credit card bean. If you don't have any external functions that need to be performed, you could delete all code dealing with snap-ins. But, you would probably like to log all purchase activity by creating and using your own Command Bean. An example of such a Command Bean is listed in Code segment 5.

Code 5

-- Code Sample 5 ---
-- Activity log command bean  --

import java.util.*;
import java.text.*;
import java.io.*;
import com.novell.web.command.beans.commerce.*;

public class ActivityLogger implements Serializable, CommerceCommand
{
     // ============================================================
     // Instance variables
     // ============================================================

     private String message = null;
     private String fullMessage = null;

     // ============================================================
     // Constructors
     // ============================================================

     public ActivityLogger() {
     }

     // ----------------------------------------------
     // Command interface
     // ----------------------------------------------

     /**
     * called by a user of this command bean to test whether
     * the required input properties have been set and the bean is in
     * the "initialized" state.
     */
     public boolean isReadyToCallPerform() {
     if (message == null) {
         return(false);
     }
     return(true);
     }

     /**
     * executes this command bean and sets all output properties that
     * reflect the "executed" state of this bean.
     */
     public void perform() throws CommerceCommandException {
     if (isReadyToCallPerform() == false) {

         throw new CommerceCommandException("Invalid state: A log message has
		 not been provided");
     }

     DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT,
DateFormat.DEFAULT, Locale.getDefault());
     String timeStamp = formatter.format(new Date());

     fullMessage = timeStamp + message + '\n';            

     // Appending to log File
     try {
         BufferedWriter out = new BufferedWriter(new FileWriter(
		 "purchaseActivity.log", true)); 
         out.write(fullMessage);
         out.close();
     } catch (IOException e) {
     }
     }

     /**
     * resets the output properties to the values they had prior to
     * the perform method being called 
     */

     public void reset()
     {
     fullMessage = null;
     }

     // ----------------------------------------------
     // End of Command interface
     // ----------------------------------------------

     // ============================================================
     // setters & getters
     // ============================================================

     /**
     * sets the message to be used by the bean
     */
     public void setLogMessage(String newValue) {
     message = newValue;
     }

     /**
     * returns the full message for the bean.
     */
     public String getCompletedLogMessage() {
     return fullMessage;
     }
}

In addition, perhaps you would like to send your e-mail confirmation with a command based on javaMail. Code segment 6 shows these changes to the purchasing task.

Code 6

-- Code Sample 6 ---
-- Modified purchasing code from DefaultOnDemandServlet --

public void exec(HttpServletRequest request, HttpServletResponse response) 
     throws ServletException,IOException,CommerceCommandException {
     // ***********************************************
     // Get Authenticated User Identity
     // ***********************************************
     CommerceIdentity ciUser = (CommerceIdentity)getAuthSessionObj(request);

     // ***********************************************
     // Get needed parameters
     // ***********************************************
     String strPackageDN   = getParameter(request, "package", true, false,
	 true, null);
     String strPaymentType = getParameter(request, "Payment_type", true,
	 false, false, "");

     // ***********************************************
     // Begin PurchaseCommercePackage command
     // ***********************************************
     PurchaseCommercePackage purchaseCommercePackage = new
     PurchaseCommercePackage(ciServer, strTree, strPackageDN,
	 ciUser.getUserFullName(), nDecimalPlaces);

     // Defined outside of strPaymentType.equals("CC") so it can be rolled back
     // on snapin execution failure
     MyCreditCard myCC = null;

     if (strPaymentType.equals("CC")) {
     ReadMyCCService readMyCC = new ReadMyCCService(ciServer, strTree,
	 strCmrcService);
     readMyCC.perform();
     
         
     // ***********************************************
     // Get additional needed parameters for Credit Card
     // ***********************************************
     myCC = new MyCreditCard(readMyCC.getAccountID(), 
         readMyCC.getAccountPassword(), readMyCC.getAuthorizeNetURL(),
         getParameter(request, "CC_Name_First", true, false, true, null), 
         getParameter(request, "CC_Name_Last", true, false, true, null),
         getParameter(request, "CC_Address_Street", true, false, true, null),
         getParameter(request, "CC_Address_City", true, false, true, null),
         getParameter(request, "CC_Address_State", true, false, true, null),
         getParameter(request, "CC_Address_Zip", true, false, true, null),
         getParameter(request, "CC_Address_Country", true, false, true, null),
         getParameter(request, "CC_Email", true, false, true, null),
         getParameter(request, "CC_Phone", true, false, true, null),
         getParameter(request, "CC_Number", true, false, true, null),
         getParameter(request, "CC_Expiration_Month", true, false, true, null),
         getParameter(request, "CC_Expiration_Year", true, false, true, null),

         null, null, 0, null);  // These parameters are used by the
         PurchaseCommercePackage command

     myCC.setProductionFlag(bProductionMode);
     purchaseCommercePackage.setCreditCardClass(myCC);
     }

     /* Perform Purchase Command */
     purchaseCommercePackage.perform();

     /* Perform activity logging */
     ActivityLogger  actLog = new ActivityLogger ();
     actLog.setLogMessage("Package "+strPackageDN + " was purchased by "+
ciUser.getUserFullName());
     actLog.perform();

     try {
     // Send email confirmation
     new SendJavaEmail(strEmailServer, strEmailFrom,
purchaseCommercePackage.getPurchaserEmail(), strEmailSubject, 
     (new
CommerceEmailNotifyFormat()).format(purchaseCommercePackage.
getCommercePurchase())).perform();
     }
     catch (CommerceCommandException e) {
     // Don't do anything, the mail server may be down
     }

     // ***********************************************
     // Forward information to JSP page
     // ***********************************************
     callPage("enable_results.jsp", request, response);
  }
}

Writing a Data Bean

As the name implies, a Data Bean contains information or data only and does not contain any business logic. Generally a data bean is used to pass information from a Command Bean into a Format Bean or to JavaServer Pages (JSP). Data Beans are accessed through setter and getter methods (see Code 7).

Code 7

-- Code Example 7 --

public class HelloData
{
     private String someData = null;

     public void setData(String newValue) {
     someData = newValue;
     }
     
     public String getData() {
     return someData;
     }
}

As you can see, the MVC architecture with Command Beans gives you, the developer, a lot of freedom to engineer your own design and to add those items or processes that will make your OnDemand site unique.

Novell OnDemand Tasks and Commands

The following tables list the current Novell OnDemand tasks, the DirCommerce Engine commands, and the Novetrix-related commands.


Task
Function

AddCategoryTask

Allows a user to add a Directory Classified Category (NDS Organizational Unit) such as Clothing, Electronics, etc.

AddItemTask

Allows a user to add a Directory Classified Item (NDS Package Object) that represents a physical item for sale.

DefaultTask

Sends the browser to the initial OnDemand web page.

EnableCCResizeTask

Resizes the pop-up Activate window so there is more room for the credit card input fields.

EnableCCTask

Shows the credit card fields in the Activate window.

EnableSubmitTask

Takes purchase information and does the following: generates a purchase object in NDS, sends an e-mail confirmation to the user, executes the snap-in (if applicable), and charges the user credit card (if applicable).

EnableTask

Brings up the pop-up Activate window and displays the name of the package about to be purchased, and lists available purchase options.

ServicesTask

Lists available packages according to the selected category.

SignupSubmitTask

Takes initial sign-up information and creates a new user in NDS.

DirCommerce Engine Commands


Command
Function

AddUserToGroup

Adds a user to a group within the eDirectory tree.

BasicFormat

Interface for all view format beans.

CheckAvailableUserName

Checks to see if a user name at a given context in the eDirectory tree exist.

CommerceCommand

Interface for all commerce commands.

CommerceCommandException

Base class for all command exceptions.

CommerceConstants

Constant literals used to reference commerce directory attributes.

CommerceCreditCard

Interface provides for the most generic form of credit card processing. This interface is provided for credit card implementation with the directory commerce engine.

CommerceCreditCardException

Base class for commerce credit card exceptions.

CommerceIdentity

Performs verification of login and login tasks. State information is kept after each successful verification or login so that the tree and/or user name may be retrieved if this information is needed.

CommerceUtils

Common commerce utility methods.

CreateNDSObject

Creates a NDS object in the eDirectory tree.

CreateCommerceCategory

Creates a commerce category object at a given context in the eDirectory tree.

CreateCommercePackage

Creates a commerce package object at a given context in the eDirectory tree.

CreateCommerceUser

Creates a commerce user object at a given context in the eDirectory tree.

DeleteNDSObject

Deletes a specific NDS object from the eDirectory tree.

CommerceEmailNotifyFormat

Formats the commerce purchase command's e-mail notification message with input from a CommercePurchase data class.

ExecuteCommerceSnapin

Executes a commerce snap-in operation associated with a commerce package object. A 3rd party snap-in writer must implement the commerce snap-in methods.

GetEntryEffectiveRights

Retrieves the effective rights for an entry (file or directory) in the NetWare File System for the logged in user or for another user that the logged in user has rights to see.

CommerceHttpFormat

Interface for view format beans that determine the locale to use for formatting.

ListNDSObjects

List NDS objects from a specified container in an eDirectory tree.

ListCommercePackageItems

List all commerce items from a given package in the eDirectory tree.

ListCommercePackagesPurchased

List all the currently available commerce purchases a specified user has purchased.

ListCommerceCategories

List all the commerce categories at a given context in the eDirectory tree.

ListCommercePackages

List all the commerce packages at a given context in the eDirectory tree.

ListUserCommerceItems

List all the currently available commerce items a specified user has purchased. This list contains all the items from all the purchased packages.

ModifyNDSObject

Modifies a specific NDS object in the eDirectory tree.

PurchaseCommercePackage

Purchases a specified commerce package for a specific user.

ReadNDSObject

Reads a specific NDS object from an eDirectory tree.

ReadCommerceCategory

Reads a specific commerce category object from an eDirectory tree and places the data in a CommerceCategory data class.

ReadCommercePackage

Reads a specific commerce package object from an eDirectory tree and places the data in a CommercePackage data class.

ReadCommercePurchase

Reads a specific commerce purchase object from an eDirectory tree and places the data in a CommercePurchase data class.

RollbackOnDemandPurchase

Reverses a specific purchase of a commerce package.

SendEmail

Sends out an e-mail message based on Sun Micosystem's SmtpClient class libraries.

SendJavaMail

Sends out an e-mail message based on javaMail 1.1.3.

CommerceCategory

Data bean that aggregates properties of the dirCommerce Category objects in an eDirectory tree.

CommerceItem

Data bean that aggregates properties of the dirCommerce Item objects in an eDirectory tree.

CommercePackage

Data bean that aggregates properties of the dirCommerce Package objects in an eDirectory tree.

CommercePurchase

Data bean that aggregates properties of the dirCommerce Purchase objects in an eDirectory tree.

CommerceSnapin

Interface for Commerce snap-ins. Commerce snap-ins are the bridge between the commerce engine and native methods that are needed to implement OnDemand functionality. (i.e. The selling of certificates or the leasing of disk space). A snap-in writer must implement snap-in methods.

StartCommerceUsage

Starts a commerce usage process for a given purchase in the directory by creating a usage object in the eDirectory tree.

StopOnDemandUsage

Stops a commerce usage process for a given purchase in the directory by closing a usage object in the eDirectory tree.

ListUserPurchases

Lists purchases made by the user during the specified date range.

CommerceUserPurchase

Data bean that aggregates properties of the user and purchase objects used for listing user purchases.

ChangeNDSUserPassword

Modifies a specified NDS user's password in the eDirectory tree.

Conclusion

The OnDemand Domain Framework provides the mechanism for representing items for sale or lease, making purchases, and the means for paying for those purchases using Novell's eDirectory. It also provides the means for the provisioning of applications, distribution of electronic content, disk space leasing, and certificate manufacturing. But this is not the limit-with the flexibility of MVC design and your ingenuity, it can be a lot more. The framework allows you to let your own personal taste shine through with your own look and feel. You can use the commands provided for you by OnDemand, or add your own commands and business logic. You can customize your layout by using or modifying the Format Beans. The Net is yours to conquer, and Novell wants to help.

For more information on MVC programming, see the following articles:

"How to Develop Web Applications for WebSphere using MVC Beans," Novell AppNotes, August 2000

NDK documentation for Novell's MVC Beans for eBusiness at http://developer.novell.com/ndk/mvc.htm

"Writing a Web Application for WebSphere Application Server," NetWare Connection, September 2000 (http://www.nwconnection.com/2000_09/web/)

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates