Previous     Contents     Index     DocHome     Next     
iPlanet Application Server 6.0 Programmer's Guide (C++)



Chapter 4   Writing Server-Side Application Code


This chapter describes AppLogic objects, which are a set of programming instructions that accomplish a well-defined, modular task within an application.

The following topics are included in this chapter:



What Is An AppLogic Object?

AppLogic objects run on the iPlanet Application Server and are managed and hosted by it. Typically, an application includes several to many AppLogics, which can be deployed across many servers. These AppLogics provide some or all of the procedural, or logic, portion of the application.

Each AppLogic object is derived, directly or indirectly, from the GXAppLogic class in the iPlanet Application Server Foundation Class Library. AppLogic source files are stored in files with the .cpp extension.

AppLogics perform the tasks in the server side of the application. For example, some of the AppLogic objects in the Online Bank sample application perform the following tasks:

  • Display a menu page.

  • Retrieve and display the current balance in a customer's account.

  • Retrieve and display transactions.

  • Transfer funds from one account to another.

When writing AppLogic objects, you can use the classes and interfaces provided in the iPlanet Application Server Foundation Class Library. This class library provides the specialized functionality you need to write AppLogic objects for iPlanet Application Server applications.



Introduction to Writing AppLogic Objects



To write an AppLogic object,use one of the following techniques:

  • Use the iPlanet Application Builder to create an AppLogic visually. This tool provides a framework that gives you a head start on the most commonly-used types of AppLogic.

    For more information, see iPlanet Application Builder User's Guide.

  • If you are not using the AppLogic Designer, you can use your favorite code editor to write the AppLogic, using and call the iPlanet Application Server Foundation Class Library when necessary. You can also use a code editor to modify an AppLogic that was produced by a development tool or imported into your project. The rest of this chapter describes how to write AppLogic objects without using the AppLogic Designer.


Parts of a Typical AppLogic Object

The following skeleton code shows the syntax of a typical AppLogic object.

First, the AppLogic can use one or more #include statements to gain access to code in other files.

#include <file.h>

After the #include statements, the body of the AppLogic begins with a subclass declaration. All AppLogics are derived, directly or indirectly, from the GXAppLogic class.

class NewAppLogicName : public GXAppLogic {

The main task of the AppLogic is specified in code that overrides the Execute( ) method, which is inherited from the GXAppLogic superclass.

   STDMETHODIMP

   NewAppLogicName::Execute() {

The code within the Execute( ) method can perform any desired task. In this skeleton example, it is not possible to show all the typical tasks.

   // AppLogic code

   // . . .

The final task of a typical AppLogic is to send a response back to the calling entity. The result can be any type of data, and it can be sent to any calling entity, including another AppLogic. There are several alternative techniques available, such as using the EvalTemplate( ) or EvalOutput( ) method to stream data back to the client. In the following code, methodCall is a placeholder for a method call, where result is a success code that indicates to the iPlanet Application Server system if the request was processed correctly. You use ValOut or streaming or EvalTemplate( )/EvalOutput( ) to return application specific results.

      result = MethodCall(params);

      return result;

   }

}

For more information, see Returning Results From an AppLogic Object.


Example
The following example code shows a simplified version of the OBShowMenuPage AppLogic in the Online Bank sample application. This AppLogic displays a main menu in an HTML page.

The following code is in the header file:

// Declare an indirect subclass of AppLogic: OBShowMenuPage

// uses OBBaseAppLogic, which is derived from AppLogic

class OBShowMenuPage : public OBBaseAppLogic

{

   // ...

};

The following code is in the source file:

// Include header files

#include <stdio.h>

#include <gxplat.h>

#include <gxutil.h>

#include <gxagent.h>

#include <gxdlm.h>

#include "ShowMenuPage.h"

#include "gxval.h"

#include "common.h"

// ...

// ...

// Override Execute() method

STDMETHODIMP

OBShowMenuPage::Execute()

{

   HRESULT hr=GXE_SUCCESS;

   if(!IsSessionValid())

      return HandleOBSessionError();

   OBSession *pSession=NULL;

   if(((hr=GetOBSession(&pSession))==GXE_SUCCESS)&&pSession)    {

      ULONG userType=pSession->GetUserType();

      if(userType==OB_USERTYPE_CUSTOMER)

// Return results for user type customer

         EvalTemplate("GXApp/COnlineBank/templates/

            CustomerMenu.html", (IGXHierQuery*)NULL, NULL,

            NULL, NULL);

      else if(userType==OB_USERTYPE_REP)

// Return results for user type representative of bank

         EvalTemplate("GXApp/COnlineBank/templates/

            RepMenu.html", (IGXHierQuery*)NULL, NULL, NULL,

            NULL);

      pSession->Release();

   }

   else

      Result("<HTML>Call to getOBSession() failed

         in Login</HTML>");

   return GXE_SUCCESS;

}



Steps for Writing AppLogic Objects



This section provides an overview of the process of writing an AppLogic object. It assumes that you are familiar with using the code editor on your development platform.

To write AppLogic using the iPlanet Application Builder, follow the general steps defined in the rest of this section. It uses examples from the OBLogin AppLogic in the Online Bank sample application, which is described in greater detail in What Is An AppLogic Object?What Is An AppLogic Object? of Chapter 4 "Writing Server-Side Application Code."


Header File

These instructions use examples from the header file OBLogin.h.

  1. In the header file, include the other necessary header files:

       #include <stdio.h>         // standard I/O routines

       #include <gxapplogic.h>    // KIVA AppLogic base class

       #include "BaseAppLogic.h"  // AppLogic base class for this

                                  // application

  2. Declare the GUID variable for the AppLogic (a unique GUID is associated with each AppLogic):

       extern GUID OBLoginGUID;

  3. Subclass from the application's AppLogic base class, which is derived from GXAppLogic:

       class OBLogin : public OBBaseAppLogic

    {

  4. Define the constructor and destructor methods, then declare the Execute( ) method using the STDMETHOD macro:

       public:

          OBLogin();

          virtual ~OBLogin();

          STDMETHOD(Execute) ();

    };

  5. Associate the AppLogic with its GUID variable using the GXDLM_DECLARE macro:

       GXDLM_DECLARE( OBLogin, OBLoginGUID);


Source File

These instructions use examples from the source file OBLogin.cpp.

  1. In the source file, include the necessary header file(s):

       #include "OBLogin.h"

       #include "gxval.h"

       #include "common.h"

  2. Create a GUID for the AppLogic using the kguidgen utility, as described in Getting Ready to Run an ApplicationGetting Ready to Run an Application of Chapter 11 "Running and Debugging Applications

  3. Paste the generated GUID for the AppLogic into the source file (.cpp). Note that the text version is embedded in the comments (for readability purposes only) and that the GUID struct is what gets parsed.

       //

       // {C1B5E720-6153-11D1-A1AE-006008293C54}

       //

       GUID OBLoginGUID =

       { 0xC1B5E720, 0x6153, 0x11D1, { 0xA1, 0xAE, 0x00, 0x60,

          0x08, 0x29, 0x3C, 0x54 } };

  4. In the source file, establish to the iPlanet Application Server the entry point in a dynamically loadable, shared library module using the GXDLM_IMPLEMENT_BEGIN, GXDLM_IMPLEMENT, and GXDLM_IMPLEMENT_END macros. These macros define certain exported functions which the iPlanet Application Server expects to find when it loads the AppLogic at runtime. The macros are needed in order to fully initialize and create instances of the AppLogic.

       GXDLM_IMPLEMENT_BEGIN();

       GXDLM_IMPLEMENT(COBLogin, OBLoginGUID);

       GXDLM_IMPLEMENT_END();

       OBLogin::OBLogin() {

          GXDllLockInc(); // Update count of refs to applogic lib

       };

       OBLogin::~OBLogin() {

          GXDllLockDec(); // Update count of refs to applogic lib

       };

    It is advisable to use the GXDllLockInc( ) function at the beginning of the constructor method and the GXDllLockDec( ) function at the end of the destructor method.

  5. Override the Execute( ) method with your own code. The STDMETHODIMP macro specifies that this execute method has a return type value of virtual HRESULT.

       STDMETHODIMP

       OBLogin::Execute()

       {

          // Overriding code

       }



Performing the Main Task in an AppLogic Object

To write code that performs the main task of an AppLogic object, override the AppLogic's Execute( ) method. The Execute( ) method is inherited from the GXAppLogic class, from which you derived the AppLogic. iPlanet Application Server automatically calls Execute( ) when a request comes in for the AppLogic.

You can write code in Execute( ) to perform any desired task. A typical AppLogic's Execute( ) method might contain code to perform the following tasks:



Calling an AppLogic From Code

In addition to being executed by iPlanet Application Server in response to user requests, AppLogic objects can be called by other AppLogic objects or by other code. The called AppLogic returns results to the calling code, as shown in the following illustration.



AppLogic objects can call each other whether they are running on the same iPlanet Application Server or on different iPlanet Application Servers. In your AppLogic code, you do not specify the location of the called AppLogic. This allows you to change the partitioning and location of AppLogic objects and redeploy an application without having to modify AppLogic code.

In some cases, the user might submit a request that runs an AppLogic, which calls another AppLogic, which calls another one, and so on. The input parameters are passed down the chain automatically by iPlanet Application Server, and the results from the called AppLogics are passed back up the chain until they reach the end user. You can modify the input parameters or intercept the results at any point if desired, but typically, the parameters and results are passed along as shown in the following illustration.



To call an AppLogic from another AppLogic, use the NewRequest( ) method. For server-side code, this method is in the GXAppLogic class. For client-side code, it is in the IGXConnection interface. In the NewRequest( ) call, specify the name or globally unique identifier (GUID) of the AppLogic you want to call. The name or GUID is assigned when you register the AppLogic with iPlanet Application Server. For more information about registration, see Registering Code And Security Information of , "Running and Debugging Applications."

iPlanet Application Server uses the arguments of the NewRequest( ) method to construct an AppLogic request, which it then processes by executing the AppLogic. For more information, see Requests, AppLogic Names, and GUIDs.

You can pass parameters to and from the called AppLogic by using IGXValList objects. For more information, see Passing Parameters to AppLogic From Code.


Example
The following code calls an AppLogic by GUID:

hr = NewRequest("{E5CA1000-6EEE-11cf-96FD-0020AFED9A65}",

                 m_pValIn, m_pValOut, 0);

The following code shows how to call the same AppLogic by name. In this code, it is assumed that you have registered the AppLogic with the name CShowMenuPage.

hr = NewRequest("AppLogic CShowMenuPage",

                 m_pValIn, m_pValOut, 0);



Requests, AppLogic Names, and GUIDs



When an AppLogic object is called, whether from a user or from code, a message called a request is sent to iPlanet Application Server. In response to the request, iPlanet Application Server runs the AppLogic. Requests from users and from within program code can use either of the following techniques to identify the proper AppLogic to handle the request:

  • unique AppLogic name

  • globally unique identifier (GUID)

The following illustration shows how AppLogics are called.



Every AppLogic has a unique name and a unique GUID. The GUID is a 128-bit hexadecimal number in the following format:

{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

For example:

{C1B5E720-6153-11D1-A1AE-006008293C54}

When an AppLogic is registered with iPlanet Application Server, a unique GUID and a name are assigned to the AppLogic.You can register AppLogics and assign names to them using the technique described in Registering Code And Security Information of , "Running and Debugging Applications."



Passing Parameters to AppLogic Objects



When iPlanet Application Server processes a request to run an AppLogic object, it checks the request to see whether it contains any parameters, and it passes the parameters to the AppLogic. For example, the parameters may be values the user has supplied from input fields on a form. AppLogic objects can also call an AppLogic and pass parameters to it, setting up the parameters in code.

iPlanet Application Server passes parameters in the form of IGXValList objects. An IGXValList object is an unordered collection of named parameters. Each parameter has a data type and value. To pass parameters to an AppLogic, iPlanet Application Server constructs an IGXValList object based on the names and values it finds in the request, as shown in the following illustration.




Passing Parameters To AppLogic From An HTML Page

The following illustration and list summarize the steps you follow and the sequence of events that occurs when you pass parameters to an AppLogic object from an HTML page.



To pass parameters to AppLogic from an HTML page

  1. Create an HTML form and write an AppLogic object to handle the input from the form. The form typically includes the following items:

    • One or more named controls that accept input, either as typed text or selected values, such as radio buttons and single- or multiple-selection list boxes. If a user selects several items from a multiple-selection list box, the value of the field is returned as a semicolon-delimited list.

    • A Submit button that the user clicks after filling out the form.

    • The URL that specifies which AppLogic to run when the user clicks the Submit button.

    For more information about how to code this URL, see Calling an AppLogic Object From an HTML Page of , "Writing Server-Side Application Code."

  2. The user runs the application and fills out the form. When the user clicks Submit, a request is issued that includes the input field names, data values, and AppLogic name or GUID from the form. The Web server passes this request to iPlanet Application Server.

  3. iPlanet Application Server instantiates an IGXValList object and populates it with the data values from the form. Each value in the list is named after one of the input fields on the form. The input parameters might also include cookies, if any are currently stored in the Web browser for this application.

  4. iPlanet Application Server then instantiates the AppLogic, sets the AppLogic's m_pValIn member variable to the IGXValList object that contains the AppLogic's input parameters, and then calls the Execute( ) method of the AppLogic.

  5. The AppLogic can get the parameter values by referencing m_pValIn and using the GetVal**( ) methods of the IGXValList interface.


Example
In the Online Bank sample application, an employee of the bank can use the Find Customer form to get information about a given customer. This form is presented as an HTML page with input fields into which the employee types the search criteria, such as the customer's last name:

<!-- Preliminary HTML tags ... -->

<FORM method="POST" action="/cgi-bin/gx.cgi/

   AppLogic+FindCust">

<H2>Search for Customer</H2>

<H5>Please enter search criteria:</H5>

<TABLE BORDER=0 COLS=2 WIDTH=100% BGCOLOR=#CCCC80>

<TR>

<TD>Last Name</TD><TD><INPUT TYPE="TEXT" NAME="lastName"

   SIZE=30 VALUE=""></TD>

</TR>

<TR>

<TD>First Name</TD><TD><INPUT TYPE="TEXT"

   NAME="firstName" SIZE=30 VALUE=""></TD>

</TR>

<!-- Other criteria fields ... -->

</TABLE>

<input type="submit" name="go" value="Search">

</FORM>

<!-- Closing HTML tags ... -->

When the employee clicks the form's Search button, a request is sent to the Web server. The request includes the name of the FindCust AppLogic, which is designed to process this form. The names of fields from the form and the data the bank employee typed in each field are also included in the request.

The Web server forwards the request to the iPlanet Application Server, which places the input data in an IGXValList object. iPlanet Application Server then runs the FindCust AppLogic, setting the AppLogic's m_pValIn parameter to the IGXValList object that contains the AppLogic's parameters.

The AppLogic's Execute( ) method contains code to get the parameter values out of the IGXValList object. For example, the following code places the data value from the LastName field on the form into a variable named pLastName.

LPSTR pLastName=NULL;

pLastName=GXGetValListString(m_pValIn, "lastName");

After using the parameter values to look up the requested customer data from the bank's database, the AppLogic returns an HTML page to display the results.


Uploading Files From a Web Browser

By using AppLogic input parameters, you can send a text or binary file from a Web browser to an application running on the iPlanet Application Server. You can also upload files in Microsoft Internet Information Server (MS IIS). This feature is useful for applications which could benefit from the submission of files of data. The file is passed in the input IGXValList object, just like any other parameters coming from the HTML page.

For example, in a Human Resource management application, a form could prompt the user to attach a resume file along with other information such as the job for which they are applying. The AppLogic receiving the submitted resume could store the resume and other information in a database.

For applications that use the file upload feature to work, file uploading must be supported by the Web server to which the iPlanet Application Server is connected.


Example
The following example HTML code uploads the user's file when the user clicks the Send File button. The file name of the user's file becomes the value of the variable userFile.

<FORM ENCTYPE="multipart/form-data" ACTION="/cgi-bin/gx.cgi/GUIDGX-{0F6D8100-6E1F-11cf-96FD-0020AFED9A6 5}" METHOD=POST>

Send this file: <INPUT NAME="userFile" TYPE="file">

<INPUT TYPE="submit" VALUE="Send File">

</FORM>

The following example code handles the submission of the file and processes its contents. This code would appear as part of the AppLogic corresponding to the GUID {0F6D8100-6E1F-11cf-96FD-0020AFED9A65}.

StreamResult("<HTML><HEAD><TITLE>File Submit</TITLE>

   </HEAD>");

StreamResult("<BODY BGCOLOR=#FFFFFF>");

StreamResult("<H2>File Info</H2>");

char tmp[1024];

tmp[0] = '\0';

m_pValIn->GetValString("userFile_file", tmp, sizeof(tmp));

StreamResult("<br>File name: ");

StreamResult(tmp);

tmp[0] = '\0';

m_pValIn->GetValString("userFile_type", tmp, sizeof(tmp));

StreamResult("<br>File type: ");

StreamResult(tmp);

tmp[0] = '\0';

m_pValIn->GetValString("userFile_size", tmp, sizeof(tmp));

StreamResult("<br>File size: ");

StreamResult(tmp);

int bufferSize = atoi(tmp) + 16;

char *buffer = new char[bufferSize];

buffer[0] = '\0';

m_pValIn->GetValBLOB("userFile", (LPBYTE) buffer,

   bufferSize);

StreamResult("<H2>File Content:</H2><PRE>");

StreamResult(buffer);

delete [] buffer;

StreamResult("</PRE></BODY></HTML>");

return 0;


Passing Parameters to AppLogic From Code

You can pass parameters to an AppLogic object when you call it from another AppLogic or from other code. To call an AppLogic from code, construct an IGXValList object in code, populate it with the desired parameter values, and pass the IGXValList object when you call the AppLogic. You can also return output parameters from the called AppLogic in another IGXValList object.

The following illustration and list summarize the steps you follow and the sequence of events that occurs when you pass parameters to an AppLogic from code. In the following discussion, the use of output parameters is also described.



To pass parameters to an AppLogic from code:

  1. Instantiate two IGXValList objects. Populate one IGXValList object with the parameters you want to pass to the AppLogic. The second IGXValList object is for the parameters that will be returned from the called AppLogic. To set up these objects, use the following methods:

    • To instantiate the IGXValList objects, use the GXCreateValList( ) function. For example:

            m_pParamsTo = GXCreateValList();

            m_pParamsReturned = GXCreateValList();

    • To populate the first IGXValList object with parameters you want to pass to the AppLogic, use the SetVal**( ) methods of the IGXValList interface. With each call to any of these methods, you specify a parameter name and its value. For example, the following line specifies a string parameter named stateVal and sets it to the value Oklahoma:

            GXSetValListString(m_pParamsTo, "stateVal","Oklahoma");

  2. Call the AppLogic using the NewRequest( ) method from the GXAppLogic class. This method issues a request that includes the AppLogic name or GUID and the input and output IGXValList objects. For example:

       NewRequest(calledGUID, paramsTo, paramsReturned, 0);

    In response to the request, iPlanet Application Server instantiates the called AppLogic and sets its m_pValIn and m_pValOut member variables to the IGXValList objects specified by the calling code. In the previous example, m_pValIn is paramsTo and m_pValOut is paramsReturned.

  3. The AppLogic can obtain its input parameter values by referencing m_pValIn with theGetVal**( ) methods from the IGXValList interface, as appropriate. For example, the called AppLogic could use the following code to get the value of the stateVal input parameter:

       LPSTR state=GXGetValListString(m_pValIn, "stateVal");

  4. If desired, you can return output parameters from the called AppLogic by filling the output IGXValList object with values. To do so, use the m_pValOut member variable to reference the output IGXValList object, and call the SetVal**( ) methods of the IGXValList interface. The called AppLogic uses the same techniques to set up its output IGXValList object as the calling code used to set up the input IGXValList object. For example, the called AppLogic could use the following code to set the value of the Pop output parameter:

       m_pValOut->SetValString("Pop", result);

  5. After the AppLogic is finished running, the calling code can use its second IGXValList object to reference the parameters that were passed back from the called AppLogic. For example:

       paramsReturned->GetValString("Pop", population,

          sizeof(population));


Example
The following code shows part of an AppLogic that receives the name of a state as a parameter. The state comes from a field named StateField in a form that is filled out by the user. The AppLogic passes the state name to another AppLogic, which returns the population of that state. The called AppLogic passes the population out in a parameter named Pop.

// Get input parameter.

char state[128];

m_pValIn->GetValString("StateField", state, sizeof(state));

// Set up parameter to pass to other AppLogic.

IGXValList *paramsTo;

paramsTo = GXCreateValList();

paramsTo->SetValString("st", state);

// Set up IGXValList to receive result from other AppLogic.

IGXValList *paramsReturned;

paramsReturned = GXCreateValList();

// Call other AppLogic.

HRESULT hr;

hr = NewRequest("{E5CA1000-6EEE-11cf-96fd-0020AFED9A65}",

   paramsTo, paramsReturned, 0);

if (hr == NOERROR)

{

   // Get value from IGXValList returned by

   // other AppLogic.

   char population[128];

   paramsReturned->GetValString("Pop", population,

      sizeof(population));

   // ...

}

The following code shows how the called AppLogic references the state name that is passed in to it, and how it returns the Pop parameter to the calling AppLogic:

m_pValIn->GetValString("st", state, sizeof(state));

// ...

m_pValOut->SetValString("Pop", result);



Returning Results From an AppLogic Object



The final task an AppLogic object typically performs is returning its results. iPlanet Application Server directs the AppLogic results to the entity that called the AppLogic, whether it is a Web browser or another AppLogic.

For example, in response to a user request from a Web browser, an AppLogic might be called to look up data and merge it with an HTML template to create an HTML report. The report is the result of the AppLogic, and iPlanet Application Server sends the report back to the Web browser so the user can view it.


Types of Results

The techniques for returning AppLogic results fall into the following categories:

  • The return value of the Execute( ) method. It is advisable for every AppLogic to return this type of result to indicate success or failure. For more information, see Using the Return Value of Execute( ).

  • HTML pages. You should return HTML only when all clients are Web browsers and you want to create special HTML-specific output effects. For more information, see Returning HTML Results.

  • Output parameters in an IGXValList object. You can return this type of result when the AppLogic is called from another AppLogic. For more information, see Returning Output Parameters in an IGXValList Object.


Using the Return Value of Execute( )

The return statement stops execution of a method or function and returns a value indicating either a successful completion of the task or an error. For example, the following statement indicates success:

return GXE_SUCCESS;

A nonzero value indicates failure.

In an iPlanet Application Server application, you use the return statement in each AppLogic when you override its Execute( ) method (unless the Execute( ) method has been modified to return a data type other than int). Inside Execute( ), the return statement is commonly combined with a method call, such as EvalTemplate( ) or EvalOutput( ), that returns results to the entity that called the AppLogic.

The iPlanet Application Server Foundation Class Library provides several such methods. By combining a method call with the return statement, you can accomplish two objectives: you can send output such as an HTML report from the AppLogic, and you can return the numeric code that indicates success or failure.

For example, the following code uses EvalTemplate( ) to send a dynamically-generated HTML page back to the entity that called the AppLogic. When EvalTemplate( ) is finished, it returns a code indicating success or failure. This code is, in turn, used as the argument to the return statement.

return EvalTemplate("GXApp/COnlineBank/templates/

   CustomerMenu.html",(IGXHierQuery*)NULL, NULL, NULL, NULL);

If a single method call is not enough to return all the output from the AppLogic, you can use several method calls before the return statement. For example, the following code uses streaming to return an HTML result in three parts:

StreamResultHeader(header);

StreamResult(body1);

StreamResult(body2);

return 0;

The streaming methods return data as it becomes available, instead of waiting for all the data to be ready before sending output to the user. For more information about streaming, see Streaming Results.

The method calls need not occur immediately before the return statement as they do in the previous example. They can be separated by additional lines of code. For example, you might want to return the results in several portions from several points in the AppLogic code.

Application-specific return values, such as error values or messages, should be returned using the AppLogic's m_pValOut variable, output streaming, or EvalTemplate( ) or EvalOutput( ).


Returning HTML Results

You can explicitly return HTML when all clients are Web browsers. The advantage of forcing HTML results, rather than using the client-independent programming model, varies from application to application. If you wish to use particular features of HTML and are certain that all clients will be Web browsers for the life of the AppLogic, you can return HTML results using one of the following techniques:

  • Merge the result set from a hierarchical query with an HTML template to produce a dynamically generated HTML page. For example, use this technique to return a database report or a dynamically populated form.

    For more information, see Returning Results Using an HTML Template.

  • If the HTML result is not complicated or you prefer not to use an HTML template, you can construct and return HTML results programmatically. In most cases, it is preferable to use HTML templates because they are easier to maintain.

    For more information, see Returning HTML Results Without a Template.

You can also combine these two techniques to stream several portions of HTML in succession. When results are streamed, the first portion of the data is available for use immediately. This increases the perceived performance of the application. For example, although the AppLogic may process and return a lengthy query result, the AppLogic can use streaming to send back a report header, which is displayed quickly to the user. For more information, see Streaming Results.


Returning Results Using an HTML Template

To return HTML that is merged with dynamic data, use an HTML template. An HTML template is an HTML page that contains placeholders where data is to be merged with the template. For more information, see , "Working with Templates."

The dynamic data is obtained from one of the following sources:

You can return additional results after EvalTemplate( ) has finished streaming its results. To do so, call StreamResult( ) after calling EvalTemplate( ). For more information, see Streaming Results.





Caution

The SaveSession( ) method in the GXAppLogic class performs some processing of HTTP headers, which must be sent before the HTTP body. The EvalTemplate( ) method streams an HTTP body. Therefore, if your application uses sessions and also streams HTML results to a Web browser, be sure to call SaveSession( ) before calling EvalTemplate( ) and StreamResult( ).




Example
The following code, from the ShowMenuPage AppLogic in the Online Bank sample application, uses EvalTemplate( ) to return an output HTML page using the HTML template CustomerMenu.html.

EvalTemplate("GXApp/COnlineBank/templates/CustomerMenu.html",

   (IGXHierQuery*)NULL, NULL, NULL, NULL);


Returning HTML Results Without a Template

An AppLogic can return HTML that is constructed programmatically, without using an HTML template. In most cases, it is preferable to use HTML templates, because they are easier to maintain.

To prepare HTML output programmatically, set the value of a string variable to the HTML string, and return that variable using Result( ) or StreamResult( ). For example, the following code is from the Logout AppLogic in the Online Bank sample application:

return Result("<HTML><BODY>Thanks for using the Online

   Bank.</BODY></HTML>");

You can also construct the HTML result in two parts, an HTTP header and HTTP body, and return the two parts sequentially. Use StreamResultHeader( ) to return the header and StreamResult( ) to return the body. For example:

StreamResultHeader(headerStr)

StreamResult(bodyStr);


Streaming Results

Streaming is a technique for managing how data is returned to the user. When results are streamed, the first portion of the data is available for use immediately. When results are not streamed, the whole result must be prepared before any part of it can be sent to the client. Streaming provides a way to return large amounts of data in a more timely manner.

In an iPlanet Application Server application, you can use streaming to return either HTML or client-independent results.


Methods That Affect Streaming
The following list summarizes the methods in the libraries that perform streaming. For details about these methods, see the iPlanet Application Server Foundation Class Reference.

The following methods affect the streaming of header information:

  • The SaveSession( ) method in the GXAppLogic class performs some processing of HTTP headers, which must be sent before the HTTP body. Therefore, if your application uses sessions and also streams HTML results to a Web browser, be sure to call SaveSession( ) before calling any streaming methods, including EvalTemplate( ) or EvalOutput( ).

    For more information about SaveSession( ), see Starting a Session of , "Managing Session and State Information."

  • The SetVariable( ) method sets the value of a variable and streams the variable out in an HTTP header. This method supports HTTP cookies. Call SetVariable( ) before calling any HTTP body streaming methods, such as EvalTemplate( ) or EvalOutput( ).

    For more information about SetVariable( ), see Using Cookies of , "Application Development Techniques."

  • The StreamResultHeader( ) method is used to explicitly stream an HTTP header to a Web browser. To use this method, construct the data you want to pass as a stream header and pass it to StreamResultHeader( ) as a parameter.

    For more information, see the iPlanet Application Server Foundation Class Reference.

The following methods stream body information:

  • The EvalTemplate( ) method merges data with a template. As soon as a segment of the output page is finished, EvalTemplate( ) streams it to the waiting client.

    For more information about EvalTemplate( ), see Returning Results Using an HTML Template.

  • The StreamResult( ) method is used to explicitly stream an HTTP body to a Web browser. To use this method, construct the data you want to pass as a stream body and pass it to StreamResult( ) as a parameter.

    For more information, see the iPlanet Application Server Foundation Class Reference.


HTTP Header and Body Components
Streamed HTML results are communicated using the Hypertext Transfer Protocol (HTTP), which is the protocol used for communicating hypertext documents across the Internet and the World Wide Web. The HTTP protocol specifies the order in which data must be passed. If your AppLogic calls HTTP methods out of order, the AppLogic violates the protocol and causes a runtime error at the Web browser.

The HTTP protocol divides data into two categories: header and body. A discussion of the requirements for HTTP headers and bodies is outside the scope of iPlanet Application Server documentation. For more information, refer to the literature on the HTTP protocol.

When streaming HTML, be sure to stream header data before body data. You can stream the header or body in several parts, using several method calls, as long as all the header calls occur before the body calls. For example:

StreamResultHeader(startHeader);

StreamResultHeader(finishHeader);

StreamResult(bodyStart);

StreamResult(bodyMiddle);

StreamResult(bodyEnd);


Returning Output Parameters in an IGXValList Object

AppLogic objects that are called by other AppLogics or by other code can return one or more output parameters in an IGXValList object. To return output parameters, populate the AppLogic's output IGXValList object with the values you want to return. Use the AppLogic's m_pValOut member variable to refer to the output IGXValList object, and use the SetVal**( ) methods of the IGXValList interface to populate the list. With each call to one of these methods, you name an item in the list and set its value.

For more information, see Passing Parameters to AppLogic From Code.


Example
The following code returns the product of two numbers in an output IGXValList object.

int product = a * b;

m_pValOut->SetValInt("answer", product);

return 0;



Caching AppLogic Results to Improve Performance



Results from AppLogic objects can be cached. A cache is a fast-access area in the computer's memory. Caching improves performance when AppLogics perform time-consuming operations, such as lengthy database queries and report generation. Only streamed results, such as reports, can be cached, not other results such as output parameters. For example, output from EvalOutput( ) or EvalTemplate( ) can be cached.

The first time an AppLogic runs, it can store its results in the cache. When the iPlanet Application Server receives additional requests for the same AppLogic, instead of running the time-consuming operations again, the iPlanet Application Server returns the results directly from the cache. The following illustration shows how caching works.



When the most up-to-date results are needed, it is necessary to run AppLogics every time they are requested, rather than using cached results. However, it is often appropriate to cache and reuse results. For example, sales reports that are generated daily can be cached for 24 hours. Stock market price quotes can be provided on a 15-minute delay basis, with results cached between each update.

Each AppLogic has one result cache. The cache can contain multiple results, which are produced by running the AppLogic with different input parameter values. For example, an AppLogic might produce a report that shows the order history for a product. The AppLogic would accept the name of the product as an input parameter from the user. The same AppLogic might, therefore, produce several different reports for different products, and some or all of these reports can be cached.


How to Cache Results

To specify that you want the results from an AppLogic to be cached, call the SetCacheCriteria( ) method. The parameters to SetCacheCriteria( ) define the conditions of the caching, such as how long cache results are kept, size of cache, and which input parameter values are significant in controlling when results are cached.

The SetCacheCriteria( ) method also clears the cache of any existing results. Therefore, before calling SetCacheCriteria( ), call IsCached( ) to avoid accidentally discarding the current contents of the cache. For example:

if (!IsCached())

{

   SetCacheCriteria(3600, 1, "");

}

IGXHierQuery *hqry;

// ...create and define hierarchical query here...

LPSTR templateName;

// ...assign template name here...

// Run template report.

//

EvalTemplate(templateName, hqry, NULL, NULL, NULL);

hqry->Release();

delete [] templateName;

return 0;


Using Cache Criteria

When you call SetCacheCriteria( ) to start caching, you specify the names and, optionally, the relevant values of certain AppLogic input parameters. You can specify criteria for some or all of the AppLogic's parameters. The criteria set limits on which parameters and which values are significant to iPlanet Application Server when the server determines whether to cache a particular AppLogic result.

Each time an AppLogic runs with caching enabled, iPlanet Application Server checks to see whether the AppLogic's input parameters match the criteria in the SetCacheCriteria( ) call. If so, iPlanet Application Server places the AppLogic's results in a cache. The cache also stores the values of the relevant parameters.

Each cached result is the output from running the AppLogic with a certain set of parameter values that fall within the criteria specified for that cache. For example, an EmployeeReport AppLogic might cache different reports for employees in different company departments, as shown in the following illustration.




How To Specify Caching Criteria

iPlanet Application Server provides several types of criteria that you can use to specify the conditions under which you want caching to occur. Use any of the following formats in the caching criteria parameter of SetCacheCriteria( ):

  • Parameter Name

  • Matching Value

  • List of Values

  • Range of Values

  • List of Several Criteria


Parameter Name
Use this to cache multiple results for every value of the specified parameter. For example:

SetCacheCriteria(3600,1,"Department");

Alternatively, you can also use the following syntax:

SetCacheCriteria(3600,1,"Department=*");

iPlanet Application Server caches a new result every time the AppLogic runs with a different value for the Department parameter.


Matching Value
Use this to cache a single result for a given value of a parameter. For example:

SetCacheCriteria(3600,1,"Department=Operations");

iPlanet Application Server caches only one result from this AppLogic, when the Department parameter is Operations.


List of Values
Use this to cache multiple results for several distinct values of a single parameter. For example:

SetCacheCriteria(3600,1,

   "Department=Research | Engineering");

iPlanet Application Server caches a maximum of two results from this AppLogic, one for Research and one for Engineering.


Range of Values
Use this to cache multiple results for a continuum of values of a single parameter. For example:

SetCacheCriteria(3600,1,"Salary=40000-60000");

iPlanet Application Server caches results from this AppLogic whenever the Salary parameter contains a new value between 40000 and 60000, inclusive.


List of Several Criteria
Use this to cache multiple results using the values of several parameters, up to the total number of parameters accepted by the AppLogic. The list can contain any combination of the previously described types of criteria, separated by commas. iPlanet Application Server caches results when all the criteria in the list are met. For example:

SetCacheCriteria(3600,1,

   "Department=Sales,Salary=40000-60000");

iPlanet Application Server caches results from this AppLogic whenever the Department parameter is Sales and the Salary parameter contains a new value between 40000 and 60000, inclusive.


Example
The following code is part of an AppLogic called EmployeeReport. The caching criteria supplied in the SetCacheCriteria( ) call specify that, if the AppLogic's Department parameter is either Sales or Publications, the AppLogic's results are to be cached. The value of the Department parameter is stored along with the cached results.

SetCacheCriteria(3600,1,

   "Department=Sales | Publications");

If this AppLogic runs once with a Department parameter value of "Sales", the results are cached, along with the parameter name and value, as shown in the following illustration.



Now suppose the iPlanet Application Server receives another request to run this same AppLogic, but this time the value of Department is "Publications." iPlanet Application Server checks to see whether the value of Department in the request

matches the value of Department in the cached result, as shown in the following illustration:



Because the values do not match, the iPlanet Application Server runs the AppLogic again. Because the parameter name and value match the criteria in the SetCacheCriteria( ) call, iPlanet Application Server creates a new entry in the AppLogic's cache and stores the AppLogic's results. iPlanet Application Server also stores the current value (Publications) of the Department parameter. As a result, now two cached results exist for this AppLogic, as shown in the following illustration.



The next time iPlanet Application Server receives a request to run EmployeeReport with a Department parameter of Sales or Publications, it uses the cached results for the appropriate department.

Keep in mind that the Department parameter can have other values besides Sales and Publications, or might be omitted entirely if it is an optional parameter. The AppLogic might also have other parameters. None of these other values or parameters have any bearing on caching, because the cache criteria make no reference to them. Only those parameters and values that are specified in the SetCacheCriteria( ) call, and no others, are used to identify the various cached results for an AppLogic.

For example, suppose an AppLogic request specifies "Engineering" for the Department parameter. The AppLogic runs without caching its results, because this value of the Department parameter does not fall within the caching criteria, as shown in the following illustration.




How to Change Caching Criteria

To change caching criteria, call SetCacheCriteria( ) again. Each subsequent call to SetCacheCriteria( ) supersedes the criteria set in the previous call. If the criteria are changed in the call, the contents of the AppLogic's result cache are discarded, and the new criteria replace the old criteria for subsequent executions of that AppLogic.

For example, suppose your mail-order business puts a certain sweater on sale for a week. In anticipation of increased user interest in the sale item, you could change the cache criteria so that requests for information about that sweater are cached.


How to Remove Cached Results

You can remove some or all of the current contents of the cache without changing the cache criteria. To remove some specific cached results, call RemoveCachedResult( ). For example, the following code removes a cached result for a given AppLogic. The first parameter specifies which AppLogic's results are to be removed, and the second gives the criteria that tell which particular results to remove:

hr = RemoveCachedResult(guid, m_pValIn);

To clear the cache of all results, call RemoveAllCachedResults( ). For example:

hr = RemoveAllCachedResults(guid);


Example
The following code removes cached results for a given AppLogic.

// Get the input parameter that tells which AppLogic's

// cache is to be flushed

guid = GXGetValListString(m_pValIn, "applogic");

// Get the input parameter that gives the criteria used

// in selecting which result(s) to flush from the cache

LPSTR specific = GXGetValListString(m_pValIn, "specific");

if (specific)

// If result criteria were passed in, flush the

// corresponding results from the cache

   hr = RemoveCachedResult(guid, m_pValIn);

else

{

   // If no specific cache criteria were passed in,

   // either delete the cache or remove all entries,

   // depending on value of the "delete" parameter

   LPSTR del = GXGetValListString(m_pValIn, "delete");

   if (del)

      hr = DeleteCache(guid);

   else

      hr = RemoveAllCachedResults(guid);

}


How to Stop Caching

To stop caching results, call DeleteCache( ). For example:

hr = DeleteCache(guid);

When this method is called, the current contents of the AppLogic's result cache, if any, are deleted. Unless the AppLogic makes a subsequent call to SetCacheCriteria( ), no further results are cached for this AppLogic.

You can also stop caching temporarily by calling SkipCache( ). The AppLogic results are not cached this time the AppLogic runs, but the cache is not cleared, and when the AppLogic runs again in the future, it will continue to cache results.


Previous     Contents     Index     DocHome     Next     
Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.

Last Updated April 26, 2000