Using Dynamic Server Pages (DSPs)

What Is a Dynamic Server Page?

A dynamic server page (DSP) is a document embedded with special codes (tags) that instruct webMethods Integration Server to perform certain actions when an HTTP (or HTTPS) client requests the document. DSPs are used to construct browser-based applications. Because they are HTML based, they can be used to build complex user interfaces that includes any valid construct (e.g., forms, cascading style sheets, JavaScript) recognized by the client’s browser.

Important: When Integration Server returns a DSP, it always sets the value of the HTTP content-type header field to text/html. Therefore, a DSP should only contain HTML content and should only be used by clients that recognize and accept this content type.

What Does a DSP Look Like?

A DSP looks like an ordinary HTML document that contains additional tags enclosed in % symbols (e.g., %loop%). When a client requests a DSP, Integration Server executes the action specified by the tag and substitutes the result of that action (based on the rules of the tag) in the document it returns to the client.

Note: A DSP tag is never sent to the client; the client receives only the result of the tag.

The following is an example of a very basic DSP (tags are in bold). In this example, the DSP invokes a service by way of the %invoke% tag. The %loop% … %endloop% block loops over the list of documents (called orders) that the service returns and inserts the results into the HTML document.

<HTML>  
<HEAD>  
<title>Order Tracking System>/title>  
</HEAD>  
  
<BODY>  
<h1>Current Orders</h1>  
 %invoke orders:showOrders%  
 %loop orders%  
 <p>Date: %value orderDate% PO Number %value orderNum%</p>  
 %endloop%  
 %endinvoke%  
</BODY>

When Do You Use DSPs?

DSPs are used to build browser-based clients (i.e., clients that use a web browser to retrieve documents). They allow you to construct a more secure and flexible user interface than can be built by directly invoking a service from a browser.

webMethods Integration Server Administrator is a good example of the type of user interface you can create with DSPs. The interface for this application is composed entirely of DSPs. You may want to refer to it for design ideas and examples of how to use particular tags. To examine the DSPs that make up the server’s user interface, look at the DSP files in the Integration Server_directory \packages\WmRoot\pub directory on your Integration Server.

What Are the Advantages of Using DSPs?

In the example in What Does a DSP Look Like?, the DSP invokes a service and displays its results. You could accomplish the same thing by invoking the service directly from a browser and applying an output template to the result. However, DSPs have several advantages over directly invoking a service with a URL:
  • They conceal the INVOKE mechanism and the name of the service from the user.
  • They give you the flexibility to change the name of a service or replace one service with another without changing the way in which the end user invokes the service. (The user always invokes the same DSP, whose contents you can change as needed.)
  • They can easily be updated and extended.
  • They allow you to execute multiple services via a single request.
  • They allow you to conditionally execute a service based on run-time input. For example, you might build a DSP that actually contains several different HTML pages, and use the %switch% tag to select among them.

Creating DSPs

To create a DSP, you must compose it with a text editor and then save it on Integration Server (see Publishing DSPs). Unlike output templates, you do not create DSPs with Service Development.

When you build a DSP, do the following:

  • Type literal text exactly as you want it to appear in the document that you want Integration Server to return to the client.
  • Insert DSP tags at the points where you want their results to appear. For a summary of valid DSP tags and how to use them, see Using the DSP Tags.
  • Make sure that your HTML file contains the proper encoding or META tag for the encoding you use, as this may affect the browser or parser performance outside the Integration Server.
Important: Make sure the document that you create resolves into a valid HTML document.
Note: While building your DSP, keep in mind that at run time Integration Server will process it once, from top to bottom.

File Encoding and Character Set Limitations

The file encoding you use limits the characters that you can use in your DSP (including the data inserted into your DSP using %VALUE% statements) to those in the character set of the encoding you choose. It also limits any translated versions of the DSPs to the same character set. Generally it is a good idea to use the UTF-8 (Unicode) encoding, since Unicode supports nearly all of the characters in all of the world's languages. You will not lose any data if you choose to save your DSP in UTF-8; any data entered into a form will be properly interpreted by Integration Server.

The encoding you choose also applies to any localized (translated) versions of the DSP that you create, so you should choose a character encoding that supports all of the languages for which you will create localized DSPs. For details, see DSPs and Output Templates in Different Languages.

Publishing DSPs

To run a DSP, you must publish it on an Integration Server. To do this, take the following general steps.
  1. Save the DSP document in a text file that has a “.dsp” extension. For example: showorders.dsp.
  2. Place the DSP file in the pub directory of the package in which you want the dsp to reside. For example:
    • To publish a DSP in the orders package, you would copy it to:

           Integration Server_directory \packages\orders\pub

    • To publish a DSP in the status subdirectory within the orders package, you would copy it to:

           Integration Server_directory \packages\orders\pub\status

For details about publishing DSPs in other languages, see DSPs and Output Templates in Different Languages.

Securing DSPs

The following sections describe how you can secure DSPs against unauthorized access, secure against cross site scripting (XSS) attacks, and limit the external URLs to which a page can be redirected.

Securing DSPs Against Unauthorized Access

When you publish a DSP, you need to configure the server’s security mechanisms to protect the DSP from unauthorized access. DSPs have two levels of security protection you need to set.
  • Access to the DSP itself. Access to a DSP is controlled by an Access Control List (ACL). An ACL specifies which users have permission to retrieve the DSP. An ACL allows you to make access to the DSP as liberal (e.g., allow access to anyone) or as restrictive (e.g., restrict access to only certain people) as you need.

    To assign an ACL to a DSP, you must update (or create) the .access file in the directory where the DSP resides. For procedures, see “Assigning ACLs to Files the Server Can Serve” in webMethods Integration Server Administrator’s Guide.

    Note: Unlike a service, access to a DSP cannot be restricted to a particular port. Thus you do not specify port-level controls for a DSP.
  • Access to services invoked by the DSP. When a user requests a DSP, the services invoked by the DSP are subject to a port-level check (against the port on which the DSP was requested) and an ACL check (against the user that requested the DSP). To ensure that the services in your DSP execute successfully, you must do the following:
    • Make sure that the services it invokes are allowed to execute on the port(s) where the DSP will be requested.
    • Make sure that users who are authorized to use the DSP are also authorized to execute the services that the DSP invokes. (For convenience, you might want to assign the same ACL to the DSP and to the services it invokes.)

    For information about configuring port-level security and assigning ACLs to services, see webMethods Integration Server Administrator’s Guide.

    Note: A service that is internally invoked by a service in a DSP is not subject to security control unless Enforce Execute ACL is set (in the Properties panel) for the internally invoked service. When this option is set, the server performs an ACL check on the service using the user ID under which the DSP was initially requested.

Securing DSPs Against Cross Site Scripting Attacks

If you have custom DSPs that use the %value Variable% tag, the output from the tag might be vulnerable to cross site scripting (XSS) attacks. To prevent these cross site scripting attacks, set the watt.core.template.enableFilterHtml parameter to true (the default). When this parameter is true, the output from a %value Variable% tag, including XML and JavaScript, is HTML encoded.

When the watt.core.template.enableFilterHtml parameter is set to true, if you do not want Integration Server to HTML encode the output from a %value Variable% tag, you can use the encode(none) option of the %value Variable% tag, (%value Variable encode(none)%).

If you do not want Integration Server to HTML encode the output from any %value Variable% tag in all DSPs, set the watt.core.template.enableFilterHtml parameter to false. Setting the watt.core.template.enableFilterHtml parameter to false does not override settings of the %value Variable% tag’s encode option.

Important: If you use encode(none) so that the output from a %value Variable% tag is not HTML encoded, that value is vulnerable to cross site scripting attacks. If you set the watt.core.template.enableFilterHtml parameter to false, all DSPs that use the %value Variable% tag are vulnerable to cross site scripting attacks.

For more information about the encode(none) option, see %value%. For more information about the watt.core.template.enableFilterHtml parameter, see webMethods Integration Server Administrator’s Guide.

Securing DSPs Against CSRF Attacks

Integration Server adds CSRF secure tokens in DSPs dynamically thereby ensuring that the custom DSPs are secured against CSRF attacks.

However, Integration Server does not insert CSRF secure tokens in custom DSPs that use the JavaScripts Location object such as document.location and window.location.href. You must update these pages manually.

For example, if you have the following code in your custom DSP:

  document.location="ldap-settings.dsp";

You must replace it with the following code, enabling the GET request:

  if(is_csrf_guard_enabled && needToInsertToken) {  
     document.location="ldap-settings.dsp?"  
     + _csrfTokenNm_ + "=" + _csrfTokenVal_;  
  } else {  
     document.location="ldap-settings.dsp";  
  }

You do not have to define the JavaScript variables _csrfTokenNm_, _csrfTokenVal_, is_csrf_guard_enabled, and needToInsertToken. But, you must import Integration Server_directory /WmRoot/csrf-guard.js to your DSP before using these variables, if you have not already imported /WmRoot/webMethods.js.

In GET requests, Integration Server inserts the CSRF secure token in the URL, thus displaying the CSRF secure token. When the CSRF guard is enabled (Security > CSRF Guard page in the webMethods Integration Server Administrator), to further secure the DSPs, Software AG recommends that you replace the GET requests with POST requests. POST requests eliminate the risk of sending the CSRF secure tokens in URLs. To replace a GET request by a POST request, pass the values as HTML form properties. To create new HTML form and set the properties in the form, use the createForm(<FORM_ID>, <ACTION>, "POST", <PARENT_TAG>) and setFormProperty(<FORM_ID>, <PROPERTY_ID>, <PROPERTY_VALUE>) methods defined in JavaScript webMethods.js.

For example, if the CSRF guard is enabled, to convert the above GET request code to POST, replace it with the following code:
Note: If the CSRF guard is disabled, continue to use the GET request.
  if(is_csrf_guard_enabled && needToInsertToken)
{
createForm("htmlForm_listeners ", 'ldap-settings.dsp', "POST", <PARENT_TAG>);
setFormProperty(“htmlForm_listeners”, _csrfTokenNm_, _csrfTokenVal_);
htmlForm_listeners.submit();
} else {
document.location="ldap-settings.dsp";
}

The <PARENT_TAG> can be head or body based on whether this code belongs to head or body of the DSP.

Integration Server inserts CSRF secure tokens in the links in DSPs only if these links point to a DSP. If these links do not point to a DSP, you must update these links manually to include the CSRF secure tokens. For example, if you have the following code in your DSP:

<a href="/invoke/wm.sap.Transaction/viewAs?type=xml</a>

If the CSRF guard is enabled, to convert it to POST request, create a new HTML form as shown below and change the link in the DSP:
Note: If the CSRF guard is disabled, continue to use the GET request.
if(is_csrf_guard_enabled && needToInsertToken)
{
createForm(“htmlform_transactionView”,
“="/invoke/wm.sap.Transaction/viewAs”, POST, <PARENT_TAG>);
setFormProperty(“htmlform_transactionView”, “type” “xml”);
setFormProperty(“htmlform_transactionView”, _csrfTokenNm_, _csrfTokenVal_);
<a href=”javascript:document.htmlform_transactionView.submit();></a>
} else {
<a href="/invoke/wm.sap.Transaction/viewAs?type=xml</a>
}

If the links in DSP point to another DSP, Integration Server automatically inserts CSRF secure token in the links. To further enhance the security, it is recommended that you convert the link in DSP as a POST request if it points to another DSP, provided the CSRF guard is enabled. For example, if you have the following code in your DSP:

<a href="security-ports-add.dsp">

After Integration Server inserts the CSRF secure token in the URL, the code is changed to the following:

<a href="security-ports-add.dsp?secureCSRFToken=<token_id>">

If the CSRF guard is enabled, to convert it to POST request, create a new HTML form as shown below and change the link in the DSP:
Note: If the CSRF guard is disabled, continue to use the GET request.
if(is_csrf_guard_enabled && needToInsertToken) {
createForm(“htmlform_security_ports”, “security-ports-add.dsp”, “POST”, <PARENT_TAG>);
setFormProperty(“htmlform_security_ports”, “action”, “add”);
<a href="javascript:document.htmlform_security_ports.submit();">Add Port</a>
} else {
<a href="security-ports-add.dsp?action=add">Add Port</a>
}

For more information about configuring CSRF guard in Integration Server, see webMethods Integration Server Administrator’s Guide.

Limiting the External URLs that Can Be Used for Redirection

Use the %validConst% tag in custom DSPs to specify a list of URLs to which a page can be redirected. By specifying the %validConst% tag, the page can only be redirected to the URLs you specify.

For more information about how to use this tag, see Specifying a List of Permitted URLs for Redirection.

Requesting DSPs

To process a DSP, you request it from a browser using the following URL format:

   http://hostName:portNum/packageName/fileName.dsp

where:
hostName Is the host name or IP address of the Integration Server on which the DSP resides.
portNum Is the port number on which the Integration Server listens for HTTP requests.
packageName Is the name of the package to which the DSP belongs. packageName must match the package directory in which the DSP resides within Integration Server_directory \packages on the server. If you do not specify a package name, the server looks for the named DSP in the Default package.
Note: This parameter is case-sensitive.
fileName.dsp Is the name of the file containing the DSP. This file name must have a “.dsp” extension, and it must reside within the pub directory (or a subdirectory beneath pub) under the package directory named in packageName. If the DSP resides in a subdirectory, include the name of that subdirectory in the file name (see example below).
Note: This parameter is case-sensitive.

Examples

The following URL retrieves showorders.dsp from a package named ORDER_TRAK on a server named rubicon:

  http://rubicon:5555/ORDER_TRAK/showorders.dsp

The following URL retrieves showorders.dsp from a package named ORDER_TRAK on a server named rubicon:

  http://rubicon:5555/ORDER_TRAK/showorders.dsp

The following URL retrieves showorders.dsp from the STATUS subdirectory in a package named ORDER_TRAK on a server named rubicon:

  http://rubicon:5555/ORDER_TRAK/STATUS/showorders.dsp

The following URL retrieves showorders.dsp from the Default package on a server named rubicon:

  http://rubicon:5555/showorders.dsp

Hyperlinks to DSPs

Typing the DSP’s URL on the address line in your browser is one way to run a DSP. However, when you use DSPs to build a user interface, you will often invoke DSPs from HTML forms and links as shown in the following example.

<HTML>  
<HEAD>  
   <title>Order Tracking System</title>  
</HEAD>  
  
<BODY>  
 <A HREF=/ORDER_TRAK/showorders.dsp>Show
Orders</A>  
</BODY>  
</HTML>

Using the DSP Tags

To develop a DSP, you embed DSP tags where you want the results of the tags to appear. The following is a summary of tags that you can use to build DSPs. For a complete description of each tag, see Tag Descriptions.

Important: DSP tags are case sensitive. In your DSP, you must type them exactly as shown below (e.g., type %loop%, not %LOOP%).
Use this tag... To...
%invoke% Invoke a service within a DSP.
%value% %rename% %scope%
Manipulate variables.
%ifvar% %switch%
Conditionally process a block of code within a DSP.
%loop% Reiterate a block of code within a DSP.
%include% Insert the content of a text file (which may contain additional DSP tags) into the DSP.
%validConst% Limit the external URLs that can be accessed via redirection.
%comment% Denote a comment within a DSP. Comments are neither processed by the DSP Processor nor returned to the requestor.
Note: Integration Server automatically resolves tags when a client requests that DSP via an HTTP or HTTPS request. If you want to resolve tags within a document at some arbitrary point in a service, you can explicitly run the DSP Processor against the document using the services in the pub.report folder. For information about using these services, see Arbitrarily Processing DSP Tags.

Begin...End Constructs

Many DSP tags have both beginning and ending elements. When you use the %loop% tag, for example, you enclose the code over which you want the DSP Processor to iterate, within a %loop%…%end% construct.

To make your DSP easier to read, you can append a suffix to the %end% element of any construct to visually associate it with its beginning element. For example, in the following DSP, the %end% element of the %loop% construct is named %endloop% and the %end% element for the %ifvar% construct is named %endifvar%.

.  
.  
.  
%ifvar orders%  
 %loop orders%  
 <p>Date: %value orderDate%PO Number: %value orderNum%</p>  
 %endloop%  
%endifvar%  
.  
.  
.

Be aware that only the first three characters of an %end% element are significant. The DSP Processor ignores any suffixes that you add and simply associates an %end% element with the most recent beginning element (in other words, the %end% element always ends the current construct). This means that you can nest one construct within another (as shown above), but you cannot overlap them.

For example, you cannot use the %comment%…%endcomment% construct to “remark out” an %endloop% element as shown in the following sample. Because the DSP Processor ignores suffixes, the first %endloop% tag would end the comment block, and the %endcomment% tag would end the loop.

  .  
  .  
  .  
  %ifvar orders%  
   %loop orders%  
   <p>Date: %value orderDate% PO Number: %value orderNum%</p>  
%comment%  
   <p>Buyer: %value orderDate% PO Number: %value orderNum%</p>  
   %endloop%  
%endcomment%  
   <p><b>Shipping Details:</b></p>  
   <p>Date Shipped: %value shipDate%<br>  
    Carrier: %value carrier% %value serviceLevel%<br>  
    ======================================================</p>  
   %endloop%  
  %endifvar%  
  . 
  . 
  .

Invoking Services Using the %invoke% Tag

You use the %invoke% tag to invoke a service in a DSP. When this tag is processed, Integration Server executes the specified service at the point where the tag appears and returns the results of the service to the DSP processor.

The basic format of the %invoke% tag is as follows, where serviceName is the fully qualified name of the service that you want to invoke:

%invoke serviceName%  
  Block of Code  
[%onerror%  
  Block
of Code]  
%end%

Example

.  
.  
.  
%invoke orders:getShipInfo%  
  <p>  
  Date Shipped: %value shipDate%<br>  
  Carrier: %value carrier% %value serviceLevel%  
  </p>  
%onerror%  
  %include standarderror.txt%  
%endinvoke%  
.  
.  
.

What Is Scope?

When you invoke a service in a DSP, notice that you do not specifically state which parameters you want to pass to it. Instead, the service automatically receives an IData object containing all the variables that are in the DSP’s current scope.

Scope refers to the set of variables upon which a DSP can operate directly. When a DSP is initially invoked, its scope encompasses the set of name=value pairs it receives (via GET or POST) from the requestor. For example, if you were to request a DSP with the following URL:

  http://rubicon:5555/ORDER_TRAK/getorderinfo.dsp?action=shipinfo&oNum=00011520

Its initial scope would look like this:

After you execute a service with the %invoke% tag, the scope automatically switches to encompass the set of variables returned by that service. For example, if the DSP in the preceding example invokes a service that returns shipping information, that DSP’s collection of variables would look like this after the service executes. Note that just the variables returned by the service are within scope.

Conceptually, you can think of a DSP as maintaining its run-time variables in a set of nested containers. It starts with a container that holds the variables submitted by the requestor. When a service is invoked, it puts the results from the service in a new container inside the initial container—the new container comprises the current scope. If another service is invoked while that container is open, the variables returned by the from the service are put into another container, which is placed inside the previous container, and so forth.

Note: Besides the %invoke% tag, certain other tags (e.g., %loop%) implicitly switch scope. This behavior is noted in the tag descriptions in Tag Descriptions.

Why Does Scope Matter?

Understanding (and controlling) the scope within a DSP is important for two reasons:
  • Only those variables that are within the current scope are passed to a service that you invoke in a DSP. So, to ensure that a service receives all the variables it needs at run time, you must make sure that all those variables are within the scope. For more information about passing parameters to and within a DSP, see Passing Parameters with a DSP.
  • Only those variables that are within scope can be addressed without qualifiers. (See Referencing Variables In and Out of Scope.) Moreover, except for the initial scope (whose variables exist for the entire life of a DSP), certain tags, such as the %end% tag, cause the current scope to close and discard the variables within it.

Ending the Scope of the Invoke Action

The %end% element in the %invoke%…%end% construct ends the scope for that invoke. It marks the point in the DSP where the variables associated with that construct are dropped and scope reverts to the previous level.

The following example shows a DSP that invokes two services in sequence. In this DSP, both services receive the variables from the initial scope as input. The two %invoke% blocks are highlighted in bold in the sample.

 <HTML>   
 <HEAD>  
 <title>Order Tracking System</title>  
 </HEAD>  
 <!--User passes in order number in param named oNum> -->  
 <!--The initial scope contains only <oNum>     -->  
   
 %invoke orders:getShipInfo%  
 <!--Scope switches to results
of getShipInfo      -->  
 <!--You can reference variables
in the initial scope -->  
 <!--with a relative addressing
qualifier     -->  
   <p>  
   Order: %value /oNum%<br>  
   Date Shipped: %value shipDate%<br>  
   Carrier: %value carrier% %value
serviceLevel%  
   </p>  
 %endinvoke%  
   
 <!--Scope reverts to the initial scope     -->  
 <!--Results from getShipInfo have been discarded  -->  
 <!--and cannot be accessed beyond this point    -->  
  
 %invoke orders:getCustInfo%  
 <!--Scope switches to results
of getCustInfo    -->  
 <!--You can reference variables
in the initial scope-->  
 <!--with a relative addressing
qualifier    -->  
    <table>  
    <tr><td>Company:</td>
  <td>%value companyName%</td></tr>  
    <tr><td>Phone:</td>
  <td>%value phoneNum%</td></tr>  
    <tr><td>Address:</td>
  <td>%value StreetAddr1%<br>  
                   %value StreetAddr2%</td></tr>  
    <tr><td></td>     <td>%value
city%, %value state%</td></tr>  
    <tr><td></td>     <td>%value
postalCode%</td></tr>  
    </table>  
 %endinvoke%  
   
 <!--Scope reverts to the initial scope     -->  
 <!--Results from getCustInfo have been discarded  -->  
 <!--and cannot be accessed beyond this point    -->  
 </BODY>  
 </HTML>
 <HTML>  
 <HEAD>  
 <title>Order Tracking System</title>  
 </HEAD>  
 <!--User passes in order number in param named <oNum> -->  
 <!--The initial scope contains only <oNum>     -->  
  
 %invoke orders:getShipInfo%  
 <!--Scope switches to results
of getShipInfo      -->  
 <!--You can reference variables
in the initial scope -->  
 <!--with a relative addressing
qualifier     -->  
   <p>  
   Order: %value /oNum%<br>  
   Date Shipped: %value shipDate%<br>  
   Carrier: %value carrier% %value
serviceLevel%  
   </p>  
 %invoke orders:getCustInfo%  
 <!--Scope switches to results
of getCustInfo     -->  
 <!--You can reference variables
in the initial scope -->  
 <!--and prior scope with relative
addressing qualifiers -->  
   <table>  
   <tr><td>Company:</td>
 <td>%value companyName%</td></tr>  
   <tr><td>Phone:</td>
 <td>%value phoneNum%</td></tr> <tr><td>Address:</td> <td>%valueStreetAddr1%<br>  
                %value StreetAddr2%</td></tr>  
   <tr><td></td>    <td>%value
city%, %value  
                state%</td></tr>  
   <tr><td></td>    <td>%value
postalCode%</td></tr>  
   </table>  
 %endinvoke%  
 <!--Scope reverts back to results
of getShipInfo     -->  
 <!--Results from getCustInfo
have been discarded     -->  
 <!--and cannot be accessed beyond
this point     -->  
 %endinvoke%  
  
 <!--Scope reverts to the initial scope     -->  
 <!--Results from getShipInfo have been discarded  -->  
 <!--and cannot be accessed beyond this point     -->  
 </BODY>  
 </HTML>

Referencing Variables In and Out of Scope

You can refer to variables that are in the current scope directly—without any qualifiers. To reference a variable that is out of scope, you must use the following directory-like notation to describe its position relative to either the current scope or the initial scope.
Use this notation... To...
variableName Reference a variable in the current scope. For example: shipNum.
../variableName Reference a variable one or more levels above the current scope. For example:
../oNum One level above
../ ../oNum Two levels above
/variableName Reference a variable in the initial scope. For example: /oNum.
recName/variableName Reference a variable within a specific document. For example:
buyerInfo/state Selects the state element from the document buyerInfo in the current scope
../buyerInfo/oNum Selects the state element from the document buyerInfo one level above current scope

Passing Parameters with a DSP

You use the standard HTTP “GET” and “POST” methods to pass input parameters to a DSP. In a browser-based client, you usually do this with an HTML form. For example, if you were creating an order-tracking application, you might create a form that prompts the user for an order number and invokes a DSP that returns the shipping status of that order.

Figure 1. You can use an HTML form to pass input to a DSP

Use an HTML <FORM> tag to invoke a DSP. Then, use HTML <INPUT> tags to pass input parameters to it.

 <HTML>  
 <HEAD>  
 <TITLE>Order Tracking System</TITLE>  
 </HEAD>  
 <BODY BGCOLOR="#FFFFCC">  
 <H1>Shipping Information</H1>  
 <HR>  
 <FORM ACTION="/ORDER_TRAK/getorderinfo.dsp"
METHOD="GET">  
  <P>Enter Order Number  <INPUT TYPE="TEXT" NAME="oNum"> <BR>  
  <INPUT TYPE="HIDDEN" NAME="action"
VALUE="shipinfo">  <BR>  
  <INPUT TYPE="SUBMIT" VALUE="Submit">  
  </FORM>  
  
 <HR>  
 </BODY>

When the DSP is invoked, its initial scope encompasses two parameters: oNum and action. Services that you invoke within this scope receive an IData object containing these two elements.

The following code shows the contents of the DSP (getorderinfo.dsp) invoked by the previous example. It uses the value in action to conditionally execute a section of the DSP that invokes the service. (For more information about using the %switch% tag to conditionally execute a section of code, see Building Conditional Blocks with the %switch% Tag.)

<HTML>  
<HEAD>  
<title>Order Tracking System</title>  
</HEAD>  
<BODY BGCOLOR="#FFFFCC">  
  
<!--User passes in order number in param named <oNum> -->  
<!--and requested action in <action>      -->  
  
<H1>Order Tracking System</H1>  
%switch action%  
 %case ‘shipinfo’%  
  %invoke orders:getShipInfo%  
  <p>  
  Order: %value /oNum%<br>  
  Date Shipped: %value shipDate%<br>  
  Carrier: %value carrier% %value serviceLevel%  
  </p>  
  %endinvoke%  
%case ‘orderinfo’%  
  %invoke orders:getOrderInfo%  
.  
.  
.

Passing Parameters Between DSPs

Because HTTP does not preserve variables from one request to another, to pass data from one DSP to another, you must explicitly set those values in the documents that you return to the requestor. For example, let’s say you want to allow your user to view or edit the shipment displayed by the order-tracking DSP above. To do this, you must return a document containing links to the DSPs that perform these tasks, and these DSPs will need the order number (oNum) that the user submitted on the original page. To pass the order number to these DSPs, you must put oNum in the page you return to the client.

The following example shows two ways in which you can build a DSP that will pass a variable to another DSP. The first portion of code in bold illustrates how you can pass a parameter in a hidden input element. The second portion of code in bold illustrates how you can pass a parameter as a name-value pair in a link to a DSP.

<HTML>  
<HEAD>  
<title>Order Tracking System</title>  
</HEAD>  
<BODY BGCOLOR="#FFFFCC">  
  
<H1>Order Tracking System</H1>  
<!--User passes in order number in param named <oNum> -->  
<!--and requested action in <action>        -->  
%switch action%  
  %case ‘shipinfo’%  
  %invoke orders:getShipInfo%  
   <H2>Shipping Information for Order %value /oNum%</H2>  
   <P>Date Shipped: %value shipDate%<BR>  
   Carrier: %value carrier% %value serviceLevel%  
   </P>  
   <HR>  
   %ifvar shipDate -isnotempty%  
    <FORM ACTION="/ORDER_TRAK/editshipinfo.dsp" METHOD="get">  
    <P><B>Change this Shipment:</B></P>  
    <P><INPUT TYPE="RADIO" NAME="action" VALUE="edit">  
     Edit Shipment Details</P>  
    <P><INPUT TYPE="RADIO" NAME="action" VALUE="cancel">  
     Cancel this shipment</P>  
     <INPUT TYPE="SUBMIT" VALUE="Submit">  
    <INPUT TYPE="HIDDEN" NAME="oNum" VALUE="%value /oNum">  
    </FORM>  
    <HR>  
  %endifvar%  
  <P><A HREF="/ORDER_TRAK/getorderinfo.dsp  
    ?action=orderinfo&oNum=%value /oNum%">View Entire Order</A></P>  
%endinvoke%  
%case ‘getorder’%  
 %invoke orders:getOrderInfo%  
 .  
 .  
 .

Passing Parameters Between Services within a DSP

To pass data between services within a DSP, you can use any of the following techniques:
  • Invoke the service that needs the parameter within the scope of the service that produces the parameter. When a service is invoked in a DSP, it receives all of the variables that are “in scope” at the point where it is invoked. For an example of this, see the sample code on Ending the Scope of the Invoke Action.
  • Use the %rename% tag to copy a variable that is out of scope into the current scope. For details and examples, see the %rename% tag description on %rename%.
  • Use the %scope% tag to add a variable to the current scope and specify its value. For details and examples, see the %scope% tag description on %scope%.

Catching Errors

If you want your DSP to react in a specified way when the invoked service fails, include an %onerror% tag within your %invoke%…%end% construct. The code in the %onerror% block executes only if an exception occurs while the service executes or the service returns an error.

When the %onerror% block executes, the scope contains the following values:
Key... Description
error A String containing the Java class name of the exception that was thrown (e.g., com.wm.app.b2b.server.AccessException).
errorMessage A String containing the exception message in English, regardless of the locale of the server or client.
localizedMessage A String containing the exception message, translated into the language used by the client that invoked the DSP.
errorInput The IData object that was passed to the invoked service.
errorOutput The IData object returned by the invoked service. If the service returned an error, errorOutput will contain $error and any other variables that were in the pipeline when the service ended.
Important: If the service experiences an exception (i.e., the server is not able to execute it successfully), errorOutput will not be exist. This variable is only produced when the service returns an error.
errorService The name of the invoked service.

The following example shows how you might use an %onerror% clause to return an error message to the user.

 .  
 .  
 .  
 %invoke orders:getShipInfo%  
  <H2>Shipping Details for Order %value /oNum%</H2>  
  <P>Date Shipped: %value shipDate%<BR>  
  .  
  .  
  .  
 %onerror%  
  
  <HR>  
  <P><FONT COLOR="#FF0000">The
Server could not process your request  
  because the following error occurred.
Contact your server  
  administrator.</FONT></P>  
  <TABLE WIDTH="50%" BORDER="1">  
  <TR><TD><B>Service</B></TD><TD>%value
errorService%</TD></TR>  
  <TR><TD><B>Error</B></TD><TD>%value
Error% &nbsp;  
            %value errorMessage%</TD></TR>  
  </TABLE>  
  <HR>  
  
 %endinvoke%  
   .  
   .  
   .

Extracting Results from an Array Variable

If a service returns an array variable—such as a String list, a String table, or a document list—to a DSP, you use the %loop% tag with a variableName to extract values from the elements in the array.

When you use %loop% on a document variable, the scope within the loop block automatically changes to encompass just those elements within the specified document.

The following example shows a loop that extracts values from a document list (called items) that is returned by the service named orders:getOrderInfo.

 %invoke orders:getOrderInfo%  
  <P>This shipment contains the following items</P>  
  <TABLE WIDTH="90%" BORDER="1">  
  <TR><TD>Number</TD><TD>Qty</TD><TD>Description</TD><TD>Status</TD></TR>  
  
 %loop items%  
  <TR>  
  <TD>%value stockNum%</TD>  
  <TD>%value qty%</TD>  
  <TD>%value description%</TD>  
  <TD>%value status%</TD>  
  </TR>  
 %endloop%  
  
  </TABLE>  
 %endinvoke%  
  .  
  .  
  .

For additional information about the %loop% tag, see the %loop% tag description on %loop%.

Extracting Results from a Document

To extract results from a document (i.e., an IData object), you use the %loop% tag with the -struct option to execute a block of code once for each key in the structure.

The following example shows how you would extract values from each key in a document named buyerInfo.

 %invoke orders:getOrderInfo%  
  <P>Buyer:</P><P>  
  %loop -struct buyerInfo%  
   %value%<BR>  
  %endloop%   
  
  </TABLE>  
   .  
   .  
   .

Using the %loop% Tag to Examine the Current Scope

If you use the –struct option without specifying the name of a document, the loop executes once for each element in the current scope. During testing and debugging, you may want to use this technique to examine the variables and their values at a particular point in the DSP. The following example shows the code you would use to display the name of each key and its contents in the current scope.

   .  
   .  
   .  
  
 <P>  
  %loop -struct%  
   %value $key% %value%<BR>  
  %endloop%  
 </P>  
   .  
   .  
   .

Conditionally Executing Blocks of Code

There are two tags you can use to conditionally execute code in a DSP: %ifvar% and %switch%. Both tags selectively execute a block of code based on the existence or value of a variable at run time.

Building Conditional Blocks With the %ifvar% Tag

The %ifvar% tag is similar to an “if…then…else” expression in other programming languages. You use it to denote a block of code that is to be executed only when a specified variable exists or contains a value that you specify.

The basic format of the %ifvar% tag is as follows, where variableName specifies the name of the variable that will be evaluated at run time:

%ifvar variableName%  
  Block of Code  
[%else%  
  Block of Code]  
%end%
Example
   .  
   .  
   .  
 <!--Check for presence of backordered items in the order -->  
 <!--and display if they exist                 -->  
   %ifvar backItems%  
     <p>Backordered Items  
     %loop backItems%  
      %value%<BR>  
     %endloop%  
   %endifvar%  
  
   .  
   .  
   .

Testing for a Particular Value

In the preceding example, the enclosed block of code executes if a variable named backItems exists in the current scope. To test for the content of a variable, you can apply the following options to the %ifvar% tag.
Use this option... To...
-isnull Test whether the specified variable exists and is null.
-notempty Test whether the specified variable contains a value (i.e., the value is not null or empty).
equals(‘anyString’) Test whether the specified variable contains a specific value. (variableName must be a String variable to use this option.)
vequals(refVariable) Test whether the value of the specified variable matches the contents of another variable in the pipeline.

The following example shows an %ifvar%…%else%…%end% construct that executes one of two blocks, depending on the contents of a variable named clubMember.

  .  
  .  
  .  
 %invoke orders:getShipInfo%  
  <H2>Shipping Details for Order %value /oNum%</H2>  
  <P>Date Shipped: %value shipDate%<BR>  
   .  
   .  
   .  
  %ifvar clubMember equals(‘Y’)%  
   %include membershipterms.txt%  
  %else%  
   %include nonmembershipterms.txt%  
  %endifvar%  
  
 %endinvoke%  
   .  
   .  
   .

For additional information about the %ifvar% tag, see the %ifvar% description on %ifvar%.

Building Conditional Blocks with the %switch% Tag

You can use the %switch% tag to construct a conditional expression based on the value of a specified variable. The %switch% tag allows you to define a separate block of code (a case) for each value that a variable can take at run time. You use this tag instead of %ifvar% when you have more than two possible paths of execution. (You can also handle multiple paths of execution by building multiple %ifvar% expressions, however, the %switch% tag is much easier to use and maintain for this purpose.)

The basic format of the %switch% tag is as follows, where variableName specifies the name of the variable you want to evaluate at run time and switchValue is the value that will cause a case to execute:

%switch variableName%  
 %case ‘switchValue’%  
  Block of Code  
 %case ‘switchValue’%  
  Block of Code  
  .  
  .  
  .  
[%case%  
  Default Block
of Code]  
%end%

At run time, the DSP Processor evaluates each %case% block in order, and executes the first block whose switchValue matches the value in variableName. After processing the code within that block, the DSP Processor skips the remaining cases in the %switch% construct.

The following example shows an %switch% construct that executes one of two cases, depending on the contents of a variable named action.

   .  
   .  
   .  
%swtich action%  
 %case ‘shipinfo’%  
  %invoke orders:getShipInfo%  
    .  
    .  
    .  
   %endinvoke%  
  %case ‘vieworder’%  
   %invoke orders:getOrderInfo%  
    .  
    .  
    .  
  %endinvoke%  
%endswitch%

Specifying a Default Case

If you want to specify a block of code that executes when all other cases are not true, include a case without a switchValue. The following example illustrates how to create a default case by omitting switchValue and putting the case at the end of the %switch% construct.

   .  
   .  
   .  
 %switch acctType%  
  %case ‘Platinum’%  
   %include platorderform.html%  
  %case ‘Gold’%  
   %include goldform.html%  
  %case%  
   %include regorderform.html%

If you include a default case, you must put it at the end of the switch construct. For additional information about using the %switch% tag, see the %switch% tag description on %switch%.

Inserting Text Files in a DSP

The %include% tag allows you to insert a text file in a DSP. When you use the %include% tag, the DSP Processor inserts the specified file and evaluates its contents (and processes any tags that it contains) from top to bottom at run time.

The basic format of the %include% tag is as follows, where fileName specifies the name of the file that you want to insert into the DSP. (If fileName is not in the same directory as the DSP, you must specify its path relative to the DSP as shown by the example.)

  %include fileName%

Example

  .  
  .  
  .  
%switch acctType%  
 %case ‘Platinum’%  
  %include forms\platorderform.txt%  
 %case ‘Gold’%  
  %include forms\goldorderform.txt%  
 %case%  
  %include forms\regorderform.txt%  
%endswitch%

When you insert a file, it inherits the scope that is current at the point where you call it. For additional information about the %include% tag, see the %include% tag description on %include%.

Specifying a List of Permitted URLs for Redirection

Use the %validConst% tag to specify external URLs that Integration Server will allow for redirection from the page. The following example shows how to use the %validConst% tag to specify the URL “http://example.com” as a valid URL for redirection.

Example

  .  
  .  
  .  
%validConst url(http://example.com)%  
%endvalidConst%  
  .  
  .  
  .

If you want to allow more than one URL for redirection, you can specify a comma-separated list of URLs. The following example shows how to use the %validConst% tag to specify the URLs “http://example.com”, “http://example.org”, and “http://example.net” are valid for redirection.

Example

  .  
  .  
  .  
%validConst url(http://example.com,http://example.org,http://example.net)%  
%endvalidConst%  
  .  
  .  
  .

Arbitrarily Processing DSP Tags

Integration Server automatically processes DSP tags when a DSP is requested via HTTP. You can also process the tags in a string of text at any arbitrary point during a service using the services in the pub.report folder. When you use these services, tags are processed against the variables that are in the pipeline at run time.

For information about using the services in the pub.report folder, see webMethods Integration Server Built-In Services Reference.