Skip Headers
Oracle® Fusion Middleware Developer's Guide for Oracle SOA Suite
11g Release 1 (11.1.1.5.0)

Part Number E10224-09
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

30 Building a Custom Worklist Client

Starting with the sample Worklist Application, you can build clients for workflow services using the APIs exposed by the workflow service. The APIs enable clients to communicate with the workflow service using remote EJBs, SOAP, and HTTP.

This chapter includes the following sections:

30.1 Introduction to Building Clients for Workflow Services

The typical sequence of calls when building a simple worklist application is as follows.

To build a simple worklist application:

  1. Get a handle to IWorklistServiceClient from WorkflowServiceClientFactory.

  2. Get a handle to ITaskQueryService from IWorklistServiceClient.

  3. Authenticate a user by passing a username and password to the authenticate method on ITaskQueryService. Get a handle to IWorkflowContext.

  4. Query the list of tasks using ITaskQueryService.

  5. Get a handle to ITaskService from IWorklistServiceClient.

  6. Iterate over the list of tasks returned, performing actions on the tasks using ITaskService.

Example 30-1 demonstrates how to build a client for workflow services. A list of all tasks assigned to jstein is queried. A task whose outcome has not been set is approved.

Example 30-1 Building a Client for Workflow Services—Setting the Outcome to APPROVE

try
{
 //Create JAVA WorflowServiceClient
 IWorkflowServiceClient  wfSvcClient = WorkflowServiceClientFactory.getWorkflowServiceClient(
  WorkflowServiceClientFactory.REMOTE_CLIENT);
 //Get the task query service
 ITaskQueryService querySvc = wfSvcClient.getTaskQueryService();

 //Login as jstein
 IWorkflowContext ctx = querySvc.authenticate("jstein","welcome1".toCharArry(),null);
 //Set up list of columns to query
 List queryColumns = new ArrayList();
 queryColumns.add("TASKID");
 queryColumns.add("TASKNUMBER");
 queryColumns.add("TITLE");
 queryColumns.add("OUTCOME");
 
 //Query a list of tasks assigned to jstein
 List tasks = querySvc.queryTasks(ctx,
              queryColumns,                   
              null, //Do not query additional info
              ITaskQueryService.AssignmentFilter.MY,
              null, //No keywords
              null, //No custom predicate
              null, //No special ordering
              0,    //Do not page the query result
              0);
 //Get the task service
 ITaskService taskSvc = wfSvcClient.getTaskService();
 //Loop over the tasks, outputting task information, and approving any
 //tasks whose outcome has not been set...
 for(int i = 0 ; i < tasks.size() ; i ++)
 {
  Task task = (Task)tasks.get(i);
  int taskNumber = task.getSystemAttributes().getTaskNumber();
  String title = task.getTitle();
  String taskId = task.getSystemAttributes().getTaskId();
  String outcome = task.getSystemAttributes().getOutcome();
  if(outcome == null)
  {
   outcome = "APPROVE";
   taskSvc.updateTaskOutcome(ctx,taskId,outcome);
  }
  System.out.println("Task #"+taskNumber+" ("+title+") is "+outcome);
 }

}
catch (Exception e)
{
 //Handle any exceptions raised here...
 System.out.println("Caught workflow exception: "+e.getMessage());
}

30.2 Packages and Classes for Building Clients

Use the following packages and classes for building clients:

30.3 Workflow Service Clients

Any worklist application accesses the various workflow services through the workflow service client. The workflow service client code encapsulates all the logic required for communicating with the workflow services using different local and remote protocols. After the worklist application has an instance of the workflow service client, it does not need to consider how the client communicates with the workflow services.

The advantages of using the client are as follows:

The following class is used to create instances of the IWorkflowServiceClient interface:

oracle.bpel.services.workflow.client.WorkflowServiceClientFactory

WorkflowServiceClientFactory has several methods that create workflow clients. The simplest method, getWorkflowServiceClient, takes a single parameter, the client type. The client type can be one of the following:

The other factory methods enable you to specify the connection properties directly (rather than having the factory load them from the wf_client_config.xml file), and enable you to specify a logger to log client activity.

The following enhancements to the workflow service clients are included in this release:

Through the factory, it is possible to get the client libraries for all the workflow services. See Table 31-1, "Enterprise JavaBeans, SOAP, and Java Support" for the clients available for each of the services.

Note that you can obtain instances of BPMIdentityService and BPMIdentityConfigService by calling the getSOAPIdentityServiceClient and getSOAPIdentityConfigServiceClient methods on WorkflowServiceClientFactory. You can obtain all other services through an instance of IWorkflowServiceClient.

The client classes use the configuration file wf_client_config.xml for the service endpoints. In the client class path, this file is in the class path directly, meaning the containing directory is in the class path. The wf_client_config.xml file contains:

Example 30-5 Section for Remote Clients

<remoteClient>
      <serverURL>t3://hostname.domain_name:7001</serverURL>
  <userName>weblogic</userName>
  <password>weblogic</password>
  <initialContextFactory>weblogic.jndi.WLInitialContextFactory
     </initialContextFactory>
  <participateInClientTransaction>false</participateInClientTransaction>
</remoteClient>

Example 30-6 Section for SOAP Endpoints

<soapClient>
   <rootEndPointURL>http://hostname.domain_name:7001</rootEndPointURL>
   <identityPropagation mode="dynamic" type="saml">
   <policy-references>
      <policy-reference enabled="true" category="security" 
         uri="oracle/wss10_saml_token_client_policy"/>
      </policy-references>
   </identityPropagation>
</soapClient>

The workflow client configuration XML schema definition is in the wf_client_config.xsd file.

30.3.1 The IWorkflowServiceClient Interface

The IWorkflowServiceClient interface provides methods, summarized in Table 30-1, for obtaining handles to the various workflow services interfaces.

Table 30-1 IWorkflowServiceClient Methods

Method Interface
getTaskService
oracle.bpel.services.workflow.task.ITaskService
getTaskQueryService
oracle.bpel.services.workflow.query.ITaskQueryService
getTaskReportService
oracle.bpel.services.workflow.report.ITaskReportService
getTaskMetadataService
oracle.bpel.services.workflow.metadata.ITaskMetadataService
getUserMetadataService
oracle.bpel.services.workflow.user.IUserMetadataService
getRuntimeConfigService
oracle.bpel.services.workflow.runtimeconfig.IRuntimeConfigService
getTaskEvidenceService
oracle.bpel.services.workflow.metadata.ITaskMetadataService

30.4 Class Paths for Clients Using SOAP

SOAP clients must have the following JAR files in their class path:

You can generate the wlfullclient.jar file using the commands shown in Example 30-7.

Example 30-7 wlfullclient.jar File Generation

cd ${bea.home}/wlserver_10.3/server/lib
java -jar ../../../modules/com.bea.core.jarbuilder_1.3.0.0.jar

Note:

Client applications no longer use the system\services\config or system\services\schema directories in the class path.

30.5 Class Paths for Clients Using Remote EJBs

Clients using remote EJBs must have the following JAR files in their class path:

Note:

Client applications no longer use the system\services\config or system\services\schema directories in the class path.

30.6 Initiating a Task

Tasks can be initiated programmatically, in which case the following task attributes must be set:

The following task attributes are optional, but are typically set by clients:

30.6.1 Creating a Task

The task object model is available in the package

oracle.bpel.services.workflow.task.model

To create objects in this model, use the ObjectFactory class.

30.6.2 Creating a Payload Element in a Task

The task payload can contain multiple payload message attributes. Since the payload is not well defined until the task definition, the Java object model for the task does not contain strong type objects for the client payload. The task payload is represented by the AnyType Java object. The AnyType Java object is created with an XML element whose root is payload in the namespace

http://xmlns.oracle.com/bpel/workflow/task

The payload XML element contains all the other XML elements in it. Each XML element defines a message attribute.

Example 30-8 shows how to set a task payload.

Example 30-8 Setting a Task Payload

import oracle.bpel.services.workflow.task.model.AnyType;
import oracle.bpel.services.workflow.task.model.ObjectFactory;
import oracle.bpel.services.workflow.task.model.Task;
..........

Document document = //createXMLDocument
Element payloadElem = document.createElementNS("http://xmlns.oracle.com/bpel/workflow/
  task", "payload");
Element orderElem = document.createElementNS("http://xmlns.oracle.com/pcbpel/test/order", "order");
Element child = document.createElementNS("http://xmlns.oracle.com/pcbpel/test/order", "id");
  child.appendChild(document.createTextNode("1234567"));
  orderElem.appendChild(child); 
  payloadElem.appendChild(orderElem);
  document.appendChild(payloadElem);

  task.setPayloadAsElement(payloadElem);

Note:

The AnyType.getContent() element returns an unmodifiable list of XML elements. You cannot add other message attributes to the list.

30.6.3 Initiating a Task Programmatically

Example 30-9 shows how to initiate a vacation request task programmatically.

Example 30-9 Initiating a Vacation Request Task Programmatically

// create task object
  ObjectFactory objectFactory = new ObjectFactory();
  Task task = objectFactory.createTask();

  // set title
  task.setTitle("Vacation request for jcooper"); 

  // set creator
  task.setCreator("jcooper");
 
// set taskDefinitionId. taskDefinitionId is the target
// namespace of the task 
// If namespace is used, the active version of the composite corresponding 
// to that of the namespace will be used.
task.setTaskDefinitionId("http://xmlns.oracle.com/VacationRequest/
Project1/Humantask1");  (Your task definition ID will be different.)

  // create and set payload 
  Document document = XMLUtil.createDocument();
  Element payloadElem = document.createElementNS(TASK_NS, "payload"); 
  Element vacationRequestElem = document.createElementNS(VACATION_REQUEST_NS,
    "VacationRequestProcessRequest");
 
  Element creatorChild = document.createElementNS(VACATION_REQUEST_NS, "creator");
  creatorChild.appendChild(document.createTextNode("jcooper")); 
  vacationRequestElem.appendChild(creatorChild);
  
  Element fromDateChild = document.createElementNS(VACATION_REQUEST_NS, "fromDate");
  fromDateChild.appendChild(document.createTextNode("2006-08-05T12:00:00")); 
  vacationRequestElem.appendChild(fromDateChild);
  
  Element toDateChild = document.createElementNS(VACATION_REQUEST_NS, "toDate");
  toDateChild.appendChild(document.createTextNode("2006-08-08T12:00:00"));
  vacationRequestElem.appendChild(toDateChild);
  
  Element reasonChild = document.createElementNS(VACATION_REQUEST_NS, "reason");
  reasonChild.appendChild(document.createTextNode("Hunting")); 
  vacationRequestElem.appendChild(reasonChild);
  
  payloadElem.appendChild(vacationRequestElem);
  document.appendChild(payloadElem);
  
  task.setPayloadAsElement(payloadElem);
 
  IWorkflowServiceClient workflowServiceClient =
    WorkflowServiceClientFactory.getWorkflowServiceClient
    (WorkflowServiceClientFactory.SOAP_CLIENT);
  ITaskService taskService = workflowServiceClient.getTaskService(); 
  IInitiateTaskResponse iInitiateTaskResponse = taskService.initiateTask(task); 
  Task retTask = iInitiateTaskResponse.getTask(); 
  System.out.println("Initiated: " + retTask.getSystemAttributes().getTaskNumber() + " - " +
    retTask.getSystemAttributes().getTaskId());
  return retTask;

30.7 Changing Workflow Standard View Definitions

The worklist application and the UserMetadataService API provide methods that you can use to create, update, and delete standard views. See Section 31.1.7, "User Metadata Service" for more information.

30.8 Writing a Worklist Application Using the HelpDeskUI Sample

The following example shows how to modify the help desk interface that is part of the HelpDeskRequest demo.

To write a worklist application

  1. Create the workflow context by authenticating the user.

    // get workflow service client
      IWorkflowServiceClient wfSvcClient =
        WorkflowServiceClientFactory.getWorkflowServiceClient
        (WorkflowServiceClientFactory.REMOTE_CLIENT);
     
    //get the workflow context
    IWorkflowContext wfCtx =
    wfSvcClient.getTaskQueryService().authenticate(userId, pwd, null);
    

    This is Step 3 in Section 30.1, "Introduction to Building Clients for Workflow Services."

    The login.jsp file of HelpDeskRequest uses the preceding API to authenticate the user and create a workflow context. After the user is authenticated, the statusPage.jsp file displays the tasks assigned to the logged-in user. Example 30-10 shows sample code from the login.jsp file.

    Example 30-10 Login.jsp

    <%@ page import="javax.servlet.http.HttpSession"
             import="oracle.bpel.services.workflow.client.IWorkflowServiceClient"
             import="oracle.bpel.services.workflow.client.WorkflowServiceClientFactory"
             import="java.util.Set"
             import="java.util.Iterator"
             import="oracle.bpel.services.workflow.verification.IWorkflowContext"
             import="oracle.tip.pc.services.identity.config.ISConfiguration"%>
    <%@ page contentType="text/html;charset=windows-1252"%>
     
    <html>
    <head>
    <title>Help desk request login page</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    </head>
     
    <body bgcolor="#F0F0F0" text="#000000" style="font: 12px verdana; line-height:18px">
    <center>
    <div style="width:640px;padding:15px;border-width: 10px; border-color: #87b4d9; border-style:
     solid;
    background-color:white; text-align:left">
     
        <!-- Page Header, Application banner, logo + user status -->
        <jsp:include page="banner.jsp"/>
       
        <!-- Initiate Meta Information -->
     
        <div style="background-color:#F0F0F0; border-top:10px solid white;border-bottom:
          10px solid white;padding:10px;text-align:center" >
        <b>Welcome to the HelpDesk application</b>
        </div>
     
        <% 
         String redirectPrefix =  "/HelpDeskUI/";
          // Ask the browser not to cache the page
          response.setHeader("Pragma", "no-cache");
          response.setHeader("Cache-Control", "no-cache");
     
          HttpSession httpSession = request.getSession(false);
          if (httpSession != null) {
           
            IWorkflowContext ctx = (IWorkflowContext) httpSession.getAttribute("workflowContext");
            if (ctx != null) {
              response.sendRedirect(redirectPrefix + "statusPage.jsp");
            }
            else
            {
              String authFailedStr = request.getParameter("authFailed"); 
              boolean authFailed = false;
              if ("true".equals(authFailedStr))
              {
                authFailed = true;
              }
              else
              {
                authFailed = false;
              }
     
              if (!authFailed)
              {
                //Get page parameters:
                String userId="";
                if(request.getParameter("userId") != null)
                {
                  userId = request.getParameter("userId");
                }
                String pwd="";
                if(request.getParameter("pwd") != null)
                {
                  pwd = request.getParameter("pwd");
                }
     
                if(userId != null && (!("".equals(userId.trim())))
                   && pwd != null && (!("".equals(pwd.trim()))))   
                {
                  try {
                    HttpSession userSession = request.getSession(true);
     
                    IWorkflowServiceClient wfSvcClient =
                            WorkflowServiceClientFactory.getWorkflowServiceClient
                                    (WorkflowServiceClientFactory.REMOTE_CLIENT);
                    IWorkflowContext wfCtx =
                                wfSvcClient.getTaskQueryService().authenticate(userId, pwd, null);
                    httpSession.setAttribute("workflowContext", wfCtx);
                    response.sendRedirect(redirectPrefix + "statusPage.jsp");
                  }
                  catch (Exception e)
                  {
                    String worklistServiceError = e.getMessage();
                    response.sendRedirect(redirectPrefix + "login.jsp?authFailed=true");
                    out.println("error is " + worklistServiceError);
                  }          
                }
              } else
              {
                out.println("Authentication failed");
              }
            }
          }
        %>
     
        <form action='<%= request.getRequestURI() %>' method="post">
          <div style="width:100%">
          <table cellspacing="2" cellpadding="3" border="0" width="30%" align="center">
            <tr>
              <td>Username
              </td>
              <td>
                <input type="text" name="userId"/>
              </td>
            </tr>
            <tr>
              <td>Password
              </td>
              <td>
                <input type="password" name="pwd"/>
              </td>
            </tr>
            <tr>
              <td>
                <input type="submit" value="Submit"/>
              </td>
            </tr>
          </table>
        </form>
        </div>
    </div>
    </center>
      </body>
    </html>
    
  2. Query tasks using the queryTask API from TaskQueryService.

    //add list of attributes to be queried from the task
    List displayColumns = new ArrayList();
         displayColumns.add("TASKNUMBER");
         displayColumns.add("TITLE");
         displayColumns.add("PRIORITY");
         displayColumns.add("STATE");
         displayColumns.add("UPDATEDDATE");
         displayColumns.add("UPDATEDBY");
         displayColumns.add("CREATOR");
         displayColumns.add("OUTCOME");
         displayColumns.add("CREATEDDATE");
         displayColumns.add("ASSIGNEEUSERS");
         displayColumns.add("ASSIGNEEGROUPS");
         // get the list of tasks
         List tasks =  wfSvcClient.getTaskQueryService().queryTasks
                            (wfCtx,
                            displayColumns,
                            null,
                            ITaskQueryService.AssignmentFilter.MY_AND_GROUP,
                            null,
                            null,
                            null,
                            0,
                            0);
        // create listing page by using above tasks
        //add href links to title to display details of the task by passing taskId
          as input parameter
       Use getTaskDetailsById(IWorkflowContext wftx, String taskId);
    

    This is Step 4 in Section 30.1, "Introduction to Building Clients for Workflow Services."

    The statusPage.jsp file of HelpDeskRequest is used to display the status of help desk requests. Example 30-11 shows the statusPage.jsp example code.

    Example 30-11 statusPage.jsp

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    <%@ page import="oracle.tip.pc.services.identity.BPMAuthorizationService,
                     oracle.bpel.services.workflow.verification.IWorkflowContext,
                     oracle.tip.pc.services.common.ServiceFactory,
                     oracle.bpel.services.workflow.client.IWorkflowServiceClient,
                     oracle.bpel.services.workflow.client.WorkflowServiceClientFactory,
                     oracle.bpel.services.workflow.query.ITaskQueryService,
                     oracle.bpel.services.workflow.task.model.Task,
                     oracle.bpel.services.workflow.task.model.IdentityType,
                     oracle.tip.pc.services.identity.BPMUser,
                     java.util.List,
                     java.util.Calendar,
                     java.text.SimpleDateFormat,
                     java.util.ArrayList"%>
    <%@ page contentType="text/html;charset=UTF-8"%>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>RequestPage</title>
        <style TYPE="text/css">
          Body, Form, Table, Textarea, Select, Input, Option
          {  
            font-family : tahoma, verdana, arial, helvetica, sans-serif;
            font-size : 9pt;
          }
          table.banner
          {
            background-color: #eaeff5;
          }
          tr.userInfo
          {
            background-color: #eaeff5;
          }
          tr.problemInfo
          {
            background-color: #87b4d9;
          }
        </style>
      </head>
      <body bgcolor="White">
      <%
         HttpSession httpSession = request.getSession(false);
         httpSession.setAttribute("pageType","STATUSPAGE");
      %>
      <table bordercolor="#eaeff5" border="4" width="100%">
        <tr><td> <jsp:include page="banner.jsp"/> </td></tr>
      </table>
      <%
          BPMUser bpmUser = null;
          String redirectPrefix =  request.getContextPath() + "/";
          IWorkflowContext ctx = null;
          if (httpSession != null) {
            
            ctx = (IWorkflowContext) httpSession.getAttribute("workflowContext");
            if (ctx != null) {
                bpmUser = getAuthorizationService(ctx.getIdentityContext()).
                                 lookupUser(ctx.getUser());
            }
            else
            {
               response.sendRedirect(redirectPrefix + "login.jsp");
               return;
            }
          }
          else
          {
             response.sendRedirect(redirectPrefix + "login.jsp");
             return;
          }
          if(bpmUser == null)
          {
            response.sendRedirect(redirectPrefix + "login.jsp");
             return;
          }
          String status = (String)httpSession.getAttribute("requeststatus");
          if(status != null && !status.equals(""))
          {
        %>
           <p></p>
           <div style="text-align:left;color:red" >
             <%= status %>
           </div>
        <%    
          }
          httpSession.setAttribute("requeststatus",null);
          IWorkflowServiceClient  wfSvcClient =
                            WorkflowServiceClientFactory.getWorkflowServiceClient(
                                     WorkflowServiceClientFactory.REMOTE_CLIENT);
          List displayColumns = new ArrayList();
          displayColumns.add("TASKNUMBER");
          displayColumns.add("TITLE");
          displayColumns.add("PRIORITY");
          displayColumns.add("STATE");
          displayColumns.add("UPDATEDDATE");
          displayColumns.add("UPDATEDBY");
          displayColumns.add("CREATOR");
          displayColumns.add("OUTCOME");
          displayColumns.add("CREATEDDATE");
          displayColumns.add("ASSIGNEEUSERS");
          displayColumns.add("ASSIGNEEGROUPS");
          List tasks =  wfSvcClient.getTaskQueryService().queryTasks
                            (ctx,
                            displayColumns,
                            null,
                            ITaskQueryService.ASSIGNMENT_FILTER_CREATOR,
                            null,
                            null,
                            null,
                            0,
                            0);
      %>
      <p></p>
      <div style="text-align:left;color:green" >
       <b>
        Previous help desk request
       </b>
      </div>
      <p></p>
      <div style="text-align:center" >
      <table cellspacing="2" cellpadding="2" border="3" width="100%">
         <TR class="problemInfo">
             <TH>TaskNumber</TH>
             <TH>Title</TH>
             <TH>Priority</TH>
             <TH>CreatedDate</TH>
             <TH>Assignee(s)</TH>
             <TH>UpdatedDate</TH>
             <TH>UpdatedBy</TH>
             <TH>State</TH>
             <TH>Status</TH>
         </TR>
         <%
           SimpleDateFormat dflong = new SimpleDateFormat( "MM/dd/yy hh:mm a" );
           for(int i = 0 ; i < tasks.size() ; i ++)
           {
              Task task = (Task)tasks.get(i);
              int taskNumber = task.getSystemAttributes().getTaskNumber();
              String title = task.getTitle();
              int priority = task.getPriority();
              String assignee = getAssigneeString(task);
              Calendar createdDate = task.getSystemAttributes().getCreatedDate();              
              Calendar updateDate =  task.getSystemAttributes().getUpdatedDate();
              String updatedBy = task.getSystemAttributes().getUpdatedBy().getId();
              String state = task.getSystemAttributes().getState();
              String outcome = task.getSystemAttributes().getOutcome();
              if(outcome == null) outcome = "";
              String titleLink = "http://" + request.getServerName() +
                                 ":" + request.getServerPort() +
                                  "/integration/worklistapp/TaskDetails?taskId=" +  
                                  task.getSystemAttributes().getTaskId();
          %>
            <tr class="userInfo">
               <td><%=taskNumber%></td>
               <td><a href="<%=titleLink%>" target="_blank"><%=title%></a></td>
               <td><%=priority%></td>
               <td><%=dflong.format(createdDate.getTime())%></td>
               <td><%=assignee%></td>
               <td><%=dflong.format(updateDate.getTime())%></td>
               <td><%=updatedBy%></td>
               <td><%=state%></td>
               <td><%=outcome%></td>
            <tr>
         <%
           }
         %>
      </table>
      </div>
      <%!
          private BPMAuthorizationService getAuthorizationService(String identityContext)
          {
           BPMAuthorizationService authorizationService =
     ServiceFactory.getAuthorizationServiceInstance();
           if (identityContext != null)
             authorizationService = ServiceFactory.getAuthorizationServiceInstance(identityContext);
     
           return authorizationService;
          }
          private String getAssigneeString(Task task) throws Exception
          {
             List assignees = task.getSystemAttributes().getAssigneeUsers();
             StringBuffer buffer = null;
             for(int i = 0 ; i < assignees.size() ; i++)
             {
               IdentityType type = (IdentityType)assignees.get(i);
               String name = type.getId();
               if(buffer == null)
               {
                  buffer = new StringBuffer();
               }
               else
               {
                 buffer.append(",");
               }
               buffer.append(name).append("(U)");
             }
             assignees = task.getSystemAttributes().getAssigneeGroups();
             for(int i = 0 ; i < assignees.size() ; i++)
             {
               IdentityType type = (IdentityType)assignees.get(i);
               String name = type.getId();
               if(buffer == null)
               {
                  buffer = new StringBuffer();
               }
               else
               {
                 buffer.append(",");
               }
               buffer.append(name).append("(G)");
             }
             if(buffer == null)
             {
                return "";
             }
             else
             {
               return buffer.toString();
             }
          }
      %>
     </body>
    </html>