Complete Contents
Introduction
Chapter 1 About Netscape Application Server Extensions
Chapter 2 About the Netscape Extension Builder
Chapter 3 Introduction to Netscape's Interface Definition Language
Chapter 4 Designing a Netscape Extension
Chapter 5 Generating Output Files
Chapter 6 Completing Method Stubs
Chapter 7 Using Template Streaming
Chapter 8 Managing State and Session Information
Chapter 9 Using Object Pools
Chapter 10 Compiling the Extension Source Code
Chapter 11 Deploying and Managing a Netscape Extension
Chapter 12 Example Extension: HelloWorld
Appendix A C++ Helper Functions
Appendix B Java Helper Static Methods
Appendix C Java Class Decorations
Appendix D Reserved Words
Appendix E The ConnManager.cpp File
Glossary
Previous Next Contents Index


Using Template Streaming

This chapter describes template streaming, which enhances the performance of applications that use extensions.

The following topics are included in this chapter:


Introduction to Template Streaming
Template streaming enhances the performance of applications that use extensions. Extensions enabled for template streaming allow the Netscape Template Engine to stream results obtained by the extension back to the client. The template engine supports both HTML and GXML streaming for extensions. This means you can stream results back to non-HTML clients, such as OCL clients.

Template streaming is useful for extensions that return large amounts of data or that take a significant amount of time to process results. Streaming returns results to clients in groups of rows, allowing the client to process the data in chunks before all of the processing is actually completed.

Steps for Enabling Template Streaming
To enable extension objects to be easily streamed using Netscape's Template Engine, perform the following main tasks:

  1. In Netscape Extension Builder Designer, set the Template Streaming decoration in any coclasses for which you want to stream results.
  2. This step is described in Setting the Template Streaming Decoration.

  3. After generating source code, complete method stubs in the appropriate interface: either ITemplateData for Java extensions, or IGXTemplateData for C++ extensions.
  4. This step is described in Completing Stubs to Support Template Streaming. For reference information on these interfaces, see the Java or C++ edition of Netscape Application Server Foundation Class Reference.

  5. Create an HTML or GXML template to use with an application component.
  6. This step is described in Creating a Template.

  7. Test an application that uses the extension.
  8. This step is described in Testing an Application.

Example of Template Streaming
To demonstrate the preceding steps, a complete example is provided in the Netscape Extension Builder sample directory. The zoo subdirectory contains a Java extension that demonstrates the use of template streaming.

The sample application demonstrates the creation of objects, in this case animals. The AddAnimal application component enables you to create animals, one a time, along with associated data. The ListAnimals application component enables you to display the list of animals you created. Because this list is potentially large, the ListAnimals application component relies on the extension's template streaming to display the results immediately.

This example is relatively simple, in order to demonstrate the techniques involved. A more complex example might involve database access to obtain data about each animal. In that case, template streaming would be particularly useful because an end user would not need to wait for completion of all database accesses before seeing results.


Setting the Template Streaming Decoration
Template streaming is useful for coclasses that represent lists of objects whose data might be streamed to the browser.

In Netscape Extension Builder Designer:

  1. Highlight a coclass for which you want to enable template streaming.
  2. In the component view, set the Template Streaming decoration to Yes.
  3. This indicates that the results obtained by methods of this class are handled by the Netscape Template Engine, and the results will be streamed back to the user.

  4. Finish designing the extension, and generate IDL files as you would for any extension.
For example, if you open the zoo.gxp project file in Netscape Extension Builder Designer and expand the tree view, a window would appear like the one shown in the following figure. In this example, CZoo is the only coclass with Template Streaming enabled.


Completing Stubs to Support Template Streaming
When the KIDL Compiler detects Template Streaming decorations, it generates source code for a particular Netscape Application Server-defined interface: either IGXTemplateData in a C++ extension or ITemplateData in a Java extension. The generated code appears in the stub files corresponding to coclasses you decorated, and you must complete the method stubs to provide the appropriate streaming implementation.

The methods in the IGXTemplateData or ITemplateData interface are used to iterate through a set of data. In applications, these interfaces are used by EvalOutput( ) or evalOutput( ) to stream data to the browser or OCL client.

Template Streaming in C++ Extensions
In Netscape Extension Builder Designer, suppose you enabled template streaming on a coclass named CTeacher. Then subsequent code generation would produce a corresponding C++ stub file, CTeacher.cpp.

Before you complete the method stubs of IGXTemplateData, this interface would appear as in the following code fragment. For an example of completed method stubs, see Template Streaming in Java Extensions.

// Stub method bodies for interface: IGXTemplateData

HRESULT

CTeacher::IsEmpty(

/* [in] */ LPSTR group,

/* [out] */ BOOL *empty)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

GXASSERT(FALSE, GXASSERT_WARNING,

"No implementation for CTeacher::IsEmpty");

return hr;

}

HRESULT

CTeacher::MoveNext(

/* [in] */ LPSTR group)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

GXASSERT(FALSE, GXASSERT_WARNING,

"No implementation for CTeacher::MoveNext");

return hr;

}

HRESULT

CTeacher::GetValue(

/* [in] */ LPSTR szExpr,

/* [out] */ IGXBuffer **ppBuff)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

GXASSERT(FALSE, GXASSERT_WARNING,

"No implementation for CTeacher::GetValue");

return hr;

}

HRESULT

CTeacher::SetHint(

/* [in] */ LPSTR group,

/* [in] */ DWORD flags,

/* [in] */ unsigned long max,

/* [in] */ IGXValList *pVal)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

GXASSERT(FALSE, GXASSERT_WARNING,

"No implementation for CTeacher::SetHint");

return hr;

}

Note the three method stubs in the interface: IsEmpty( ), MoveNext( ), and GetValue( ). First, the Netscape template engine makes a callback to IsEmpty( ) to determine whether any data was returned. Next, MoveNext( ) is called to move to the next block of data in the result set, until the end is reached. Finally, for each row in the result set, GetValue( ) is called to retrieve field values.

Any class that supports streaming can be used as a parameter to EvalOutput( ). For example:

IMyInterface *pIf;

//

// Get a pointer to IMyInterface

//

HRESULT hr=GXE_FAIL;

IGXTemplateData *pData=NULL;

// Navigate to the IGXTemplateData interface

if(((hr=pIf->QueryInterface(IID_IGXTemplateData,

(LPVOID*)&pData))==GXE_SUCCESS)&&pData)

{

// Stream back to the client. The template engine

// will use the IGXTemplateData method callbacks

// to accomplish streaming

EvalOutput("mypage.html", pData, NULL, NULL, NULL);

pData->Release();

}

Template Streaming in Java Extensions
In addition to completing method stubs for your user-defined interfaces, you must locate the ITemplateData interface code and complete the method stubs defined in this interface.

Any class that supports template streaming, by implementing the ITemplateData interface, can be used as a parameter to evalOutput( ). For example:

public int execute()

{

IZoo zoo = getZoo();

return evalOutput("zoo\Templates\ZooListing.html",

(ITemplateData) zoo, null, null, null);

}

In the Zoo sample extension, CZoo is the only coclass that uses the Template Streaming decoration. This coclass is in the cZoo service module, so the stub file you want to edit is:

zoo\java\zoo\cZoo\CZoo.java

As an example of completing method stubs for template streaming, you might modify the Zoo extension using the following procedure. The complete implementation is shown in The CZoo.java File.

  1. Open CZoo.java.
  2. Note the following code near the top of the file:

    public class CZoo

    implements zoo.IZoo, com.kivasoft.ITemplateData

  3. Locate the beginning of the method bodies for ITemplateData.
  4. The isEmpty( ) method appears first. You might complete it as shown in the following sample code:

    // Method bodies for interface: ITemplateData

    public boolean isEmpty(

    java.lang.String group)

    {

    // ignore group parameter, not using it

    return !mAnimalEnumeration.hasMoreElements();

    }

    The isEmpty( ) method determines whether there are any more elements in the result set. You can complete this method in several ways. The example code uses an enumeration.

  5. Locate the next method stub, moveNext( ), which iterates through the result set.
  6. You might complete it as shown in the following sample code:

    public int moveNext(

    java.lang.String group)

    {

    // ignore group parameter, not using it

    int retVal = -1; // if empty

    if (mAnimalEnumeration.hasMoreElements()) {

    mCurrentAnimal = (IAnimal)

    mAnimalEnumeration.nextElement();

    retVal = 0;

    }

    return retVal;

    }

  7. Locate the next method stub, getValue( ), which dynamically retrieves the specified values.
  8. The szExpr string is the current tag from the template as EvalOutput( ) processes the template. If the EvalOutput( ) method understands the tag, it returns the corresponding string data from the selected animal object, or from the zoo object itself.

    Note also that getValue( ) must return an IBuffer value, instead of directly returning a string value.

    You might complete getValue( ) as shown in the following sample code:

    public com.kivasoft.IBuffer getValue(

    java.lang.String szExpr)

    {

    String outString = "Error animal";

    System.out.println("getValueString: " + szExpr);

    if (mCurrentAnimal != null && szExpr != null) {

    if (szExpr.equals("AnimalName")) {

    outString = mCurrentAnimal.getName();

    } else if (szExpr.equals("AnimalType")) {

    if (mCurrentAnimal instanceof IElephant) {

    outString = "Elephant";

    } else if (mCurrentAnimal instanceof IPanda) {

    outString = "Panda";

    } else if (mCurrentAnimal instanceof IFrog) {

    outString = "Frog";

    }

    } else if (szExpr.equals("AnimalId")) {

    outString = mCurrentAnimal.getId() + "";

    } else if (szExpr.equals("AnimalData")) {

    if (mCurrentAnimal instanceof IElephant) {

    IElephant elephant = (IElephant)

    mCurrentAnimal;

    outString = elephant.getTrunkSize() + "feet";

    } else if (mCurrentAnimal instanceof IPanda) {

    IPanda panda = (IPanda) mCurrentAnimal;

    int type = panda.getType();

    if (type == 0) {

    outString = "Giant Panda";

    } else {

    outString = "Red Panda";

    }

    } else if (mCurrentAnimal instanceof IFrog) {

    IFrog frog = (IFrog) mCurrentAnimal;

    outString = frog.getColor();

    }

    } else if (szExpr.equals("ZooName")) {

    outString = getName();

    }

    }

    IBuffer buffer = GX.CreateBufferFromString(outString);

    return buffer;

    }

  9. Ignore the setHint( ) method by having it return 0.

Creating a Template
In addition to completing method stubs, you must create a template to display the results. The template is used by the application component that calls the extension.

In the Zoo extension, the sample template file is:

zoo\Templates\ZooListing.html

This HTML file contains the following text:

<HTML><HEAD><TITLE>Zoo Listing</TITLE></HEAD>

<BODY bgcolor="#FFFFFF" text="#000000" link="#CC0000" vlink="#FF3300" alink="#003366" basefont=3>

<H1>A list of the animals currently in the zoo:</H1>

<TABLE BORDER=1 CELLPADDING=2 CELLSPACING=0>

<TR><TH> animal name

</TH><TH> animal type

</TH><TH> animal id

</TH><TH> animal data

</TH></TR>

%gx type=tile id=Zoo MAX=100%

<TR ALIGN=RIGHT>

<TD>%gx type=cell id="AnimalName"%%/gx%

</TD>

<TD>%gx type=cell id="AnimalType"%%/gx%

</TD>

<TD>%gx type=cell id="AnimalId"%%/gx%

</TD>

<TD>%gx type=cell id="AnimalData"%%/gx%

</TD>

</TR>

%/gx%

</TABLE>

<br>

<a href="/ZooAdmin/index.html">

back to main page

</a>

</BODY>

</HTML>


Testing an Application
After the extension and template are completed, you can test the new functionality in an application.

Note. Before tesing the new functionality in the application, be sure that you have stopped NAS and NES before compiling the extension and have re-started them before loading the test page in the browser.

To test the new functionality in an application, perform the following steps:

  1. From your web browser, load a test page that uses the application. Point your browser to http://<my_host_name>/extensions, and select the Zoo example. The web page that tests the Zoo extension is:
  2. zoo\applogic\docs\ZooAdmin\index.html

    This page offers two choices. You can either add animals or list animals. Each choice relies on a separate application object for processing. The application component that displays the list is the one whose functionality was extended by the Zoo extension.

  3. To add animals, click "Add animals" or load the AddAnimal.html page. You can add arbitrary values.
  4. When you decide you are ready to list the animals, return to index.html and click "List animals."
  5. This invokes an application component whose functionality has been extended with template streaming. A streamed result set is returned and displayed using the ZooListing.html template.


The CZoo.java File
The CZoo.java file contains completed method stubs for a user-defined interface named IZoo, as well as the Netscape Application Server-defined ITemplateData interface.

//

// This file is initially generated by KIDL - Edit as

// necessary to complete

//

package zoo.cZoo;

import com.kivasoft.*;

import com.kivasoft.types.*;

import com.kivasoft.util.*;

import zoo.*;

import java.util.*;

public class CZoo

implements zoo.IZoo, com.kivasoft.ITemplateData

{

public zoo.cZoo.CZooMgr m_Module;

protected String mName = null;

protected Vector mAnimalList = null;

protected Enumeration mAnimalEnumeration = null;

protected IAnimal mCurrentAnimal = null;

public CZoo(zoo.cZoo.CZooMgr module, String name)

{

m_Module=module;

mName = name;

mAnimalList = new Vector();

reset();

}

public void finalize()

{

}

public String getName()

{

return mName;

}

public void reset()

{

mAnimalEnumeration = mAnimalList.elements();

if (mAnimalEnumeration.hasMoreElements()) {

mCurrentAnimal = (IAnimal)

mAnimalEnumeration.nextElement();

}

}

// Method bodies for interface: IZoo

public zoo.IElephant addElephant(

java.lang.String name,

int id,

double trunkSize)

{

IElephant elephant = new CElephant(m_Module, name, id,

trunkSize);

mAnimalList.addElement(elephant);

return elephant;

}

public zoo.IPanda addPanda(

java.lang.String name,

int id,

int type)

{

IPanda panda = new CPanda(m_Module, name, id, type);

mAnimalList.addElement(panda);

return panda;

}

public zoo.IFrog addFrog(

java.lang.String name,

int id,

java.lang.String color)

{

IFrog frog = new CFrog(m_Module, name, id, color);

mAnimalList.addElement(frog);

return frog;

}

// Method bodies for interface: ITemplateData

public boolean isEmpty(

java.lang.String group)

{

// ignore group parameter, not using it

return !mAnimalEnumeration.hasMoreElements();

}

public int moveNext(

java.lang.String group)

{

// ignore group parameter, not using it

int retVal = -1;

if (mAnimalEnumeration.hasMoreElements()) {

mCurrentAnimal = (IAnimal)

mAnimalEnumeration.nextElement();

retVal = 0;

}

return retVal;

}

public com.kivasoft.IBuffer getValue(

java.lang.String szExpr)

{

String outString = "Error animal";

System.out.println("getValueString: " + szExpr);

if (mCurrentAnimal != null && szExpr != null) {

if (szExpr.equals("AnimalName")) {

outString = mCurrentAnimal.getName();

} else if (szExpr.equals("AnimalType")) {

if (mCurrentAnimal instanceof IElephant) {

outString = "Elephant";

} else if (mCurrentAnimal instanceof IPanda) {

outString = "Panda";

} else if (mCurrentAnimal instanceof IFrog) {

outString = "Frog";

}

} else if (szExpr.equals("AnimalId")) {

outString = mCurrentAnimal.getId() + "";

} else if (szExpr.equals("AnimalData")) {

if (mCurrentAnimal instanceof IElephant) {

IElephant elephant = (IElephant)

mCurrentAnimal;

outString = elephant.getTrunkSize() + "feet";

} else if (mCurrentAnimal instanceof IPanda) {

IPanda panda = (IPanda) mCurrentAnimal;

int type = panda.getType();

if (type == 0) {

outString = "Giant Panda";

} else {

outString = "Red Panda";

}

} else if (mCurrentAnimal instanceof IFrog) {

IFrog frog = (IFrog) mCurrentAnimal;

outString = frog.getColor();

}

} else if (szExpr.equals("ZooName")) {

outString = getName();

}

}

IBuffer buffer = GX.CreateBufferFromString(outString);

return buffer;

}

// We're not making use of this callback

public int setHint(

java.lang.String group,

int flags,

int max,

com.kivasoft.IValList pVal)

{

return 0;

}

}

 

Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.