Lotus Forms Server - API 4.0

First Edition

Published December 2010

About this edition

Printing

When you print this document some of the style elements are removed to create a better print output. Here are a few tips about printing:
  • The document length may exceed the browser's print capability. Microsoft Internet Explorer has demonstrated the ability to print large files successfully.
  • This document is long. Use print preview to determine the printed page length.
  • You can highlight a section of the document and then choose to only print the selected content.

Working offline

You can save a local copy of this document from your browser. Each browser has different menus and menu options. Consult the browser help if you need assistance saving the document locally.

Submitting feedback

If you would like to provide feedback about this document, see the Lotus Documentation Feedback Web site.

IBM Lotus Forms Server – API

The IBM® Lotus® Forms Server – API provides low level access to XFDL forms in Java™, C, and COM.

Using the API, you can develop applications that process XFDL forms, including XForms data models within XFDL forms. You can create and manage applications that analyze, route, validate, and create electronic forms.

The API also contains the Function Call Interface (FCI) library. Using the FCI, you can extend the capabilities of your forms by adding custom XFDL functions that are available to forms designers for use at run time.

What's new in IBM Lotus Forms Server – API 4.0

This version of Lotus Forms API has several updates, including performance improvements, additional platform support, and support of new features in XFDL 8.0.

Support for additional platforms

Support for WebSphere® Application Server 7.0 and zLinux has been added. The support for i5/OS®, AIX®, and Linux® platforms has also been updated. See API system requirements for the complete list of currently supported platforms.

Support for XFDL 8.0

The API supports the latest version of XFDL markup.

Updated to latest ICU

Locale and time zone information in the API has been updated with version 4.4 of the International Components for Unicode (ICU) library.

API release notes

The release notes provides a summary of new features and improvements, installation information, and descriptions of known limitations, problems, and workarounds.

About this release New features and improvements What's new in IBM Lotus Forms Server – API 4.0
Backward compatibility information API system requirements
Installation, migration, upgrade, and configuration information System requirements API system requirements
Installation instructions Installing Lotus Forms API
Known limitations, problems, and workaround Troubleshooting Troubleshooting and support
Limitations, problems, and workarounds API technotes and flashes
Contacting customer support Customer support Lotus Forms Support web page

Installing Lotus Forms API

These procedures contain instructions for installing the API as a single component that is independent of other Lotus Forms Server products.

Installing Lotus Forms API on Windows

You can install the API using the installer in graphical mode or in console mode.

You must be logged in as a user belonging to the Administrators group when running the installer.

This procedure assumes that you will be using the graphical mode to install the API. To run the installer in console mode, at Step 2 open a terminal window and change to the temporary directory. If you are installing on a 32-bit computer, at the command line type LFServer_400_Win32.exe -i console. If you are installing on a 64-bit computer, at the command line type LFServer_400_Win64.exe -i console. The console procedure is almost identical except that you use the keyboard instead of the mouse to enter data and to navigate through the screens.

To install the API in graphical mode:

  1. Extract the .zip file to a convenient location on your server. It is best to create a new folder for the extracted files and folders.
  2. Double click the installer.
    • On 32-bit systems: LFServer_400_Win32.exe
    • On 64-bit systems: LFServer_400_WinX64.exe
    The installer begins initializing, and a few seconds later the installer window opens.
  3. Select a language and click OK.
  4. Click Next and read the license agreement.
  5. Click I accept the terms in the license agreement then click Next. The installer configures the IBM Autonomic Deployment Engine. If the Autonomic Deployment Engine is not on your system, the installer installs it for you. When configuration is complete, the Select Installation Directory panel opens.
  6. Enter or select a location for the API then click Next. The Select Server Components panel opens.
  7. Select Forms Application Components then click Next. The Optional Deployment Settings panel opens.
  8. If you want the installer to deploy the API component to an existing WebSphere Application Server:
    1. Select Deploy Forms API then click Next. The API Deployment panel opens.
    2. Enter the location of the WebSphere Application Server then click Next. The WebSphere Application Server Settings panel opens, and the installer populates the profile, cell, node, and server information fields.
    3. Select the profile that you want to use, and make sure that the cell, node, and server information is correct.
      Note: Do not select the Deployment Manager profile. Select an application server profile. For example, AppSrv01.
    4. Enter the User Name and Password information, then click Next. After the installer verifies the WebSphere Application Server information, the Pre-Installation Summary panel opens.
    Note: If you are not sure about this option, or you do not have the information available, do not select it. You can run the installer again at a later time.
  9. Click Install.
After the API is installed, you must configure it for use.

Installing Lotus Forms API on AIX, IBM i, Linux, and Solaris

You can install the API using the installer in graphical mode or in console mode. To use the graphical installer, you must have X-Windows.

You must be logged in as root user when running the installer.
If you are installing on Solaris: Make sure that you have the libstdc++.so.6 library before installing the API. To obtain and install libstdc++.so.6, download the following file: ftp://ftp.sunfreeware.com/pub/freeware/sparc/10/libgcc-3.4.6-sol10-sparc-local.gz 
If you are installing on AIX: Make sure that you have the latest version of the XL C runtime installed. To check the version, at the command line type:
lslpp -La | grep -i xlC

On AIX 5.3, the version must be 8.0 or greater. On AIX 6.1 the version must be 9.0 or greater.

To download and install the latest version of the XL C runtime PTF for AIX, see http://www-01.ibm.com/support/docview.wss?uid=swg21215669

If you are installing on IBM i: You must have a user profile that has *ALLOBJ and *SECADM special authorities. 

This procedure assumes that you will be using the graphical mode to install the API. The console procedure is almost identical except that you use the keyboard instead of the mouse to enter data and to navigate through the screens.

Table 1 shows the command that you issue in Step 2 to start the installer for your operating system.

Table 1. Installer executable file names
Operating system 64-bit 32-bit

AIX

./LFServer_400_AIXPPC64.bin

./LFServer_400_AIXPPC32.bin

IBM i (i5/OS)

./LFServer_400_i5OS64.jar

./LFServer_400_i5OS.jar

Linux

./LFServer_400_LinuxX64.bin

./LFServer_400_Linux.bin

zLinux

./LFServer_400_LinuxS390x.bin

./LFServer_400_LinuxS390.bin

Solaris

./LFServer_400_SolarisSparc64.bin

./LFServer_400_SolarisSparc.bin

IBM i: The installer is available in console mode only. In the Qshell environment, change to the directory that contains LFServer_400_i5OS.jar and issue the following command:
  • On 64-bit systems:
    • On V6R1:/QIBM/ProdData/Java400/jdk15/bin/java -jar LFServer_400_i5OS.jar -i console
    • On V7R1:/QOpenSys/QIBM/ProdData/JavaVM/jdk60/64bit/bin/java -jar LFServer_400_i5OS.jar -i console
  • On 32-bit systems:
    • On V6R1:/QIBM/ProdData/Java400/jdk15/bin/java -jar LFServer_400_i5OS.jar -i console
    • On V7R1:/QOpenSys/QIBM/ProdData/JavaVM/jdk60/32bit/bin/java -jar LFServer_400_i5OS.jar -i console

To install the API in graphical mode:

  1. Locate the zip file that applies to your operating system, and extract all of the files and folders to a convenient temporary directory on your system.
  2. Open a terminal window and start the installer by running the executable for your operating system. The installer begins initializing, and a few seconds later the installer window opens.
  3. Select a language and click OK.
  4. Click Next and read the license agreement.
  5. Click I accept the terms in the license agreement then click Next. The installer configures the IBM Autonomic Deployment Engine. If the Autonomic Deployment Engine is not on your system, the installer installs it for you. When configuration is complete, the Select Destination Folder panel opens.
  6. Enter or select a location for the API then click Next.
  7. Choose an installation type set then click Next.
  8. Select API then click Next.
  9. If you want the installer to deploy the API to an existing WebSphere Application Server or WebSphere Process Server:
    1. Select the check box then click Next.
    2. Enter the location of the server then click Next. The WebSphere Application Server Settings panel opens, and the installer populates the profile, cell, node, and server information fields.
    3. Select the profile that you want to use, and make sure that the cell, node, and server information is correct.
    4. Enter the User Name and Password information, then click Next. The installer verifies the WebSphere Application Server information.
    Note: If you are not sure about this option, or you do not have the information available, do not select it. You can manually deploy to a WebSphere server after installing the API. See Configuring WebSphere Application Server to use Lotus Forms API.
  10. Click Install.
After the API is installed, you must configure it for use.

Uninstalling the API

  1. Run the uninstall program.
    If you are using Windows®:
    1. Click Start > Settings > Control Panel > Add or Remove Programs
    2. Click IBM Lotus Forms Server 4.0 - API
    3. Click Change/Remove
    If you are using AIX:
    1. At the command prompt, run the uninstall script. The script is called uninstall. If you installed the API in the default location, the command is:
      /usr/IBM/LotusForms/Server/4.0/_uninst/FormsServer/uninstall -i console
    If you are using Linux, or Solaris:
    1. At the command prompt, run the uninstall script. The script is called uninstall. If you installed the API in the default location, the command is:
      /opt/IBM/LotusForms/Server/4.0/_uninst/FormsServer/uninstall -i console
  2. Manually remove files that you created during the installation of the API. The files are PureEdgeAPI.ini and prefs.config.
  3. Manually remove directories and files under the install directory tree that could not be removed by the uninstaller.
  4. Update the environment variables to remove the API from the system path.
    Operating system Environment variable
    AIX LIBPATH
    Linux or Solaris LD_LIBRARY_PATH
    Windows PATH

Configuring

Configuring the API on Windows

Setting the Windows PATH environment

You must add the location of the dynamic load libraries (DLLs) to the Windows PATH environment variable.

Note: If you are installing the API for use with WebSphere Application Server, you do not need to perform this task.

To set the Windows PATH environment variable for the API:

  1. Right click My Computer > Properties. The System Properties window opens.
  2. Click Advanced.
  3. Click Environment Variables. The Environment Variables window opens.
  4. In the System variables list, select the Path variable, then click Edit. The Edit System Variable window opens.
  5. At the end of the list In the Variable value field, type the location of the API DLLs. The default location of the DLLs is:
    C:\Program Files\IBM\Lotus Forms\Server\4.0\API\redist\Win32
    Important: Make sure that you use a semicolon as a separator between values.
  6. Click OK on each of the open windows.

Updating the PureEdgeAPI.ini file

You must create the PureEdgeAPI.ini file if it does not exist. If the file already exists then you must update it to add the location of the new API.

The contents of the PureEdgeAPI.ini file determine which applications use which version of the API. The API will not work without a PureEdgeAPI.ini file.

The file can exist in one or more of the following locations:
  • the calling application's folder
  • the current working folder
  • the C:\WINDOWS folder
When the API starts, it searches the folders in the order shown and uses the first PureEdgeAPI.ini file that it finds.
Note: If you chose to automatically deploy the API to WebSphere Application Server during installation of the API, then the PureEdgeAPI.ini file already exists. The installer creates the file and adds the location of the API for you. You should verify that the location is correct.

To update the PureEdgeAPI.ini file:

Go to the folder where you want the PureEdgeAPI.ini file to exist.
  • If no PureEdgeAPI.ini file exists, create the file with a text editor and add the following lines:
       [API]
       8.0.* = C:\Program Files\IBM\Lotus Forms\Server\4.0\API\redist\Win32\PureEdge\80
  • If a PureEdgeAPI.ini file already exists, make sure that the following line is in the [API] section:
       8.0.* = C:\Program Files\IBM\Lotus Forms\Server\4.0\API\redist\Win32\PureEdge\80
Note: The file path shown is the default installation location. If you did not install the API in the default location, then you must adjust the file path to match the location of the API on your system.

Configuration settings in prefs.config

The API can use a configuration file called prefs.config to set several properties. Normally, you do not need this file because the default settings are adequate for most purposes.

If the prefs.config file exists, it is in one or more of the following locations:
C:\Documents and Settings\<username>\Application Data\PureEdge\API 8.0\Prefs\prefs.config
C:\Documents and Settings\All Users\Application Data\PureEdge\API 8.0\Prefs\prefs.config

When determining the configuration, the API first looks at the configuration file in the user specific folder, then the file in the All Users folder. The API will read both configuration files, but any settings in the user specific folder will override settings in the All Users folder.

The configuration file uses tag value pairs to set the following properties:

Tag Setting
  The path to your Netscape certificate store. If the path is not provided, the API will attempt to locate the certificate store automatically.
  The path to your Netscape security libraries. To determine this path, search for nss3.dll.
javaPath The path to your Java virtual machine. If you do not provide a path, the API will attempt to locate the Java VM automatically. In most cases, automatic detection will succeed under Windows.
Note: If the calling program is running in an application server such as WebSphere Application Server, or in a portal server such as WebSphere Portal, the javaPath must point to the same JVM that the application server uses.
checkCRLDistribution Points An on or off value. If on, the API will check CRL distribution points whenever verifying a digital certificate. This requires Internet access, and will slow the verification process. If off, the API will only use locally stored CRLs to verify certificates.
javaVM Sets the default Java Virtual Machine. Once set, the API will use that JVM if it is available, otherwise it will locate the latest JVM installed on the computer.

Set this to the string that the JVM uses to register itself. For example, "Sun VM <version>". The version is guaranteed to include a major and minor number, and may include further information, such as a maintenance number, build number, and so on.

Since it can be difficult to get an exact match, you can use the * wildcard in the version string. For example, you might use the following string:

   Sun VM 1.4*

This will match any version beginning with 1.4, such as "1.4.2_03 JDK" or "1.4 JDK". When there are multiple matches, the match that will be selected is indeterminate, so it is best to be specific.

Additionally, the API always chooses the JDK over the JRE. For example, if you search for "Sun VM 1.4*", and you have "Sun VM 1.4.2_03 JDK" and "Sun VM 1.4.2_03 JRE" installed, the API will use the JDK.

Note that this setting is for Windows only.

jvmOptions.x Allows you to pass configuration options to the Java VM. Each option must have its own numbered entry as shown:
   jvmOptions.1 = <config setting 1>
   jvmOptions.2 = <config setting 2>

By default, the API does not pass any configuration options.

javaIgnoreUnrecognized An on or off value. If on, the Java VM will ignore unrecognized options used in the javaOptions setting. If off, the Java VM will report unrecognized options in the javaOptions setting. Default is off.
domspooltodiskthreshold

The in-memory size of form enclosures, in bytes. Enclosures that are greater than this threshold are removed from memory and spooled to a temporary file in the system temp folder.

The default size is 32768 bytes. If you do not want enclosures to be spooled to disk, set the size to 0 (zero).

Note that the size is the space that the enclosure takes when in memory; its file size might be different.

schemasFolder

Allows you to specify the path to the schemas folder for any external schemas required by an application or its forms. If no schemasFolder setting is specified, and an external schema is referenced, the API will look for a schemas folder in the same directory as the currently running application.

defaultDateFormat

Allows you to specify the format to assume for ambiguous dates that are entered by users. Valid settings are: DayMonthYear, MonthDayYear, YearMonthDay

The default is MonthDayYear. For example, by default the date 01/02/09 will be interpreted as January 2, 2009.

To configure the API, open the prefs.config file in a text editor and set the preferences accordingly. If you do not include a particular setting, the default is used instead. For example, your prefs.config file might look like this:

   checkCRLDistributionPoints = off

In this case, the API will automatically detect both the location of the Netscape Profile and the location of the Java virtual machine. However, the API will not check CRL distribution points and will use the default configuration options for the Java VM.

Registering the COM dynamic link library

If you plan to use the COM API, you must register the pe_com.dll file with Windows.

To register the COM DLL:

  1. Open a DOS shell or command prompt.

    For example, on Windows 2000 select Start > Programs > Accessories > Command Prompt

  2. On the command line, type:
    regsvr32 "<path to pe_com.dll>"
    Note: If the path has spaces in it, you must use quotes.
    For example:
    regsvr32 "C:\Program Files\IBM\Lotus Forms\Server\4.0\API\redist\Win32\pe_com.dll"

This registers the COM DLL.

Configuring the API on AIX, Linux, and Solaris


Setting the library path on AIX, Linux, and Solaris

You must add the location of the API library files to the library path for your operating system. You must also ensure that the location of the Network Security Services libraries is on your path.

Note: If you are installing the API for use with WebSphere Application Server, you do not need to perform this task.

If you are using AIX, the environment variable that you set is LIBPATH. If you are using Linux or Solaris, the environment variable that you set is LD_LIBRARY_PATH.

If you installed the API in the default location, the paths are as shown. Otherwise, you must set LIBPATH and LD_LIBRARY_PATH variables to match the location of the API on your system.

If you are using AIX, set your LIBPATH to the following directories:
/usr/IBM/LotusForms/Server/4.0/API/redist/AIX
/usr/IBM/LotusForms/Server/4.0/API/redist/AIX/PureEdge/80/system
<path to Network Security Services libraries>
If you are using Linux, set your LD_LIBRARY_PATH to the following directories:
/opt/IBM/LotusForms/Server/4.0/API/redist/Linux
/opt/IBM/LotusForms/Server/4.0/API/redist/Linux/PureEdge/80/system
<path to Network Security Services libraries>

If you are using Solaris, set your LD_LIBRARY_PATH to the following directories:

/opt/IBM/LotusForms/Server/4.0/API/redist/SunOS
/opt/IBM/LotusForms/Server/4.0/API/redist/SunOS/PureEdge/80/system
<path to Network Security Services libraries>

The Network Security Services libraries are required for creating and verifying electronic signatures. The libraries are installed with most Netscape and Mozilla products, including Firefox, SeaMonkey, and Mozilla Application Suite. They can also be obtained directly from mozilla.org. To find the location of this directory on your computer, search for the file libnss3.so.

Many methods exist of setting these paths; the method that you choose depends on the operating system, the interactive shell that you use, the preferences of the system administrator, or any other policies that might apply in your particular environment.

Updating the PureEdgeAPI.ini file on AIX, Linux, and Solaris

You must create the PureEdgeAPI.ini file if it does not exist. If the file already exists then you must update it to add the location of the new API.

The contents of the PureEdgeAPI.ini file determine which applications use which version of the API. The API will not work without a PureEdgeAPI.ini file.

The file can exist in one or more of the following locations:
  • the calling application's directory
  • the current working directory
  • the /etc directory
When the API starts, it searches the folders in the order shown and uses the first PureEdgeAPI.ini file that it finds.
Note: If you chose to automatically deploy the API to WebSphere Application Server during installation of the API, then the PureEdgeAPI.ini file already exists. The installer creates the file and adds the location of the API for you. You should verify that the location is correct.

To update the PureEdgeAPI.ini file:

Go to the directory where you want the PureEdgeAPI.ini file to exist.
  • If no PureEdgeAPI.ini file exists, create the file with a text editor and add one of the following lines, depending on your operating system:
    If you are using AIX:
       [API]
       8.0.* = /usr/IBM/LotusForms/Server/4.0/API/redist/AIX/PureEdge/80
    If you are using Linux:
       [API]
       8.0.* = /opt/IBM/LotusForms/Server/4.0/API/redist/Linux/PureEdge/80
    If you are using Solaris:
       [API]
       8.0.* = /opt/IBM/LotusForms/Server/4.0/API/redist/SunOS/PureEdge/80
  • If a PureEdgeAPI.ini file already exists, make sure that the correct <path to API> for your operating system is in the [API] section.
Note: The file path shown is the default installation location. If you did not install the API in the default location, then you must adjust the file path to match the location of the API on your system.

Configuration settings in prefs.config on AIX, Linux, and Solaris

The API can use a configuration file called prefs.config to set several properties. If you are using the API in Java, then you must set the location of the Java virtual machine. The default settings of the other properties are adequate for most purposes.

Important: If you chose to automatically deploy the API to WebSphere Application Server when you installed the API, then the prefs.config file already exists. The installer creates the file and adds the location of the JVM for you, in the javaPath setting. You should verify that the javaPath setting is correct.
The prefs.config file can be in one or more of the following locations:
/home/<username>/.PureEdge/API 8.0/prefs/prefs.config
/etc/PureEdge/API 8.0/prefs/prefs.config

When determining the configuration, the API first looks at the configuration file in the user-specific directory, then the file in the /etc/PureEdge/API 8.0/prefs directory. The API will read both configuration files, but any settings in the user-specific directory will override settings in the/etc/PureEdge/API 8.0/prefs directory.

Note: When creating these directories, remember that paths which include spaces must be enclosed in quotation marks. Also, ensure that you create permissions to access these directories using chmod a+r.

After you have installed the API, create the prefs.config file if it does not already exist. The file uses tag value pairs to set the following properties:

Tag Setting

overrideDefaultPathToNetscapeProfile

The path to your Netscape certificate store. If the path is not provided, the API will attempt to locate the certificate store automatically.

overrideDefaultPathToNetscapeSecurityLibraries

The path to your Netscape security libraries. To determine this path, search for a directory that contains libnss3.so and libnspr4.so.

rsaSecurityEngineNames

A comma-separated list of security engines that the API will query for RSA signature support. The default setting in API version 3.5 and later is:

rsaSecurityEngineNames = Netscape,CryptoAPI

To query all signature engines that are supported by the API, use the * wildcard. For example:

rsaSecurityEngineNames = *

If you use the * wildcard, it must be the only entry. The * wildcard is the behavior of API versions 3.0.1 and earlier.

If you are using the API on i5/OS, then you must either include the Java security engine in the list, or use the * wildcard. For example:

rsaSecurityEngineNames = Netscape,CryptoAPI,Java

If you specify an engine that is not supported on your platform, the API will ignore that entry.

javaPath

The path to your Java virtual machine.

If you are using the API from a C program, the javaPath can point to any JVM on your system.

If you are using the API from a Java program, the javaPath must point to the same JVM that the calling Java program uses.

If the calling program is running in an application server such as WebSphere Application Server, or in a portal server such as WebSphere Portal, the javaPath must point to the same JVM that the application server uses.

checkCRLDistribution Points

An on or off value. If on, the API will check CRL distribution points whenever verifying a digital certificate. This requires Internet access, and will slow the verification process. If off, the API will only use locally stored CRLs to verify certificates.

javaOptions

A space delimited list of configuration options that will be passed to the Java VM when it is started by the API. By default, the API does not pass any configuration options.

javaIgnoreUnrecognized

An on or off value. If on, the Java VM will ignore unrecognized options used in the javaOptions setting. If off, the Java VM will report unrecognized options in the javaOptions setting. Default is off.

domspooltodiskthreshold

The in-memory size of form enclosures, in bytes. Enclosures that are greater than this threshold are removed from memory and spooled to a temporary file in the system temp folder.

The default size is 32768 bytes. If you do not want enclosures to be spooled to disk, set the size to 0 (zero).

Note that the size is the space that the enclosure takes when in memory; its file size might be different.

schemasFolder

Allows you to specify the path to the schemas folder for any external schemas required by an application or its forms. If no schemasFolder setting is specified, and an external schema is referenced, the API will look for a schemas folder in the same directory as the currently running application.

defaultDateFormat

Allows you to specify the format to assume for ambiguous dates that are entered by users. Valid settings are: DayMonthYear, MonthDayYear, YearMonthDay

The default is MonthDayYear. For example, by default the date 01/02/09 will be interpreted as January 2, 2009.

To configure the API, open the prefs.config file in a text editor and set the preferences accordingly. If you do not include a particular setting, the default is used instead. For example, your prefs.config file might look like this:

   javaPath = /usr/java/jre/lib/sparc/libjava.so
   checkCRLDistributionPoints = off

In this case, the API will automatically detect the location of the Netscape Profile and will use the Java VM in the /usr/java/jre/lib/sparc/ directory. However, the API will not check CRL distribution points and will not send any configuration options to the Java VM.

Configuring WebSphere Application Server to use Lotus Forms API

You can deploy the API to WebSphere Application Server in one of two ways: automatically during installation, or manually after installation.

Important: Do not manually configure WebSphere Application Server if you chose to automatically deploy the API. You only need to manually configure WebSphere Application Server under one or more of these conditions:
  • you did not choose to automatically deploy the API during installation of the API
  • you are deploying the API in a managed node environment
Notes:
  1. If you are deploying the API in a managed node environment, you must run the installer on each machine that hosts one or more managed nodes, and then manually configure WebSphere Application Server. Do not automatically deploy the API during installation if you are using managed nodes.
  2. You must use the 32-bit versions of WebSphere Application Server and IBM WebSphere Portal when running on 64-bit systems. If you are using WebSphere Portal on AIX or Solaris, you must install the 32-bit version of WebSphere Application Server before installing WebSphere Portal. After you have installed WebSphere Application Server, run the WebSphere Portal install type that allows you to deploy to an existing WebSphere Application Server.
  3. If you are using AIX, Linux, or Solaris, you must also set the javaPath parameter in the prefs.config file. The javaPath must point to the same JVM that WebSphere Application Server uses.
  4. Make sure that you configure the API before deploying the API to WebSphere Application Server. Specifically, make sure that a PureEdgeAPI.ini file exists.

Several steps are required to manually deploy the API to WebSphere Application Server:

Setting the WebSphere Variables

You must create environment variables for use in later configuration steps.

You cannot configure your system to use both the Classic and Streaming Java APIs. You must choose only one.

To set the WebSphere variables:

  1. In the WebSphere Integrated Solutions Console, go to Environment > WebSphere Variables.
  2. Use the drop-down list to set the scope. Select the node that contains the server that you are using.
  3. Click New. The New page opens.
  4. If you are using the Classic API:
    1. In the Name field, type LFS_API_DIR.
    2. In the Value field, type the folder in which you installed the API files.

      For example: C:\Program Files\IBM\Lotus Forms\Server\4.0\API\redist\Win32\

    3. Add a description then click OK, then click Save.
    4. Repeat the above steps to create an environment variable called LFS_API_LIB_DIR and point it to the folder that contains the API libraries.

      For example, ${LFS_API_DIR}\PureEdge\80\java\classes

  5. If you are using the Streaming API:
    Note: You cannot configure your system to use both the Classic and Streaming Java APIs. You must choose only one.
    1. In the Name field, type LFS_API_STREAM_LIB_DIR.
    2. In the Value field, type the folder that contains StreamingAPI.jar.

      For example, C:\Program Files\IBM\Lotus Forms\Server\4.0\API\redist\java

    3. Add a description then click OK, then click Save.

Setting the Shared Libraries

After setting the WebSphere variables, you must configure WebSphere Application Server so that it can access the API's shared libraries.

To set the shared libraries:

  1. In the WebSphere Integrated Solutions Console, go to Environment > Shared Libraries.
  2. Use the drop-down list to set the scope. Select the node that contains the server that you are using. This must be the same node that you selected when you set up the WebSphere variables.
  3. Click New to create a shared library.
  4. If you are using the Classic API:
    1. In the Name field, type LFS_API_LIB.
    2. In the Classpath field, enter the following files, one per line:
      • ${LFS_API_LIB_DIR}/pe_api.jar
      • ${LFS_API_LIB_DIR}/pe_api_native.jar
      • ${LFS_API_LIB_DIR}/commons-codec.jar
      • ${LFS_API_LIB_DIR}/xmlsec-1.4.1.jar
  5. If you are using the Streaming API:
    Note: You cannot configure your system to use both the Classic and Streaming Java APIs. You must choose only one.
    1. In the Name field, type LFS_Streaming.
    2. In the Classpath field, type ${LFS_API_STREAM_LIB_DIR}/StreamingAPI.jar.
  6. Click OK, then click Save.

Setting the Java Process Definitions

If you are using the Classic API, you must set the Java process definitions. If you are using the Streaming API, you do not need to set the Java process definitions.

To set the Java process definitions:

  1. In the WebSphere Integrated Solutions Console, go to the Environment Entries page for the server to which you are deploying the API.
    WebSphere version Environment Entries page location

    6.1

    Servers > Application servers > <server_name> > Java and Process Management > Process Definition > Environment Entries

    7.0

    Servers > Server Types > WebSphere application servers > <server_name> > Java and Process Management > Process Definition > Environment Entries
  2. Add or update the location of the API library files. The resource name depends on the operating system.
    Operating system Resource name

    Windows

    Add a PATH resource and point it to the API directories that contain .dll files. For example:

    ${LFS_API_DIR};${LFS_API_DIR}/PureEdge/80/system

    AIX

    Add a LIBPATH resource and point it to the API directories that contain .so files. For example:

    ${LFS_API_DIR}:${LFS_API_DIR}/PureEdge/80/system

    Solaris

    Add a LD_LIBRARY_PATH resource and point it to the API directories that contain .so files. For example:

    ${LFS_API_DIR}:${LFS_API_DIR}/PureEdge/80/system

    Linux

    Add a LD_LIBRARY_PATH resource and point it to the API directories that contain .so files. For example:

    ${LFS_API_DIR}:${LFS_API_DIR}/PureEdge/80/system

    IBM i

    Add a LIBPATH resource and point it to the API directories that contain .so files. For example:

    ${LFS_API_DIR}:${LFS_API_DIR}/PureEdge/80/system

    Note: If the PATH, LIBPATH, or LD_LIBRARY_PATH resources have already been defined, then append the API directories to the existing paths. Remember to use the correct separator; Windows uses a semicolon, but AIX, Linux, and Solaris platforms use a colon.

Setting the server class loader

You must add the location of the API to the WebSphere class loader.

To set the server class loader:

  1. In WebSphere Application Server, open the Classloader panel for your server.
    1. If you are using WebSphere Application Serverr 6.1: open Servers > Application servers > <server_name> > Java and Process Management > Classloader.
    2. If you are using WebSphere Application Server 7.0: open Servers > Server Types > WebSphere application servers > <server_name> > Java and Process Management > Classloader.
  2. If a class loader for your application server does not already exist, you must create it. To create a new class loader:
    1. Click New.
    2. If you are using WebSphere Application Server 6.1: From the Class loader order list, select Classes loaded with application class loader first and click OK then click Save.
    3. If you are using WebSphere Application Server 7.0: From the Class loader order list, select Classes loaded with local class loader first (parent last) and click OK then click Save.
  3. If you are using WebSphere Application Server 6.1:
    1. Select the class loader for your application server and click Libraries
    2. Click Add.
    3. From the Library Name list, select LFS_API_LIB.
    4. Click OK then click Save.
  4. If you are using WebSphere Application Server 7.0:
    1. Click the Classloader link.
    2. Click Shared library references.
    3. Click Add.
    4. From the Library Name list, select LFS_API_LIB.
    5. Click OK then click Save.

Additional usage notes

Additional form and application design notes for IBM Lotus Forms Server – API:
  • The Viewer and API cannot read forms that have a UTF-8 byte-order mark (BOM). Attempting to do so will produce the following error: Unable to load form: Invalid document structure.

    To prevent this problem: If you use a text editor to edit your forms, configure your editor so it does not add a BOM to UTF-8 documents. (See your text editor's documentation for details.)

    To remove a BOM from a form: Open the form in the Designer and save it.

  • If you are using a server application that notarizes signatures (that is, you are using the Authenticated Clickwrap or HMAC signature engine), when the user submits a signed form to the server, the CryptoAPI digital certificate may display a prompt on the server. Because the prompt is displayed on the server, where no person can respond to it, the server (or a thread on the server) may appear to hang.
  • If you use Mozilla-based web browsers, you should set up your server modules to specify that the web browser clear its cache before it posts a form submission. Some versions of Mozilla-based browsers cache posts. As a result, if a post of a form is interrupted for some reason and you submit the form a second time, the browser sends the cached (and incomplete) first post.
  • VBScript does not correctly support output parameters. Because of this, you must set all output parameters to null.

    In cases in which you would normally use vbNull, you must instead use "1", which is the constant value of vbNull. If you do not use "1", the function you are calling will not work correctly.

  • When building a C application that uses the API on AIX, Linux, or Solaris, ensure that you link with the libpe_cc.so library.
  • The C API and the COM API require Java to perform XML Digital Signature operations.
  • Under Solaris, you must link with the -Blocal linker option (or equivalent). This makes all of the symbols within the program local, so that loaded shared libraries cannot resolve against those symbols. If this linker flag is not given, and the application is using the Java support, one of the shared libraries loaded by the Java VM resolves against symbols defined in libpe_cc.so and causes a segmentation fault when that function is called.

Samples

Sample Applications for Windows

The API includes the following sample applications:

  • Calculate Age Sample
  • Form Sample (Classic C and Java APIs, plus Streaming Java API)
  • FCI Sample (Classic C and Java APIs only)
  • JSP Sample (Classic and Streaming Java APIs only)

These applications are provided to demonstrate the use of many of the functions in the API, and are useful for testing your API installation and development environment.

Note: To view the forms provided with these sample applications, you must have a licensed or evaluation copy of IBM Lotus Forms Viewer installed on your computer.

The Calculate Age Sample Application

The Calculate Age sample application demonstrates the most commonly used functions in the API.

This application reads a form called CalculateAge.xfd into memory, and reads the values for the year, month, and day of birth from the form. It then writes those values into a series of hidden fields that are used by a compute to determine the person's age. Once the values are written, the application writes the form as Output.xfd.

Running Calculate Age Under C

Compile the source code file calculateAge.c to produce an executable called calculateAge.exe. Then follow these steps to run the Calculate Age sample application:

  1. Using the Viewer, open the form called calculateAge.xfd located in the following folder:
       <API Installation Folder>\samples\Win32\form\demo\calculate_age\
  2. Change the name and birth date if you want, then save and close the form.
  3. Run calculateAge.exe.
    • This creates a form called output.xfd in the current folder.
  4. Open the output.xfd form, and check the result in the Age field.

Running Calculate Age Under Classic and Streaming Java

Follow these steps to set up and run the Calculate Age sample application under Java:

  1. Using the Viewer, open the form called calculateAge.xfd located in the folder:
       <API Installation Folder>\samples\java\form\demo\calculate_age\
  2. Change the name and birth date if you want, then save and close the form.
  3. Using your Java compiler, compile the file called calculateAge.java found in the current folder.
    • This produces a new class file called calculateAge.class.
  4. Run calculateAge.class.
    • This creates a form called output.xfd in the current folder.
  5. Open the output.xfd form, and check the number in the Age field.

Running Calculate Age For COM

The Calculate Age sample for COM is written in Visual Basic and the sample project files were generated using Microsoft® Visual Basic 6.0. To run the sample, follow these steps:

  1. Using the Viewer, open the form called CalculateAge.xfd located in the folder:
       <API Installation Folder>\samples\Win32\COM\demo\calculate_age\
  2. Change the name and birth date if you want, then save and close the form.
  3. Load the Calculate Age project files in Microsoft Visual Studio and compile them.
    • This produces a new executable called CalculateAge.exe.
  4. Run CalculateAge.exe.
    • This creates a form called output.xfd in the current folder.
  5. Open the output.xfd form, and check the number in the Age field.

The Form Sample Application

The Form library sample application demonstrates more of the functions available in the API.

This application reads into memory an input form called formSample.xfd. It then reads the current date and birth date values from the form and sets a formula on the Age field that automatically computes the user’s age. Next, the application determines the user’s gender based on the radio buttons in the form. It then replaces these buttons with an image representing the user’s gender. Finally, it duplicates the address field to create a mailing address field. When complete, the application saves the changes made to formSample.xfd in a new form called output.xfd.

Running the Form Sample Under C on AIX, Linux, and Solaris

These steps explain how to run the form sample application in the Viewer.

Compile the source code file formSample.c to produce an executable called formSample.exe. Then follow these steps to set up and run the Form sample application:

  1. Using the Viewer, open the form called FormSample.xfd located in the folder:
       <API Installation Folder>\samples\Win32\form\demo\sample_application\
  2. Notice the radio buttons used to indicate gender and the empty Age field. Close theViewer.
  3. Run the sample application formSample.exe.
    • This produces a new form called output.xfd in the current folder.
  4. Use the Viewer to compare the two forms and note the changes produced by the application.

Running the Form Sample Under Java

To set up and run the Form sample under Java:

  1. Using the Viewer, open the form called FormSample.xfd found in the folder:
       <API Installation Folder>\samples\java\form\demo\sample_application
  2. Notice the radio buttons used to indicate gender and the empty Age field. Close the Viewer.
  3. Using your Java compiler, compile the file called formSample.java found in the current folder.
    • This produces a new class file called formSample.class.
  4. Run the sample application formSample.class.
    • This produces a new form called output.xfd in the current folder.
  5. Use the Viewer to compare the two forms.

The FCI Sample Applications

The API includes two different samples that demonstrate the FCI, depending on whether you are working in C or Java.

Running the FCI Sample Under C

The FCI sample application for C uses the FCI methods to create a function called multiply that can be called from within any form. This function multiplies two values and returns the result.

To run the sample:

  1. Compile the source code file fciExtension.c located in the folder:
       <API Installation Folder>\samples\Win32\fci\demo\multiply\
  2. Move fciExtension.ifx into the Forms System global extensions folder:
       <API Installation Folder>\PureEdge\80\system
  3. Using the Viewer, open the form fciSample.xfd, located in the folder:
       <API Installation Folder>\samples\Win32\fci\demo\multiply
  4. Fill out fciSample.xfd. The result appears in the Result field.

Running the FCI Sample Under Java

The FCI sample application for Java uses the FCI methods to create a function called convertDate. This function takes two arguments, the date and the locale, and converts the date into the specified country's language and format. The application displays the converted date as a value for the Converted Date label. In this sample, the JAR file containing the extension was embedded into the form.

To run the FCI sample application:

  1. Open the form called fciSampleWithJar.xfd found in the folder:
       <API Installation Folder>\samples\java\fci\demo\convert_date\
  2. Enter a date in the Date field, then select a language and date conversion format.
  3. Click on Click me to convert the date.
    • The converted date appears on the form.
Note: For information on how to build JAR (Java archive) files, refer to the Lotus Forms Server API – Java API User's Manual. For information on embedding JAR files into XFDL forms, refer to the online help for the Designer.

Sample Applications for AIX, Solaris, and Linux

The API includes the following sample applications:

  • Calculate Age Sample (C and Java APIs)
  • Form Sample (C and Java APIs )
  • FCI Sample (C and Java APIs )
  • JSP Sample ( Java API )

The applications are provided to demonstrate the use of many of the functions in the API, and are useful for testing your API installation and development environment.

Note: To view the forms provided with these sample applications, you must have a licensed or evaluation copy of IBM Lotus Forms Viewer installed on a Windows computer.

The Calculate Age Sample Application for AIX, Linux, and Solaris

The Calculate Age sample application demonstrates the most commonly used functions in the API.

This application reads a form called calculateAge.xfd into memory, and reads the values for the year, month, and day of birth from the form. It then writes those values into a series of hidden fields that are used by a compute to determine the person's age. Once the values are written, the application writes the form as output.xfd.

Running Calculate Age Under C on AIX, Linux, and Solaris

Perform the following steps to set up and run the Calculate Age sample under C on AIX, Linux, and Solaris systems.

  1. Switch to the directory:
       <API Installation Folder>/samples/<UNIX OS>/form/demo/calculate_age/
  2. To view XFDL forms you must use a computer running Windows. Copy the file calculateAge.xfd to a computer running Windows.
  3. In Windows, use the Viewer to open calculateAge.xfd.
  4. Change the name and birth date if you want, then save and close the form.
  5. If you changed the values in the form, copy the saved form back to the original directory on your UNIX® computer.
  6. Create the makefile by typing xmkmf at the command prompt and press Enter.
  7. At the command prompt, type make and press Enter.
    • This will build the application file (calculateAge).
  8. To run the sample application, type ./calculateAge and press Enter.
    • This will create a form called output.xfd.
  9. Copy the file output.xfd to a computer running Windows.
  10. In Windows, use the Viewer to open the output.xfd form and check the number in the Age field.

Running Calculate Age Under Classic and Streaming Java on AIX, Linux, and Solaris

Perform the following steps to set up and run the Calculate Age sample under Java on AIX, Linux, and Solaris systems.

  1. Switch to the directory:
       <API Installation Folder>/samples/java/form/demo/calculate_age/
  2. To view XFDL forms you must use a computer running Windows. Copy the file calculateAge.xfd to a computer running Windows.
  3. In Windows, use the Viewer to open calculateAge.xfd.
  4. Change the name and birth date if you want, then save and close the form.
  5. If you changed the values in the form, copy the saved form back to the original directory on your UNIX computer.
  6. Using your Java compiler, compile the file called calculateAge.java found in the current folder.
    • This produces a new class file called calculateAge.class.
  7. Run calculateAge.class.
    • This will create a form called output.xfd.
  8. Copy the output.xfd form to a computer running Windows.
  9. In Windows, use the Viewer to open the output.xfd form and check the number in the Age field.

The Form Sample Application on AIX, Linux, and Solaris

The Form library sample application demonstrates more of the functions available in the API.

This application reads into memory an input form called formSample.xfd. It then reads the current date and birth date values from the form and sets a formula on the Age field that automatically computes the user's age. Next, the application determines the user's gender based on the radio buttons in the form. It then replaces these buttons with an image representing the user's gender. Finally, it duplicates the address field to create a mailing address field. When complete, the application saves the changes in a new form called output.xfd.

Running the form sample application under C on AIX, Linux, and Solaris

Run the form sample application in IBM Lotus Forms Viewer to view what you have created.

To set up and run the Form sample under C:

  1. Switch to the directory:
       <API Installation Folder>/samples/<UNIX_OS>/demo/sample_application/
  2. To view XFDL forms you must use a computer running Windows. Copy the file formSample.xfd to a computer running Windows.
  3. In Windows, use the Viewer to open formSample.xfd.
  4. Notice the radio buttons used to indicate gender and the empty Age field. You can now close the Viewer.
  5. Create the makefile by typing xmkmf at the command prompt and press Enter.
  6. At the command prompt, type make and press Enter.
    • This will build the application file (formSample).
  7. To run the sample application, type ./formSample and press Enter.
    • This produces a new form called output.xfd in the current folder.
  8. Copy the file output.xfd to a computer running Windows.
  9. In Windows, use the Viewer to compare the two forms.

Running the Form Sample Under Java on AIX, Linux, and Solaris

Run the form sample application in IBM Lotus Forms Viewer to view what you have created.

To set up and run the Form sample under Java:

  1. Switch to the directory:
       <API Installation Folder>/samples/java/form/demo/sample_application/
  2. To view XFDL forms, you must use a computer running Windows. Copy the file formSample.xfd to a computer running Windows.
  3. In Windows, use the Viewer to open formSample.xfd.
  4. Notice the radio buttons used to indicate gender and the empty Age field. You can now close the Viewer.
  5. Using your Java compiler, compile the file called formSample.java found in the current folder.
    • This produces a new file called formSample.class.
  6. Run the sample application formSample.class.
    • This produces a new form called output.xfd in the current folder.
  7. Copy output.xfd to your Windows computer, then compare the two forms in the Viewer to see the changes that were made by the sample application.

The FCI Sample Application

The API includes two different samples that demonstrate the FCI, depending on whether you are working in C or Java.

Running the FCI Sample Under C on AIX, Linux, and Solaris

The FCI sample application for C uses the FCI methods to create a function called multiply that can be called from within XFDL forms. This function multiplies two values and returns the result.

To set up and run the FCI sample under C:

  1. Switch to the directory:
       <API Installation Folder>/samples/<UNIX OS>/fci/demo/multiply/
  2. Create the makefile by typing xmkmf at the command prompt and press Enter.
  3. At the command prompt, type make and press Enter. This will build the application file and the extension file (fciExtension.ifx).
  4. Move the file fciExtension.ifx to the /usr/lib/PureEdge/80/extensions/ directory.
  5. To run the sample application, type ./sampleap and press Enter. The following line will appear:
       Multiplying 24 by 13 gives 312.000000
    • This indicates that the application executed successfully and multiplied the two numbers using the multiply function.

Running the FCI Sample Under Java on AIX, Linux, and Solaris

The FCI sample application for Java uses the FCI methods to create a function called convertDate. The convertDate function takes two arguments, the date and the locale, and converts the date into the language and format of the selected locale. The application displays the converted date as a value for the Converted Date label.

Follow the steps below to set up and run the FCI sample application:

  1. Switch to the folder:
       <API Installation Folder>/samples/java/fci/demo/convert_date/
  2. To view XFDL forms, you must use a computer running Windows. Copy the file fciSampleWithJar.xfd to a computer running Windows.
  3. In Windows, use the Viewer to open fciSampleWithJar.xfd.
  4. Enter a date in the Date field, then select a language and date conversion format.
  5. Click on Click me to convert the date.
    • The converted date appears on the form.

Running the JSP Sample Application

The JSP sample application is only available for Java. The sample demonstrates how to integrate XFDL code with JSP. This application consists of three files: jspget.jsp, getlabel.txt, and jsppost.txt. To run the application, you need to place the above files into a J2EE compliant web server's JSP folder. For more information refer to Lotus Forms Server API – Java API User's Manual and to your web server's documentation.

JSP Sample Application

Java Server Pages (JSP) is a platform independent technology designed to make it easier to add dynamic content to web pages. A web application server compiles JSP scripts into Java servlets that are executed by the server's Java virtual machine. The resulting dynamic content is inserted into the web document that is then displayed in the end user's web browser. Because JSP technology integrates with both HTML and XML documents, you can use JSP to extend the capabilities of XFDL forms.

This section assumes that you are familiar with both JSP and XFDL. The information in this section is not intended to show you how to write JSP scripts. Rather, its purpose is to explain how to integrate XFDL with JSP. For information on JSP refer to http://java.sun.com/products/jsp/. For more information on XFDL, refer to the XFDL Specification.

System Requirements

To process JSP pages that contain XFDL, you must have one of the following servlet containers:

  • IBM WebSphere Application Server 6.0.2 fix pack 23 or greater (WebSphere Application Server, WebSphere Application Server Express®, or WebSphere Application Server Network Deployment) with the Java SDK 1.4.2 SR7 Cumulative Fix. Note: WebSphere Application Server 6.0.2 is not supported on IBM System i® servers.
  • IBM WebSphere Application Server 6.1.0 fix pack 17 greater (WebSphere Application Server, WebSphere Application Server Express, or WebSphere Application Server Network Deployment) with the Java SDK 1.5 SR3 Cumulative Fix.

Combining JSP and XFDL

Creating a JSP page involves integrating JSP elements with the source code of the original HTML or XML web document. In the case of XFDL forms, this means adding appropriate JSP elements to the form's XFDL code using a text editor. Once complete, the resulting document is a JSP page and should have a .jsp extension.

Note: Once you add JSP code to an XFDL form, you will no longer be able to open the file with Lotus Forms Designer.

While the specific content of each JSP page depends on the logic of the application and the design of the form, certain fixed elements must be present in every JSP page that contains XFDL. The following elements must appear exactly as shown in every JSP that includes XFDL:

Element Description
<?xml version="1.0"?> This line is the standard XML file identifier. It must appear as the first line in the JSP page. There can be no blank lines or spaces ahead of this text.
<% response.setContentType("application/x-xfdl"); %> This line sets the mime type of the http response object. In this case, it identifies the object as an XFDL document. As a result, the user's browser will display the document using the Viewer. With the exception of any optional comments or whitespace, this line should appear immediately after the XML file identifier.

Once you have included these standard elements, you can add the rest of your custom JSP code such as directives, declarations, or scriptlets.

Note: The XFDL portion of the JSP page must not be compressed but it is valid to use the XFDL <transmitformat> option to specify either ascii or binary compression for the transmission of the page.

Sample JSP Page

The following source code creates a simple JSP page containing an XFDL form. In this example, the JSP scriptlet obtains the current date and converts it into a string. The form contains an XFDL label item that displays the string.

<?xml version="1.0"?>
  <%-- Set the content-type so that the Web browser uses the 
       Viewer to display the XFDL form. --%>
  <% response.setContentType("application/x-xfdl"); %>
	
  <%@ page import="java.util.Date" %>
  <%-- This is the JSP scriptlet --%>
	
  <%
        Date theDate = new Date();
        String theDateString = theDate.toString();
  %>
	
  <%-- The following XFDL code defines the form --%>

<XFDL xmlns:custom="http://www.ibm.com/xmlns/prod/XFDL/Custom" 
      xmlns:designer="http://www.ibm.com/xmlns/prod/workplace/forms/designer/2.6" 
      xmlns:ev="http://www.w3.org/2001/xml-events" 
      xmlns:xfdl="http://www.ibm.com/xmlns/prod/XFDL/7.6" 
      xmlns:xforms="http://www.w3.org/2002/xforms" 
      xmlns="http://www.ibm.com/xmlns/prod/XFDL/7.6" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <globalpage sid="global">
    <global sid="global">
      <designer:date>20100129</designer:date>
        <formid>
          <title></title>
            <serialnumber>9710555EEBA829D8:-11895BD9:1267B9B3652:-8000</serialnumber>
            <version>1.0.0</version>
        </formid>
        <history>
          <editors>
            <editor minversion="3.5" version="3.5.1">IBM Lotus Forms Designer</editor>
          </editors>
        </history>
      </global>
  </globalpage>
  <page sid="PAGE1">
    <global sid="global">
      <label>PAGE1</label>
    </global>
    <label sid="LABEL1">
      <itemlocation>
        <x>15</x>
        <y>15</y>
      </itemlocation>
      <value><%= theDateString%></value>
    </label>
    <spacer sid="vfd_spacer">
      <itemlocation>
        <x>960</x>
        <y>1260</y>
        <width>1</width>
        <height>1</height>
      </itemlocation>
    </spacer>
  </page>
</XFDL>

Sample JSP Application

The API includes a sample web application demonstrating how to use JSP pages to extend the functionality of XFDL forms. This simple application consists of three files, located in the folder <API Program Folder>\samples\java\jsp\demo. The following table describes the functions of each file:

File Description
jspget.jsp This JSP page is an example of a standard HTTP GET operation. The first JSP scriptlet obtains the current date and calculates the number of days until Christmas. The XFDL form specifies two labels to display this information. The second scriptlet creates the URL that the form's submit button uses to call jsppostt2.jsp. Within the XFDL portion of the page, a JSP include directive obtains a label item from getlabel.txt.
getlabel.txt Although this file does not contain a complete form, it does contain XFDL code defining a label item. jspget.jsp accesses this code using an include directive.
jsppost.jsp This page is an example of a standard HTTP POST operation. The scriptlet uses the API's streaming method readForm to obtain the number of days until Christmas and the signature from jspget.jsp. It then uses getSignatureVerificationStatus to validate the signature. Finally, the XFDL portion of the page specifies two labels to display the results to the end user.

To run this sample in WebSphere Application Server, you must first package the above files into a WAR file. You can then deploy the WAR file using the WebSphere Application Server Administrator Console. For other application servers, you can package the files as WARs or place the JSP files into your web server JSP folder. Refer to the documentation of your application server for more information.

To run the application, users either follow a link or type the URL into the address field of the browser. For example, if the application is running on WebSphere Application Server, the URL would be: http://<server_name>:<port><example_dir>/jsp/jspget.jsp.

Tutorials

The tutorials demonstrate how to work with XFDL forms in C, Java™, and Visual Basic. They also demonstrate the features of the API that allow you to create, modify, and save XFDL forms, and how to extend XFDL forms using the function call interface library.

Java Tutorials

Learn how to manipulate and extend forms in Java with IBM Lotus Forms Server - Java API.

Developing an application in Java

In this tutorial, you will create an application that shows you how to read, modify, and write forms using the Form Library

By working through the tutorial, you will perform all of the steps involved in creating a simple application that uses the API methods, including:

  • Initializing the Form Library.
  • Reading a form into your application.
  • Setting and retrieving form data.
  • Removing a form from memory.
  • Destroying a form.

The sample application in this tutorial reads an input form called CalculateAge.xfd into memory. It retrieves the user's birth day, month, and year as well as the current date from the form. It then places these values into hidden fields in the form. This triggers the form to compute the user's age and display the result. When complete, the application saves the changes made to calculateAge.xfd as a new form called Output.xfd.

Note: The sample application described in this tutorial is included with the API and can be found in the folder: <API Program Folder>\Samples\Java\Form\Demo\Calculate_Age\

The tutorial describes the following tasks:

Setting Up Your Application

As with any Java application, you must begin by importing the necessary classes and defining the program's classes.
  1. Create a new Java source file called calculateAge.java.
  2. Any program that calls methods from the API must import the following classes:
       import com.PureEdge.DTK;
       import com.PureEdge.xfdl.FormNodeP;
       import com.PureEdge.xfdl.XFDL;
       import com.PureEdge.error.UWIException;
       import com.PureEdge.IFSSingleton;
    • You must place these lines before any class or interface definitions.
  3. Set up the rest of your application. This generally includes defining any classes and methods for your application as well as declaring and initializing any variables you may need. The following code sets up the Calculate Age application:
    • Create the public class CalculateAge and the main method for the class.
         public class CalculateAge
            {
    • Declare a FormNodeP object called theForm to represent the form.
            private static FormNodeP theForm;
    • Create the program's main method.
            public static void main(String argv[])
               {
    • Declare the program's variables.
            int birthYear;
            int birthMonth;
            int birthDay;
    • The program's main method essentially consists of a series of calls to other methods. The Form Library methods are called from the definition of these methods.
               try
               {
                  initialize();
      
                  loadForm();
      
                  birthYear = getBirthYear();
                  birthMonth = getBirthMonth();
                  birthDay = getBirthDay();
      
                  setBirthYear(birthYear);
                  setBirthMonth(birthMonth);
                  setBirthDay(birthDay);
      
                  saveForm();
    • Free the memory in which the form was stored. For more information see Closing a Form .
                  theForm.destroy();
               }
    • Finally, perform exception handling.
               catch (Exception ex)
               {
                  ex.printStackTrace();
               }
      
               /* Additional code removed */
      
            }
         }

Initializing the Form Library

All applications that use the API functions must initialize the Form Library to ensure correct error and memory handling behavior. The sample application does this in a separate method calledinitialize. In turn, initialize calls the Form Library method DTK.initialize and passes it the name of the current program.

Define the initialize method to call the DTK.initialize method. DTK.initialize initializes the API environment.
   private static void initialize() throws UWIException
   {
      DTK.initialize("calculateAge", "1.0.0", "2.6.0");
   }

Loading a Form

Before your program can begin working with a form, you must load it into memory. CalculateAge does this by defining a loadForm method to handle these tasks.

   private static void loadForm() throws Exception
      {
  1. Before you can load the form, declare the XFDL object:
       XFDL theXFDL;
  2. Use IFSSingleton.getXFDL to assign the XFDL object to theXFDL. This allows you to access the root node of the form.
        theXFDL = IFSSingleton.getXFDL();
             if(theXFDL == null)
                throw new Exception("Could not find interface");
    • The loadForm method uses the Form Library method readForm to load the form into memory. Before you can use readForm> you must retrieve the XFDL object.
  3. Call the API method readForm to load the form into memory. The method returns a reference to the root node of the form.
       theForm = theXFDL.readForm("calculateAge.xfd", 0);
          }
    • The argument "calculateAge.xfd" is the name of the form to read from the local drive.

Retrieving A Value from a Form

Once you have set up and initialized your application with the API and loaded a form into memory, your application is ready to start working with the form. The following code uses getLiteralByRefEx to get a specific value from the form:

  1. Define the method getBirthDay and a string variable called temp.
       private static int getBirthDay( ) throws Exception
          {
          String temp;
  2. Call getLiteralByRefEx to retrieve the literal information contained in the form node PAGE1.BIRTHDAY.value
             temp = theForm.getLiteralByRefEx(null, "PAGE1.BIRTHDAY.value", 0, 
                null, null);
    • If the method returns a literal value, convert it into an integer value; otherwise, indicate that no value was entered into the field and throw an exception.
            if (temp.length( ) > 0)
            {
               return Integer.parseInt(temp);
            }
            else
            {
               throw new UWIException("The birth day was not entered.");
            }
         }
  3. Define the following methods to retrieve the user's birth month and year from the input form. These methods will be exactly the same as getBirthDay except for the parameters passed to getLiteralByRefEx.
    • getBirthMonth( ) — retrieves the value PAGE1.BIRTHMONTH.value from theForm.
    • getBirthYear( ) — retrieves the value PAGE1.BIRTHYEAR.value from theForm.

Setting a Value in a Form

Once a form is loaded into memory, a developer can set the values associated with any of the item or option nodes located in the form by calling setLiteralByRefEx.

  1. Define the method setBirthDay and an integer variable to reference the user's day of birth.
        private static void setBirthDay(int birDay) throws Exception
        {
           Integer day = new Integer(birDay);
  2. Call the method setLiteralByRefEx to assign the user's day of birth to the form's hidden day field.
          theForm.setLiteralByRefEx(null, "PAGE1.HIDDENDAY.value", 0, 
             null, null, day.toString());
       }
  3. Define the remaining methods to set the user's birth month and year in the form's hidden fields. These methods will be exactly the same as setBirthDay except for the parameters passed to getLiteralByRefEx.
    • setBirthMonth( ) – sets the value PAGE1.HIDDENMONTH.value in theForm.
    • setBirthYear( ) – sets the value PAGE1.HIDDENYEAR.value from theForm.

Writing a Form to Disk

Once you have finished making the desired changes to the form, you should save it to disk. If you want to retain the original form (calculateAge.xfd), you should save the modified form under a new name. This program saves the modified form as Output.xfd.

  1. Define the method saveForm. This method demonstrates the use of the FormNodeP method writeForm.
       private static void saveForm( ) throws UWIException
       {
  2. Call the Form method writeForm and pass it the new name of the form.
     theForm.writeForm("Output.xfd", null, 0);
          }

Closing a Form

Next, you must free the memory used by the form. This is the last operation in the main method of the program.

  1. The program's main method calls the API’s destroy method to delete the theForm object.
                theForm.destroy( );
             }
  2. Display any exceptions before terminating.
             catch (Exception ex)
             {
                ex.printStackTrace( );
             }
          }

Testing your Application

Use the sample form that accompanies the API to test the Calculate Age application.

  1. Copy the file calculateAge.xfd to the folder that contains your application. The file is located in the following folder:
       <API Program folder>\Samples\java\form\demo\calculate_age\
  2. Open the form in the Viewer to see the original settings.
  3. Run the application that you have just created.
  4. A new file will be created called Output.xfd.
Note: To view the forms provided with this API, you must have a licensed or evaluation copy of IBM Lotus Forms Viewer installed.

Distributing Applications That Use the Form Library

32-bit applications that use methods from the Form Library will run on any computer that supports the Java Runtime Environment or the Microsoft Software Development Kit For Java v3.1 or later.

If you distribute applications that use the Form Library, you will also need to distribute a number of API files. Refer to Developing and distributing applications for information about distributing applications that use the Form Library.

Form Library summary

By working through this section you have successfully built the Calculate Age application. In the process, you have learned how to initialize, compile, and test form applications using the following methods from the Form Library:

  • initialize
  • getXFDL
  • readForm
  • getLiteralByRefEx
  • setLiteralByRefEx
  • writeForm
  • destroy

The source code for the Calculate Age application is included with this API and can be found in the following folder:

   <API Program folder>\Samples\Java\Form\Demo\Calculate_Age\
For a longer example using the Form Library of methods refer to the other sample application installed with the API. The source files for this application are located in the following folder:
   <API Program folder>\Samples\Java\Form\Demo\Sample_Application\

To view the forms provided with the sample applications, you must have a copy of the Viewer installed.

Developing an extension with the FCI Library

In this tutorial, you will create a simple extension to an XFDL form.

A series of practical examples is provided which you can work through to build a package of functions called sample_package, which contains one function called convertDate. The convertDate function converts a date to a language and format specific to another country. Try adding other functions to the package for more practice using the FCI Library of methods.

Although the FCI Library contains many methods, you only need to use a few of them to create a simple package of functions. These are:

  • lookupInterface
  • registerInterface
  • registerFunctionCall
  • evaluate
  • help

The remaining FCI methods allow you to customize the behavior of your functions and extensions. For example, you can attach additional information to a particular extension, or get a list of currently registered extensions.

Creating Extensions with the FCI methods

The following table is a guide for creating extensions using the Function Call Interface. Refer to the corresponding page numbers for more details:

Procedure Page
Install Lotus Forms Server - API and related files, as outlined in Installing Lotus Forms API. N/A
Set up the extension. Creating the Extension class
Create the Extension class. Creating the Extension class
Create the extension initialization method. Implementing the extension initialization method
Create a new FunctionCall object. Creating a new FunctionCall object
Set up the function call. Creating a FunctionCall class
Create the FunctionCall class. Creating a FunctionCall class
Retrieve the Function Call Manager. Retrieving the Function Call Manager
Register each FunctionCall object with the IFX Manager. Registering the FunctionCall object with the IFX Manager
Register your package(s) of custom functions with the Function Call Manager. Registering your packages of custom functions with the Function Call Manager
Implement your custom functions. Implementing your custom functions
Provide help information for each of your functions. Providing help information for each of your functions
Build the extension. Building the extension
Distribute the extension for Testing or Use. Distributing Extensions for Testing or Use
Creating the Extension class

When the Forms System is initialized, the API checks for existing extensions and calls the initialization method (extensionInit) for each extension. Your first step in creating a function call is to create an Extension class that generates a new FunctionCall object. Follow the procedure below to create the Extension class called FCIExtension:

  1. Create a new Java source file called FCIExtension.java.
  2. Define the Java package. For example:
       com.yourcompany.samples;
  3. Import the following files and any other required files to any Java files that call FCI methods. These lines must be placed before any class or interface definitions:
       import com.PureEdge.ifx.IFX;
       import com.PureEdge.ifx.ExtensionImplBase;
       import com.PureEdge.ifx.Extension;
       import com.PureEdge.xfdl.FunctionCall;
       import com.PureEdge.xfdl.FunctionCallManager;
       import com.PureEdge.xfdl.FormNodeP;
       import com.PureEdge.IFSUserDataHolder;
       import com.PureEdge.error.UWIException;
Note: If you are using methods from the Form Library, you must import the necessary packages. For more information, refer to Setting Up Your Application.
Implementing the extension initialization method

The API will initialize an extension by calling the extensionInit method and passing the method an object known as the IFX Manager.

Implement the extensionInit method as part of the Extension class.
  • extensionInit is the main function within theExtension interface. It is responsible for the registration of all the services that the extension provides.
  • The following is an example of the extensionInit method in the FCIExtension class.
          public class FCIExtension extends ExtensionImplBase implements 
          Extension
          {
             public void extensionInit(IFX IFXMan) throws UWIException
             {
                /* Additional code removed */
             }
          }
  • The IFXMan object represents the IFX Manager. Through this object all other objects and services can be reached.
  • UWIException is a generic exception.
Creating a new FunctionCall object

The extensionInit method creates a new FunctionCall object that contains your custom-built functions.

To create a new FunctionCall object you must define a FunctionCall class that contains your custom functions. Refer to "Setting up the FunctionCall Class" for more details.

  1. Declare a new FunctionCall object before you create it in the extensionInit method.
    • The following example from the FCIExtension class declares a FunctionCall object called theFunctionObject.
            public class FCIExtension extends ExtensionImplBase implements 
            Extension
            {
            private FunctionCall theFunctionObject;
               public void extensionInit(IFX IFXMan) throws UWIException
               {
                  /* Additional code removed */
               }
            }
  2. Create a new FunctionCall object inside the extensionInit method, by calling the FunctionCall class constructor that you will build in the next section.
    • In the following example, extensionInit creates a new FunctionCall object by calling the FunctionCall class constructor FciFunctionCall and passing it the IFX Manager.
            public class FCIExtension extends ExtensionImplBase implements 
            Extension
            {
            private FunctionCall theFunctionObject;
               public void extensionInit(IFX IFXMan) throws UWIException
               {
                  this.theFunctionObject = new FciFunctionCall(IFXMan);
               }
            }

Setting up the FunctionCall Class

Creating a FunctionCall class

The FunctionCall class contains definitions for your custom functions. It also registers the FunctionCall object and each of the custom functions that it supports with the Forms System so that the functions and packages that it contains will be recognized.

  1. Create a new Java source file called FciFunctionCall.java.
  2. Define the Java package. For example:
       com.yourcompany.samples;
  3. Import the following API packages:
       com.PureEdge.ifx.IFX
       com.PureEdge.xfdl.FormNodeP
       com.PureEdge.xfdl.FunctionCallManager
       com.PureEdge.xfdl.FunctionCallImplBase
       com.PureEdge.xfdl.FunctionCall
       com.PureEdge.error.UWIException
  4. Import any other required files. In this case the following files are needed to implement the convertDate function:
       java.util.Date
       java.util.Locale
       java.text.DateFormat
       java.text.SimpleDateFormat
       java.text.ParseException
  5. Create a FunctionCall class that extends the pre-defined superclass com.PureEdge.xfdl.FunctionCallImplBase and implements the pre-defined interface FunctionCall.
    • In the following example the name of the FunctionCall class is FciFunctionCall.
         public class FciFunctionCall extends FunctionCallImplBase 
            implements FunctionCall
            {
               /* Additional code removed */ 
            }
  6. Define a unique identification number for each custom function that you are going to create using the FCI.
    • In the following example,FciFunctionCall contains a function called convertDate that converts any date to the date format and language of a specific country. The convertDate function in FciFunctionCall has an ID number of 1:
         public class FciFunctionCall extends FunctionCallImplBase 
            implements FunctionCall
            {
               public static final int CONVERTDATE = 1;
               /* Additional code removed */ 
            }
  7. Define a FunctionCall class constructor that takes as its parameter the IFX Manager.
    • In the following example, the constructor for the FciFunctionCall class is FciFunctionCall.
         public class FciFunctionCall extends FunctionCallImplBase 
            implements FunctionCall
            {
               public static final int CONVERTDATE = 1;
               
               public FciFunctionCall(IFX IFXMan) throws UWIException
               {
                     /* Additional code removed */ 
               }
            }
    • The IFXMan object represents the IFX Manager. Through this object all other objects and services can be reached.
    • UWIException is a generic exception.
Retrieving the Function Call Manager

The Function Call Manager is used to handle services specific to function calls, such as handling requests for a particular function. The Function Call Manager is represented by a FunctionCallManager object.

  1. Declare the Function Call Manager before requesting it from the IFX Manager.
    • In the following example, the FciFunctionCall constructor declares the Function Call Manager with the type FunctionCallManager.
            public FciFunctionCall(IFX IFXMan) throws UWIException
            {
               FunctionCallManager theFCM;
            }
  2. Use the IFSSingleton method getFunctionCallManager in the function call constructor to request a FunctionCallManager object from the IFX Manager.
    • The getFunctionCallManager call requests the Function Call Manager from the IFX Manager.
    • The return value of the getFunctionCallManager method is a generic object, and must be typecast to the object type you have requested. In this case, the object returned from getFunctionCallManager is typecast to FunctionCallManager.
    • In the following example the FciFunctionCall constructor requests the Function Call Manager (FCM Notice that before the Function Call Manager is returned, it is explicitly cast to the type FunctionCallManager.
         public FciFunctionCall(IFX IFXMan) throws UWIException
            {
            FunctionCallManager theFCM;
               if ((theFCM = IFSSingleton.getFunctionCallManager()) == null) 
                  throw new UWIException("Needed Function Call Manager");
            }
Registering the FunctionCall object with the IFX Manager

Each FunctionCall object registers itself with the IFX Manager as an interface that provides function call support.

In the FunctionCall class constructor, register the function call with the IFX Manager using the method registerInterface.
  • In the following example the FciFunctionCall constructor uses the registerInterface method to register itself with the IFX Manager as a FunctionCall object:
          public FciFunctionCall(IFX IFXMan) throws UWIException
          {
          FunctionCallManager theFCM;
             if ((theFCM = IFSSingleton.getFunctionCallManager()) == null) 
                throw new UWIException("Needed Function Call Manager");
             IFXMan.registerInterface(this, 
                FunctionCall.FUNCTIONCALL_INTERFACE_NAME,
                FunctionCall.FUNCTIONCALL_CURRENT_VERSION,
                FunctionCall.FUNCTIONCALL_MIN_VERSION_SUPPORTED, 
                0x01000300, 0, null, theFCM.getDefaultListener( ));
          }
Registering your packages of custom functions with the Function Call Manager
Use the FunctionCallManager method registerFunctionCall in the function call constructor to register each of your custom functions and corresponding package(s) with the Function Call Manager.
  • The FCI allows you to assign a version number to each function that you create. This allows you to provide upgrades to single functions in extensions you have already distributed to users. For more information see the next section.
  • When registering your package(s) of functions with the Function Call Manager, be aware of the API package naming conventions. For more information see the next section.
  • You must register each of your custom functions separately. So, if you are registering three functions with the Function Call Manager, you must call registerFunctionCall three times.
  • In the following example, the FciFunctionCall constructor uses the registerFunctionCall method to register the convertDate function with the Function Call Manager:
          public FciFunctionCall(IFX IFXMan) throws UWIException
          {
          FunctionCallManager theFCM;
             if ((theFCM = IFSSingleton.getFunctionCallManager()) == null) 
                throw new UWIException("Needed Function Call Manager");
             IFXMan.registerInterface(this, 
                FunctionCall.FUNCTIONCALL_INTERFACE_NAME,
                FunctionCall.FUNCTIONCALL_CURRENT_VERSION,
                FunctionCall.FUNCTIONCALL_MIN_VERSION_SUPPORTED, 
                0x01000300, 0, null, theFCM.getDefaultListener( ));
             theFCM.registerFunctionCall(this, "sample_package", 
                "convertDate", FciFunctionCall.CONVERTDATE,
                FunctionCall.FCI_FOLLOWS_STRICT_CALLING_PARAMETERS,
                "S,S", 0x01000300, "Converts a date to a different 
                locale");
          }
  • Note that the "S,S" parameter in the registerFunctionCall method represents two mandatory strings that you must provide.
About Function Version Numbers

Along with registering your package(s) of custom functions with the Function Call Manager, the registerFunctionCall method is also used to specify a version number for each function that you create. In the previous example, the ConvertDate function is registered with the version number 0x01000300.

Assigning a version number to each function allows you to provide upgrades to single functions in extensions you have already distributed to users.

For example, if you distributed an extension containing a package of 50 functions for your application and then wanted to change the behavior of one of the functions, you could:

  • Write a new extension containing just the upgraded function.
  • Register the new function using registerFunctionCall, with the same package name and function name as the original function but with a higher version number.
  • Distribute the new extension to users.

When the API initializes all of the extensions it would find two functions with the same package name and function name. It would deregister the one with the lower version number thereby updating your application.

Package Naming Conventions

The main purpose of package names is to distinguish the functions in a package from those in other packages that could potentially have the same names. All packages you create must contain an underscore in their names. For example, the convertDate function belongs to a package called sample_package.

  • Choose a name that aptly describes the set of functions you are creating and is distinct enough to be unique within its realm of usage.
  • The package name is an internal logical element of the API.
  • Package names are case sensitive.
  • All package names you define must contain an underscore.
Note: A group of functions is provided with the Forms System software as the package. The package is reserved for system functions that are defined in the XFDL Specification. You may not add to the system package or call your packages by the name system.
Implementing your custom functions
Implement your custom functions as part of the FunctionCall method evaluate.
  • TheFunctionCall class must implement the evaluate method since it is defined as part of the FunctionCall interface.
  • evaluate is called whenever a particular function needs to be executed.
  • In the following example, the convertDate function is implemented as part of evaluate in the FunctionCall classFciFunctionCall.
       public class FciFunctionCall extends FunctionCallImplBase implements 
          FunctionCall
          {
          /* Additional Code Removed */
             public void evaluate(String thePackageName, 
                String theFunctionName, int theFunctionID, 
                int theFunctionInstance, short theCommand, 
                com.PureEdge.xfdl.FormNodeP theForm, 
                com.PureEdge.xfdl.FormNodeP theComputeNode, 
                com.PureEdge.IFSUserDataHolder theFunctionData, 
                com.PureEdge.IFSUserDataHolder theFunctionInstanceData, 
                com.PureEdge.xfdl.FormNodeP [] theArgList, 
                com.PureEdge.xfdl.FormNodeP theResult) throws UWIException
             {
             String theDateString;
             String theLocaleString;
             String theAnswerString = null;
             Date theDate = null;
             Locale theLocale;
             DateFormat theDateFormat;
                
                if (theCommand == FunctionCall.FCICOMMAND_RUN) 
                {
                
                /* Now we'll switch on the function ID. This makes it easy for a
                   single FunctionCall object to support multiple functions. */
                
                if (theFunctionID == FciFunctionCall.CONVERTDATE)
                {
                
                /* First, we'll grab the string values of the two arguments. 
                   Since    we indicated that this method has two parameters and
                   that it       must have two parameters 
                   (FCI_FOLLOWS_STRICT_CALLING_PARAMETERS) when we registered 
                   it, we don't have to check to see if we actually received
                   both parameters, since this code won't even be called unless
                   the caller used the right number of parameters. */
                   theDateString = theArgList[0].getLiteralEx(null);
                   theLocaleString = theArgList[1].getLiteralEx(null);
                
                   /* Now we perform the conversion. */
                   if (theLocaleString.length( ) != 5) 
                      theAnswerString = "Locale must be 2 characters, " +
                         "a space and    2 characters";
                   else
                   {
                      theLocale = new Locale(theLocaleString.substring(0, 2),
                         theLocaleString.substring(3));
                         
                      if ((theDateFormat = DateFormat.getDateInstance(
                         DateFormat.LONG, theLocale)) == null)
                         theAnswerString = "Unrecognized locale";
                      else
                      {
                         try
                         {
                            if ((theDate = new SimpleDateFormat
                               ("yyyyMMdd").parse(theDateString)) == null)
                               theAnswerString = "Unable to parse";
                         }
                         catch (ParseException ex)
                         {
                            theAnswerString = ex.toString( );
                         }
                               
                         if (theAnswerString == null)
                            theAnswerString = theDateFormat.format(theDate);
                      }
                   }
                
                   /* Lastly, we'll store the result in the result node */
                
                   theResult.setLiteralEx(null, theAnswerString);
                }
             }
             /* Additional Code Removed */
          }
Providing help information for each of your functions

By using the method help, you can provide help information to form designers within a development environment (for example, Lotus Forms Designer). Use help to help form designers choose and use the correct functions.

Provide in-depth help information for each of the functions you create by implementing the FunctionCall method help.
  • The FunctionCall class must implement the help method since it is defined as part of the FunctionCall interface.
  • In the following example, help provides help information for the convertDate function in the class FciFunctionCall.
          public class FciFunctionCall extends 
          com.PureEdge.xfdl.FunctionCallImplBase implements FunctionCall
          {
             /* Additional Code Removed */
             
             public void help(String thePackageName, 
                String theFunctionName, int theFunctionID, 
                com.PureEdge.IFSUserDataHolder theFunctionData, 
                com.PureEdge.StringHolder theQuickDesc, 
                com.PureEdge.StringHolder theFunctionDesc, 
                com.PureEdge.StringHolder theSampleCode, 
                com.PureEdge.StringListHolder theArgsNameList, 
                com.PureEdge.StringListHolder theArgsDescList, 
                com.PureEdge.ShortListHolder theArgsFlagList, 
                com.PureEdge.StringHolder theRetValDesc, 
                com.PureEdge.ShortHolder theRetValFlag) throws
                UWIException
             {
                switch(theFunctionID)
                {
                case FciFunctionCall.CONVERTDATE:
                   theQuickDesc.value = "Converts a date to a different " + 
                      "locale";
                   theFunctionDesc.value = "This function takes a date in " +
                      "the first parameter and a locale in the second " +
                      "parameter and returns the date formatted for the " + 
                      "specified locale";
                   theSampleCode.value = "\t <LABEL SID = \"LABEL1\"> \n" +
                      "\t\t <VALUE COMPUTE = "sample_package.convert " + 
                      "(\'19980101\', \'french\')"></VALUE> \n" +
                      "\t\t <SIZE CONTENT = \"ARRAY\"> \n" +
                      "\t\t\t <AE>10</AE> \n" +
                      "\t\t\t <AE>1</AE> \n" +
                      "\t\t </SIZE> \n" +
                      "\t </LABEL> \n";
                   theArgsNameList.value = new String[2];
                   theArgsNameList.value[0] = "theDate";
                   theArgsNameList.value[1] = "theLocale";
                   theArgsDescList.value = new String[2];
                   theArgsDescList.value[0] = "The english date";
                   theArgsDescList.value[1] = "The locale";
                   theRetValDesc.value = "The formatted date";
                   break;
                }
             }
          }

Building the extension

Once you have generated the Java source files for your Extension class, you must compile the source code to create the extension.

  • Use a Java compiler that is supported by this API to compile your Extension class files. Refer to the IBM Lotus Forms Server - API Installation and Setup Guide for more information on compatible development environments.
  • Before building your extension you should have a collection of .java files that represent your extension. After compiling the .java files you will have a set of files with the same name as the .java files but with the extension .class.
  • For example, after compiling the source code for the Extension class FCIExtension.java and the FunctionCall class FciFunctionCall.java your Java compiler will create two corresponding files: FCIExtension.class and FciFunctionCall.class. These two class files make up the extension called FCIExtension.
  • The details of compiling your source code are not included in this manual. Consult your Java documentation for specific information on how to use your Java compiler.

Testing and Distributing extensions

Once you have created your extensions you can package them for testing or distribution by using either of the following methods:

Packaging extensions as JAR Files

Once you have created your extensions you can package the .class files into a single Java Archive (JAR) file and distribute the file. This means that you can package multiple extensions into one JAR file for distribution.

Before building the JAR file, you must create a manifest that indicates which classes in the JAR file are extensions.

  1. Using your favorite text-editor, create a manifest file for the extensions you wish to package in the JAR file.
    • The manifest file has the file extension .mf. For example, the manifest file for FCIExtension is called:
            FCI.mf
    • The first line of the manifest must include the manifest-version number. See the following example for the correct syntax.
    • The manifest file is broken down into sections, where each section represents a particular Extension class and its attribute as an extension.
    • The class listed in each section of the manifest file is the class that implements the Extension interface. In the following example FCIExtension.class implements FCIExtension.
    • For example, the manifest file for FCIExtension will have the following syntax and format (notice that there is a space after every colon)
            Manifest-Version: 1.0
            Name: com/yourcompany/samples/FCIExtension.class
            IFS-Extension: True
    • Ensure that you add a carriage return to the last line of the manifest file. Otherwise the JAR may not work properly.
  2. Create a JAR file from the .class files that make up your extension.
    • Use the following syntax to create the JAR file:
            jar -cvfm destination.jar manifest.mf YourExtension.class 
               YourFunctionCall.class
    • Optionally, you can replace the class names with the root folder for your package. This will include all classes that are defined in that package. For example, to create a JAR file called FormIFX for FCIExtension, you would type the following:
            jar -cvfm FormIFX.jar FCI.mf com
Distributing Extensions for Testing or Use

Once you have packaged your extension, you can install it for testing or distribute it for general use. In either case, you place the extension in the same location.

To distribute your extensions so that they may be used by a specific Lotus Forms product:

Copy the JAR file to the Extensions folder of the Lotus Forms product that will use the extension.
  • For example, in order for the convertDate function to work in the Viewer, you would copy the file FormIFX.jar to the following folder:
       <Viewer program folder>\Extensions

To distribute your extensions so that they may be used by all Lotus Forms products:

  1. Copy the JAR file to the Forms System Global Extensions folder.
  • For example, in order for the convertDate function to work in the Viewer, you would copy the file FormIFX.jar to the following folder: C:\<Windows System>\PureEdge\extensions
Note: For more information about creating Java Archive files and manifest files refer to your Java documentation.
Embedding extensions in XFDL Forms

You can embed an extension in any XFDL form. The extension will run in the Viewer, but will not be processed by the API. This means that server-side applications will not run an embedded extension.

To embed an extension in a form:

  1. Create a JAR file that contains your extensions.
  2. Use Lotus Forms Designer to enclose the JAR file in a form.
About MIME Types

JAR files that are enclosed in forms must have the MIME type set to:

  • application/uwi_jar

The corresponding XFDL code will look like this:

   <mimetype>
      application/uwi-jar
   </mimetype>

If you are using the Designer to enclose a JAR file into a form the Designer will set the MIME type for you.

You can also override the default Java Virtual Machine (JVM) that is used to run the enclosed JAR file. To do this, you must add a vm parameter to your MIME type, as shown:

   <mimetype>
      application/uwi-jar; vm="<java virtual machine>"
   </mimetype>

Set this to the string that the JVM uses to register itself. For example,"Sun VM <version>". The version is guaranteed to include a major and minor number, and may include further information, such as a maintenance number, build number, and so on.

Since it can be difficult to get an exact match, you can use the * wildcard in the version string. For example, you might use the following string:

   Sun VM 1.4*

This will match any version beginning with 1.4, such as “1.4.2_03 JDK” or “1.4 JDK”.

When there are multiple matches, the API will default to the latest version. For example, if you search for version 1.4*, and you have “Sun VM 1.4 JDK” and “Sun VM 1.4.2_03 JDK” installed, the API will use version 1.4.2_03.

Additionally, the API always chooses the JDK over the JRE. For example, if you search for version 1.4*, and you have “Sun VM 1.4.2_03 JDK” and “Sun VM 1.4.2_03 JVM” installed, the API will use the JDK.

Location of Installed extensions (Security Issues)

The location in which an extension is installed determines how much access the extension has to the user's system resources (for example, user's system files). The following table summarizes the security features that are set when an extension is installed in a particular location.

Location of Installed extension Security Features
The extension is installed as a JAR or ZIP file in the Extensions folder of the Lotus Forms product that will use the extension. The extension has full access to the user's system resources.
The extension is installed as a JAR or ZIP file in the Forms System Global Extensions folder:

C:\<Windows System>\PureEdge\extensions

The extension has full access to the user's system resources.
The extension is installed as a set of .class files in the folder:

<Windows System>\PureEdge\java\source.

The extension has full access to the user's system resources.
The extension is packaged as a JAR (or Zip) file and enclosed directly within a form. The extension has access only to the form that encloses it. The extension cannot access other parts of the user's system or cause any damage.

Refer to the following section regarding additional security restrictions for functions enclosed in XFDL forms.

Additional Security Restrictions for Functions Enclosed in XFDL Forms

Note that the following methods are not available to extensions that are enclosed within an XFDL form:

  • com.PureEdge.xfdl.XFDL.readForm
  • com.PureEdge.xfdl.FormNodeP.writeForm
  • com.PureEdge.xfdl.FormNodeP.encloseFile
  • com.PureEdge.xfdl.FormNodeP.extractFile
  • com.PureEdge.ifx.IFX.ifxScanForExtensions

In addition extensions that are enclosed within a form cannot execute the following functions on a local computer:

  • Create class loaders.
  • Exit the Java virtual machine.
  • Execute a program.
  • Link to a DLL.
  • Read files.
  • Write files.
  • Delete files.
  • Print.

FCI Library summary

By working through this section you have successfully built an extension for date conversion. In the process you have learned how to set up, compile, test, and distribute extensions. You also learned how to use the following FCI methods:

  • getFunctionCallManager
  • registerInterface
  • registerFunctionCall
  • evaluate
  • help

The Convert Date sample application is included with this API. you will find it in the folder < Program Folder>\samples\java\fci\demo\convert_date.

In order to view the forms provided with this sample application, you must have a licensed or evaluation copy of Lotus Forms Viewer installed.

C Tutorials

Learn how to manipulate and extend forms in C with IBM Lotus Forms Server - C API.


Developing an application in C

In this tutorial, you will create an application that shows you how to read, modify, and write forms using the Form Library

By working through the tutorial, you will perform all of the steps involved in creating a simple application that uses the API functions, including:

  • Initializing the Form Library.
  • Reading a form into your application.
  • Setting and retrieving form data.
  • Removing a form from memory.
  • Destroying a form.

The sample application in this tutorial reads an input form called CalculateAge.xfd into memory. It retrieves the user's birth day, month, and year as well as the current date from the form. It then places these values into hidden fields in the form. This triggers the form to compute the user's age and display the result. When complete, the application saves the changes made to calculateAge.xfd as a new form called Output.xfd.

Note: The sample application described in this tutorial is included with the API and can be found in the folder: <API Program Folder>\Samples\Win32\Form\Demo\Calculate_Age\

The tutorial describes the following tasks:

Setting Up Your Application

  1. A set of template project files for applications have been provided for you. Copy the Form template files into the directory in which you will be building your application.
    • Files that are compatible with the Visual C++ development environment can be found in: <API Program folder>\Samples\Msc32\Form\Template.
    • If you prefer to set up the application development environment yourself, follow the procedure outlined in Setting up the C environment to use the Form library .
  2. Create a new .c source file named calculateAge.c and include any necessary header files. For every application that uses the Form Library, you must include pe_api.h. In calculateAge.c:
       #include "pe_api.h"
       #include <stdio.h>
       #include <string.h>
       #include <stdlib.h>
    Note: You must always include pe_api.h in any source file that uses the API.
  3. Declare all the functions implemented in calculateAge.c.
    • The initialize function initializes the API.
         r_short initialize(
         #ifdef PROTO
            void
         #endif
         );
    • The loadForm function calls the API function UFLReadForm that will read a specified form into memory.
         r_short loadForm(
         #ifdef PROTO
            formNodeP *form
         #endif
         );
    • The function getBirthDate uses the API function UFLGetLiteralByRefEx to retrieve date information from the form loaded in memory.
         r_short getBirthDate(
         #ifdef PROTO
            formNodeP form,
            int *birYear,
            int *birMonth,
            int *birDay
         #endif
         );
    • The saveForm function saves the form to disk by calling the API function UFLWriteForm.
         r_short saveForm(
         #ifdef PROTO
            formNodeP form
         #endif
         );
    • The reportError function reports errors by printing the error codes associated with a particular error.
         void reportError(
         #ifdef PROTO
            char *theMessage,
            r_short theCode
         #endif
         );
  4. Create your main function and declare any variables needed for your application. The main function in calculateAge.c will declare variables for the birth day, birth month, and birth year. It will also be responsible for calling the functions declared previously. Finally, main is responsible for freeing any memory used by the application by making a call to the function UFLDestroy.
       #ifdef WINDOWS
       #ifndef OLD_STYLE_PARAMS
          int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR
          lpszCmdParam, int nCmdShow)
       #else
          int PASCAL WinMain(hInstance, hPrevInstance,lpszCmdParam, nCmdShow)
          HANDLE hInstance;
          HANDLE hPrevInstance;
          LPSTR lpszCmdParam;
          int nCmdShow;
       #endif
    
       #else
       #ifndef OLD_STYLE_PARAMS
          int main(int argc, char **argv)
       #else
          int main(argc, argv)
          int argc;
          char **argv;
       #endif
       #endif
       {
       formNodeP theForm;
       int birthYear;
       int birthMonth;
       int birthDay;
       #ifndef WINDOWS
          void *hInstance = NULL;
       #else
       #ifndef MSC
       #ifndef __FLAT__
          _InitEasyWin();
       #endif
       #endif
       #endif
    
    /* First, we call a function that will initialize the special memory and 
          error handling. */
    
          if (initialize((void *)hInstance) != OK)
          {
             reportError("Error in initialize function.\n", 0);
             exit (1);
          }
    
    /* Next, we call a function that will load the form into memory. */
    
          if (loadForm(&theForm) != OK)
          {
             reportError("Error in loadForm function.\n", 0);
             exit (1);
          }
    
    /* This function retrieves the birth year, month and day values (as
          integers) from the original form. */
    
          if (getBirthDate(theForm, &birthYear, &birthMonth, &birthDay) != OK)
          {
             reportError("Error in the getBirthDate function.\n", 0);
             exit (1);
          }
    
    /* This function writes the birth year, month, and day into hidden fields
          in the original form whose values are the arguments for the compute for
          PAGE1.SHOWAGE.value */
    
          if (setBirthDate(theForm, birthYear, birthMonth, birthDay) != OK)
          {
             reportError("Error in the setBirthDate function.\n", 0);
             exit (1);
          }
    
    /* This function saves the processed form in the current directory as
          'output.xfd'. */
    
          if (saveForm(theForm) != OK)
          {
             reportError("Error in the saveForm function.\n", 0);
             exit (1);
          }
    
    /* Now that we are done with the form, we can free the memory by calling
          UFLDestroy. The parameter, 'theForm', is a pointer to the root node of
          the form. This causes the root node and all of its children (the
          complete form) to be deleted from memory. */
    
          UFLDestroy(theForm);
          return(OK);
       }

Initializing the Form Library

All applications that use the API functions must initialize the Form Library to ensure correct error and memory handling behavior. The sample application does this in a separate method calledinitialize. In turn, initialize calls the Form Library function IFSInitialize and passes it the name of the current program.

Define the initialize function to call the function IFSInitialize.IFSInitialize initializes the API environment.
   #ifndef OLD_STYLE_PARAMS
      r_short initialize(void *theInstance)
   #else
   r_short initialize(theInstance)
      void *theInstance;
   #endif
   {
   r_error error;

   /* Call IFSInitialize. The parameters are:
      1. SampleAp : the name of the application being run.
      2. 1.0.0 : the version of the application being run.
      3. 2.6.0 : the version of the API to use by default.
      An error code will be returned if there is a problem. */

      error =IFSInitialize("SampleAp", "1.0.0", "2.6.0");
      if (error != OK)
      {
         reportError("IFSInitialize error %hd.\n", (r_short)error);
         return(NOTOK);
      }
      return(OK);
   }

Loading a Form

Before your program can begin working with a form, you must load it into memory. CalculateAge does this by defining a loadForm function to handle these tasks.

Call UFLReadForm within the implementation of your loadForm function to read in the form, calculateAge.xfd.
   #ifndef OLD_STYLE_PARAMS
      r_short loadForm(formNodeP *form)
   #else
      r_short loadForm(form)
      formNodeP *form;
   #endif
   {

   /* Call UFLReadForm. The parameters are:
      1. calculateAge.xfd : indicates the file on the local drive to read the
         form from.
      2. 0 : because we do not need the #include lines to be resolved.
      The UFLReadForm will return a pointer to the root node of the new form
      structure once it is loaded into memory. */

      if ((*form = UFLReadForm("calculateAge.xfd", 0)) == NULL)
      {
         reportError("Could not load form.\n", 0);
         return(NOTOK);
      }
      return(OK);
}

Retrieving A Value from a Form

Once you have set up and initialized your application with the API and loaded a form into memory, your application is ready to start working with the form. The following code uses UFLGetLiteralByRefEx to get a specific value from the form:

Retrieve the birth date indicated on the form by implementing the getBirthDate function. getBirthDate will make three calls to UFLGetLiteralByRefEx.
   #ifndef OLD_STYLE_PARAMS
      r_short getBirthDate(formNodeP form, int *birYear, *birMonth, 
      int *birDay)
   #else
      r_short getBirthDate(form, birYear, birMonth, birDay)
      formNodeP form;
      int *birYear;
      int *birMonth;
      int *birDay;
   #endif
   {
   r_charP temp=NULL;
   r_short error;

   /* Call UFLGetLiteralByRefEx to get the literal information for the
      'PAGE1.BIRTHYEAR.value' node. An error code will be returned if there
      is a problem. */

      error = UFLGetLiteralByRefEx(form, NULL, "PAGE1.BIRTHYEAR.value", 0, 
         NULL, NULL, &temp);
      if (error != OK)
      {
         reportError("UFLGetLiteralByRefEx error %hd.\n", error);
         return(NOTOK);
      }

      /* If a literal value was returned, convert it into an integer value.
      Otherwise, indicate that no value was entered into the field, and exit
      the program. */

      if (temp != NULL)
         *birYear = atoi((char *)temp);
      else
      {
         reportError("The birth year was not entered.\n",0 );
         return(NOTOK);
      }

      /* Call UFLGetLiteralByRefEx to get the literal information for the
      'PAGE1.BIRTHMONTH.value' node. An error code will be returned if there
      is a problem. */

      error = UFLGetLiteralByRefEx (form, NULL, "PAGE1.BIRTHMONTH.value", 
         0, NULL, NULL, &temp);
      if (error != OK)
      {
         reportError("UFLGetLiteralByRefEx error %hd.\n", error);
         return(NOTOK);
      }

   /* If a literal value was returned, convert it into an integer value.
      Otherwise, indicate that no value was entered into the field, and exit
      the program. */

      if (temp != NULL)
         *birMonth = atoi((char *)temp);
      else
      {
         reportError("The birth month was not entered.\n",0 );
         return(NOTOK);
      }

   /* Call UFLGetLiteralByRefEx to get the literal information for the
      'PAGE1.BIRTHDAY.value' node. An error code will be returned if there is
      a problem. */

      error = UFLGetLiteralByRefEx(form, NULL, "PAGE1.BIRTHDAY.value", 0, 
         NULL, NULL, &temp);
      if (error != OK)
      {
         reportError("UFLGetLiteralByRefEx error %hd.\n", error);
         return(NOTOK);
      }

   /* If a literal value was returned, convert it into an integer value.
      Otherwise, indicate that no value was entered into the field, and exit
      the program. */

      if (temp != NULL)
         *birDay = atoi((char *)temp);
      else
      {
         reportError("The birth day was not entered.\n", 0);
         return(NOTOK);
      }
      return(OK);
   }

Setting a Value in a Form

Once a form is loaded into memory, a developer can set the values associated with any of the item or option nodes located in the form by calling UFLSetLiteralByRefEx.

Change the values of hidden fields in the original form. These hidden fields are arguments for a compute in the SHOWAGE label that calculates the user's age.
   #ifndef OLD_STYLE_PARAMS
      r_short setBirthDate(formNodeP form, int birYear, int birMonth, 
      int birDay)
   #else
   r_short setBirthDate(form, birYear, birMonth, birDay)
      formNodeP form;
      int birYear;
      int birMonth;
      int birDay;
   #endif
   {
   r_short error;
   char *temp[100];

   /* Convert the int to a r_charP and set the value of PAGE1.HIDDENYEAR.value */

      sprintf(temp, "%d", birYear);

   /* Call UFLSetLiteralByRefEx. The parameters are:
      1. form : the formNodeP to use as the starting point for the search.
      2. XFDL : the scheme used to write the reference parameter.
      3. PAGE1.HIDDENYEAR.value : the reference to the node.
      3. 0 : must be zero.
      4. NULL : use the ANSI character set.
      5. NULL : do not use a namespace node.
      6. temp : the value to assign to the literal.
      An error is returned if there is a problem. */

      error = UFLSetLiteralByRefEx(form, NULL, "PAGE1.HIDDENYEAR.value", 
         0, NULL, NULL, (r_charP)temp);
      if(error!= OK)
      {
         reportError("UFLSetLiteralByRefEx error%hd.\n", error);
         return(NOTOK);
      }

   /* Convert the int to an r_charP and set the value of
      PAGE1.HIDDENMONTH.value*/

      sprintf(temp, "%d", birMonth);
      error = UFLSetLiteralByRefEx(form, NULL, "PAGE1.HIDDENMONTH.value", 
         0, NULL, NULL, (r_charP)temp);
      if(error!= OK)
      {
         reportError("UFLSetLiteralByRefEx error%hd.\n", error);
         return(NOTOK);
      }

   /* Convert the int to an r_charP and set the value of PAGE1.HIDDENDAY.value */

      sprintf(temp, "%d", birDay);
      error = UFLSetLiteralByRefEx(form, NULL, "PAGE1.HIDDENDAY.value", 0,
         NULL, NULL, (r_charP)temp);
      if(error!= OK)
      {
         reportError("UFLSetLiteralByRefEx error%hd.\n", error);
         return(NOTOK);
      }
      return(OK);
   }

Writing a Form to Disk

Once you have finished making the desired changes to the form, you should save it to disk. If you want to retain the original form (calculateAge.xfd), you should save the modified form under a new name. This program saves the modified form as Output.xfd.

The following example implements the function saveForm. This function calls the API function UFLWriteForm that writes a form to disk.
   #ifndef OLD_STYLE_PARAMS
      r_short saveForm(formNodeP form)
   #else
      r_short saveForm(form)
      formNodeP form;
   #endif
   {
   r_short error;

   /* Call UFLWriteForm. The parameters are:
      1. form : a pointer to the root node of the form.
      2. output.xfd : the filename you want to use (you could also use a path
         here).
      3. NULL : since we do not want to set a triggeritem.
      4. 0 : since we do not want to allow the transmit options to work.
      An error code is returned if there is a problem. */

      error = UFLWriteForm (form, "output.xfd", NULL, 0); 
      if (error != OK)
      { 
         reportError("UFLWriteForm error %hd.\n", error);
         return(NOTOK); 
      } 
      return(OK); 
}

Closing a Form

Next, you must free the memory used by the form. This is the last operation in the main function of the program.

Free the memory by using UFLDestroy, which destroys the root node of the form and all of its children:
   /* Now that we are done with the form, we can free the memory by
      calling UFLDestroy. The parameter, 'theForm', is a pointer to
      the root node of the form. This causes the root node and all
      of its children (the complete form) to be deleted from memory. */
      UFLDestroy(theForm);
      return(OK);
   }

Testing your Application

Use the sample form that accompanies the API to test the Calculate Age application.

  1. Copy the file calculateAge.xfd to the folder that contains your application. The file is located in the following folder:
       <API Program folder>\Samples\Win32\form\demo\calculate_age\
  2. Open the form in the Viewer to see the original settings.
  3. Run the application that you have just created.
  4. A new file will be created called Output.xfd.
Note: To view the forms provided with this API, you must have a licensed or evaluation copy of IBM Lotus Forms Viewer installed.

Distributing Applications That Use the Form Library

If you distribute applications that use the Form Library, you will also need to distribute a number of API files. Refer to Developing and distributing applications for information about distributing applications that use the Form Library.

Form Library summary

By working through this section you have successfully built the Calculate Age application. In the process, you have learned how to initialize, compile, and test form applications using the following methods from the Form Library:

  • IFSInitialize
  • UFLReadForm
  • UFLGetLiteralByRefEx
  • UFLSetLiteralByRefEx
  • UFLWriteForm
  • UFLDestroy

The source code for the Calculate Age application is included with this API and can be found in the following folder:

   <API Program folder>\Samples\Win32\Form\Demo\Calculate_Age\
For a longer example using the Form Library of methods refer to the other sample application installed with the API. The source files for this application are located in the following folder:
   <API Program folder>\Samples\Win32\Form\Demo\Sample_Application\

To view the forms provided with the sample applications, you must have a copy of the Viewer installed.

Developing an extension with the FCI Library

In this tutorial, you will create a simple extension that adds a multiply function to an XFDL form.

A series of practical examples is provided which you may work through to build an extension called Sample Extension. The extension contains a package of functions called sample_package, which contains one function called multiply. The multiply function multiplies the value of two fields together and stores the result in a third field. Try adding other functions to the package for more practice using the FCI Library.

Although the FCI Library contains many functions, you only need to use a few of them to create a simple package of functions. These are:

  • C_ExtensionInit
  • IFSObject_AllocateObject
  • FunctionCall_SetObjectProc
  • IFXRegisterInterface
  • FCMRegisterFunctionCall
  • FunctionCallEvaluate
  • FunctionCallHelp

The remaining FCI functions allow you to customize the behavior of your functions and extensions. For example you can attach additional information to a particular extension, or get a list of currently registered extensions.

Note: Before you can build extensions using the FCI functions, you must set up your development environment. See Developing and distributing applications.

Creating Extensions with the FCI Functions

The following table is a guide for creating extensions using the FCI Library of functions. Refer to the corresponding page numbers for more details:

Procedure Page
Install the API and related files, as outlined in the IBM Lotus Forms Server - API Installation and Setup Guide. N/A
Set up the extension. Setting Up the Extension
Create the extension source file. Creating the Extension Source File
Set up the extension initialization function. Setting Up the Extension Initialization Function
Create C_ExtensionInit. Creating C_ExtensionInit
Create a new Function Call structure. Creating a New FunctionCall Structure
Define the services of the Function Call structure. Defining Services Provided by the FunctionCall Structure
Register each Function Call structure with the IFX Manager. Registering a FunctionCall with the IFX Manager
Register your package(s) of custom functions with the Forms System. Registering your packages of custom functions using the Function Call Manager
Implement your custom functions. Implementing your custom functions
Provide help information for each of your functions. Providing help information for each of your functions
Compile the extension. Compiling Your Extension
Test the extension. Testing the Extension
Distribute the extension. Distributing Extensions

Setting Up the Extension

A set of template project files for FCI applications have been provided for you. Copy the template files into the directory in which you will be building your application.
  • Files that are compatible with the Visual C++ development environment can be found in the <API Program folder>\Samples\Win32\Fci\Template.
  • If you prefer to setup the FCI application development environment yourself, follow the procedure outlined in Setting up the C environment to use the FCI library.
Creating the Extension Source File

When the Forms System is initialized, the API checks for any existing extensions and calls the initialization function (C_ExtensionInit). Your first step in creating a custom function is to set up and initialize C_ExtensionInit.

  1. Create a new C source file called fciExtension.c.
  2. Include the following preprocessor directives:
    #include "masqutil.h"
    #include "IFX.h"
    #include "xfdllib.h"
    #include "Extension.h"
    #include "FunctionCall.h"
    #include "FunctionCallManager.h"
Note: masqutil.h must always be the first include in any source file that uses the Form Library or the FCI Library.

Setting up the Extension Initialization function

Creating C_ExtensionInit

The API will initialize an extension by calling the function C_ExtensionInit and passing it a pointer to the extension and a pointer to the IFX Manager.

Set up the C_ExtensionInit function within your C source file.
  • C_ExtensionInit is responsible for the registration of all the services that the extension provides.
  • In the following example the C_ExtensionInit function for fciExtension.c is declared and passed two pointers and
  • is the current extension you are initializing.
  • is the IFX Manager structure. Through this structure all other objects and services can be reached.
    #ifndef OLD_STYLE_PARAMS
    PRE_FUNCTION_DECL r_short POST_FUNCTION_DECL C_ExtensionInit(
          Extension *theExtension, IFX *theIFXManager)
    #else
    PRE_FUNCTION_DECL r_short POST_FUNCTION_DECL C_ExtensionInit(
          theExtension, theIFXManager)
    Extension *theExtension;
    IFX *theIFXManager;
    #endif
    {
          /* Additional code removed */
    }
Creating a New FunctionCall Structure

C_ExtensionInit will have to create a FunctionCall structure that contains your custom-built functions.

  1. Declare a pointer to a new FunctionCall structure before you create it in theC_ExtensionInit function. Also, declare any additional variables that you will need in C_ExtensionInit.
    FunctionCall *theFunctionCall;
    r_short theError;
    IFXCriteriaMatchingHandler   *returnPtr;
  2. Create a new FunctionCall structure inside C_ExtensionInit by calling the function, IFSObject_AllocateObject. A generic IFSObject will be created and a generic IFSObject pointer will be returned. Cast the returned pointer to a FunctionCall pointer.
    • In the following example, C_ExtensionInit creates a new FunctionCall structure by calling the IFSObject_AllocateObject function. The pointer returned from the call to IFSObject_AllocateObject is cast to a pointer to a FunctionCall structure.
            if ((theFunctionCall = (FunctionCall*)IFSObject_AllocateObject(
            FUNCTIONCALL_INTERFACE_NAME, FUNCTIONCALL_CURRENT_VERSION, NOTOK, 0))
            == NULL)
            return(NOTOK);
Defining Services Provided by the FunctionCall Structure

The FunctionCall structure you have created will provide two services or functions.

The first service is the implementation of your custom functions. A forward declaration for this service was declared previously as the function FCISimpleFunctions. This function tells the forms driver what to do when custom functions are called from within forms.

The second service defines the help available to form designers when working with your custom functions in Lotus Forms compliant products, such as the Designer. A forward declaration for this service was declared previously as the function FCISimpleHelp.

Use the function called FunctionCall_SetObjectProc to define the services offered by the FunctionCall structure.
  • This function is called once for each service being defined, and is passed the following parameters:
  • TheFunctionCall structure.
  • The function that implements the service.
  • The type of service being defined
  • In the following example FunctionCall_SetObjectProc is called twice. The first call defines the services offered by FCISimpleFunctions. And the second call defines the services offered by FCISimpleHelp.
    if ((theError = FunctionCall_SetObjectProc(theFunctionCall,
          (voidP)FCISimpleFunctions, FUNCTIONCALLEVALUATE)) != OK)
          return(theError);
    if ((theError = FunctionCall_SetObjectProc(theFunctionCall,
          (voidP)FCISimpleHelp, FUNCTIONCALLHELP)) != OK)
          return(theError);
Registering a FunctionCall with the IFX Manager

Each FunctionCall structure must be registered with the IFX Manager as an interface that provides function call support.

C_ExtensionInit, registers the FunctionCall structure with the IFX Manager using the function IFXRegisterInterface.
  • The last parameter in the call to IFXRegisterInterface is a pointer to an object of type IFXCriteriaMatchingHandler. An object of this type can be generated by calling the function FCMGetDefaultListener.
  • In the following example theFunctionCall is registered with the IFX Manager theIFXManager.
    /*    Get the default listener */
    if ((returnPtr = FCMGetDefaultListener()) == NULL)
          return(NOTOK);
    /*    Register the interface with the Extention Manager.*/
    if ((theError = IFXRegisterInterface(theIFXManager,
          (GenericInterface*)theFunctionCall, FUNCTIONCALL_INTERFACE_NAME,
          FUNCTIONCALL_CURRENT_VERSION, FUNCTIONCALL_MIN_VERSION_SUPPORTED,
          0X01000300L, 0, NULL, 0, returnPtr)) != OK)
          return(theError);
Registering your packages of custom functions using the Function Call Manager
Call the Function Call Manager function FCMRegisterFunctionCall from C_ExtensionInit to register each of your custom functions and corresponding package(s) with the Forms System.
  • The FCI allows you to assign a version number to each function that you create. This allows you to provide upgrades to single functions in extensions you have already distributed to users. For more information see About Function Version Numbers, below.
  • When registering your package(s) of functions with the Function Call Manager, be aware of the API package naming conventions. For more information see Package Naming Conventions, below.
  • You must register each of your custom functions separately. So, if you are registering three functions with the Function Call Manager, you must call FCMRegisterFunctionCall three times.
  • In the following example C_ExtensionInit uses the FCMRegisterFunctionCall function to register the multiply function with the Function Call Manager:
    if ((theError = FCMRegisterFunctionCall(theFunctionCall, PACKAGE_NAME,
          "multiply", FCI_MULTIPLY_ID, FCI_FOLLOWS_STRICT_CALLING_PARAMETERS,
          "S,S", FCI_MULTIPLY_VERSION, FCI_MULTIPLY_DESCRIPTION)) != OK)
          return(theError);
          /* Finished */
          return(OK);
    }
Note: About Function Version Numbers

Along with registering your package(s) of custom functions with the Function Call Manager, the FCMRegisterFunctionCall function is also used to specify a version number for each function that you create. In the previous example the multiply function is registered with the version number 0x01000300.

Assigning a version number to each function allows you to provide upgrades to single functions in extensions you have already distributed to users.

For example, if you distributed an extension containing a package of 50 functions for your application and then wanted to change the behavior of one of the functions you could:

  • Write a new extension containing just the upgraded function.
  • Register the new function using FCMRegisterFunctionCall, with the same package name and function name as the original function but with a higher version number.
  • Distribute the new extension to users.

When the API initialized all of the extensions it would find two functions with the same package name and function name. It would deregister the one with the lower version number thereby updating your application.

Package Naming Conventions

The main purpose of package names is to distinguish the functions in a package from those in other packages that could potentially have the same names. All packages you create must contain an underscore in their names. For example the beep function belongs to a package called my_funcs.

  • Choose a name that aptly describes the set of functions you are creating and that is distinct enough to be unique within its realm of usage.
  • Since the package name is an internal logical element of the application, the 8-character naming restriction and case-insensitivity of Windows files do not exist.
Note: A group of functions is provided with the Forms System software as the system package. The system package is reserved for system functions that are defined in the XFDL Specification. You may not add to the system package or call your packages by the name system. Instead, ensure your package names contain an underscore.
Implementing your custom functions
Implement your custom functions as part of the extension.
  • The function defined previously as FCISimpleFunctions implements the behavior of your custom functions.
  • FCISimpleFunctions can be passed several commands by the Forms driver. When a function call in a form is to be evaluated, FCISimpleFunctions will be passed the command FCICOMMAND_RUN as a value for the parameter theCommand.
  • This function must ensure that proper error checking is implemented. The function should check that the package and function names have been properly defined, and that the package name supplied by the Forms driver matches the package name specified in your extension. If you plan to write a multi-thread function, you should also check that the application using the function is thread safe (using MUGetThreadSafeFlag).
  • In the following example, the Multiply function is implemented as part of FCISimpleFunctions in fciExtension.c:
    #ifndef OLD_STYLE_PARAMS
    PRE_FUNCTION_DECL r_short POST_FUNCTION_DECL FCISimpleFunctions(FunctionCall 
       *theObject, 
    
    r_charP thePackageName, r_charP theFunctionName, r_u_long theFunctionID, 
       r_long theFunctionInstance, 
    r_short theCommand, formNodeP theForm, formNodeP theComputeNode, IFSUserData 
    
    **theFunctionDataPtr, IFSUserData **theFunctionInstanceDataPtr, formNodeP 
       *theArgList, r_long 
    theArgListSize, formNodeP theResult)
    #else
    PRE_FUNCTION_DECL r_short POST_FUNCTION_DECL FCISimpleFunctions(theObject, 
    thePackageName, theFunctionName,theFunctionID, theFunctionInstance,theCommand, 
       theForm, 
    theComputeNode, theArgList, theArgListSize, theResult)
    FunctionCallManager *theObject;
    r_charP thePackageName;
    r_charP theFunctionName;
    r_u_long theFunctionID;
    r_long theFunctionInstance;
    r_short theCommand;
    formNodeP theForm;
    formNodeP theComputeNode;
    IFSUserData **theFunctionDataPtr;
    IFSUserData **theFunctionInstanceDataPtr;
    formNodeP *theArgList;
    r_long *theArgListSize;
    formNodeP theResult;
    #endif
    {
    r_charP theFirstParam;
    double firstNum;
    r_charP theSecondParam;
    double secondNum;
    r_short theError;
    double theMultiplyResult;
    char theLiteralBuffer[50]; 
    /*    Verify the input parameters */
          if ((thePackageName == NULL) || (theFunctionName == NULL))
          {
             MessageBox(NULL, "Invalid parameters", "Error", MB_OK);
             return(NOTOK);
          }
    /*    Make sure that the package is the one we are expecting. */
          if (cp_strcmp(thePackageName, PACKAGE_NAME) != OK)
          {
             MessageBox(NULL, "This function was called with the wrong
                package name", "Error", MB_OK);
             return(NOTOK);
          }
    /*    First switch based on the command */
          switch (theCommand)
          {
             case FCICOMMAND_RUN:
    /*    Now switch based on the function name */
                switch (theFunctionID)
                {
    /*    The "multiply" function. */
                   case FCI_MULTIPLY_ID:
                
                      if ((theError = UFLGetLiteralEx(theArgList[0],
                         NULL, &theFirstParam)) != OK)
                      {
                         MessageBox(NULL, "Unable to get the first
                            parameter.", "Error", MB_OK);
                         return(theError);
                      }
                      if ((theError = UFLGetLiteralEx(theArgList[1],
                         NULL, &theSecondParam)) != OK)
                      {
                         MessageBox(NULL, "Unable to get the first
                            parameter.", "Error", MB_OK);
                         return(theError);
                      }
                
    /*    Since the literal can be NULL, we make sure that it isn't */
                      if (theFirstParam == NULL)
                         theFirstParam = "";
                      if (theSecondParam == NULL)
                         theSecondParam = "";
          
    /*    Convert the literal into a number */
                      firstNum = atof(theFirstParam);
                      secondNum = atof(theSecondParam);
    /*    Now multiply the numbers */
                      theMultiplyResult = firstNum * secondNum;
                      sprintf(theLiteralBuffer, "%f", theMultiplyResult);
                      UFLSetLiteralEx(theResult, NULL, theLiteralBuffer);
                      break;
    /*    Error if the function is unknown. */
                   default:
                      MessageBox(NULL, "The function was called with an
                         unrecognized function", "Error", MB_OK);
                   return(NOTOK);
                }
                break;
             case FCICOMMAND_INSTANCEREGISTER:
                break;
             case FCICOMMAND_INSTANCEDEREGISTER:
                break;
             case FCICOMMAND_REGISTER:
                break;
             case FCICOMMAND_DEREGISTER:
                break;
             default:
                break;
          }
    /*    Finished */
          return(OK);
    }
Providing help information for each of your functions

By using the function template FunctionCallHelp, you can provide help information to form designers within a development environment (for example the Designer). Use FunctionCallHelp to help form designers choose and use the correct functions.

Provide in depth help information for each of the functions you create by implementing the function FCISimpleHelp.
  • FCISimpleHelp must be implemented since the service was defined previously with the call to FunctionCall_SetObjectProc.
  • In the following example, FCISimpleHelp provides help information for the multiply function.
    #ifndef OLD_STYLE_PARAMS
    PRE_FUNCTION_DECL r_short POST_FUNCTION_DECL FCISimpleHelp(FunctionCall 
       *theObject, 
    r_charP thePackageName, r_charP theFunctionName, r_u_long theFunctionID, 
       IFSUserData 
    **theFunctionDataPtr, r_charP *theQuickDescPtr, r_charP *theFunctionDescPtr, 
       r_charP 
    *theSampleCodePtr, r_charP **theArgsNameListPtr, r_long *theArgsNameListSizePtr, 
       r_charP 
    **theArgsDescListPtr, r_long *theArgsDescListSizePtr, r_short 
       **theArgsFlagListPtr, r_long 
    *theArgsFlagListSizePtr, r_charP *theRetValDescPtr, r_short 
       *theRetValFlagPtr)
    #else
    PRE_FUNCTION_DECL r_short POST_FUNC_DECL FCISimpleHelp(theObject, 
       thePackageName, 
    theFunctionName, theFunctionID, theFunctionDataPtr, theQuickDescPtr, 
       theFunctionDescPtr, 
    theSampleCodePtr, theArgsNameListPtr, theArgsNameListSizePtr, 
       theArgsDescListPtr, 
    theArgsDescListSizePtr, theArgsFlagListPtr, theArgsFlagListSizePtr, 
       theRetValDescPtr, theRetValFlagPtr)
    FunctionCall *theObject;
    r_charP thePackageName;
    r_charP theFunctionName;
    r_u_long theFunctionID;
    IFSUserData **theFunctionDataPtr;
    r_charP *theQuickDescPtr;
    r_charP *theFunctionDescPtr;
    r_charP *theSampleCodePtr;
    r_charP **theArgsNameListPtr;
    r_long *theArgsNameListSizePtr;
    r_charP **theArgsDescListPtr;
    r_long *theArgsDescListSizePtr;
    r_short **theArgsFlagListPtr;
    r_long *theArgsFlagListSizePtr;
    r_charP *theRetValDescPtr;
    r_short *theRetValFlagPtr;
    #endif
    {
          switch(theFunctionID)
          {
             case FCI_MULTIPLY_ID:
                if (((*theQuickDescPtr) = cp_strdup("Multiplies two numbers
                   together")) == NULL)
                {
                   MessageBox(NULL, "Out of memory", "Error", MB_OK);
                   return(NOTOK);
                }
                if (((*theFunctionDescPtr) = cp_strdup(
                   "This function multiplies two numbers together."
                   "/n It takes the values of two fields"
                   "/n and finds their product with a precision"
                   "/n of up to seven decimal places.")) == NULL)
                {
                   MessageBox(NULL, "Out of memory", "Error", MB_OK);
                   return(NOTOK);
                }
                if (((*theSampleCodePtr) = cp_strdup(
                   "\t<field sid=\"PRODUCT_FIELD\">\n"
                   "\t\t<value compute=\"test_Package.multiply" 
                   "(field1.value, field2.value)\"></value>\n"
                   "\t\t<size>\n"
                   "\t\t\t<ae>10</ae>\n"
                   "\t\t\t<ae>1</ae>\n"
                   "\t\t</size>\n"
                   "\t</field>\n")) == NULL)
                {
                   MessageBox(NULL, "Out of memory", "Error", MB_OK);
                   return(NOTOK);
                }
                if (((*theRetValDescPtr) = cp_strdup(
                   "The product of the two parameters given")) == NULL)
                {
                   MessageBox(NULL, "Out of memory", "Error", MB_OK);
                   return(NOTOK);
                }
                break;
             default:
                break;
          }
          return(OK);
    }

Compiling Your Extension

Once you have generated the C source file for your extension, you must compile the source code to create the extension.

  • Use a compiler for C that is supported by the API to compile your extension.
  • Before building your extension you should have a .c source file that represents your extension. After compiling the .c file you will have a set of files with the same name as the .c files but with the extension .ifx.
  • For example, after compiling the source code for the extension fciExtension.c, your C compiler will create the corresponding extension: fciExtension.ifx.
  • The details of compiling your source code are not included here. Consult your compiler documentation for information.

Testing the Extension

  1. To test the extension with an API application:
    • Copy the extension files that you just created to the following directory:
            <Windows System>\PureEdge\Extensions\

      To test the extension with Viewer:

    • Copy the extension files that you just created to the following directory:
            <Viewer Directory>\Extensions\
  2. Use the sample form that accompanies the API to test the multiply function. Copy the file Multiply.xfd from <API Program folder>\Samples\Win32\Fci\Tutorial\ to the folder containing your application.
  3. Fill out the form and see if the product of Field1 and Field2 is returned.
Note: To view the forms provided with this API, you must have a licensed or evaluation copy of the Lotus Forms Viewer installed.

Distributing Extensions

Once you have created and tested your extensions you can distribute them as .ifx files

To distribute your extensions so that they may be used by a specific Lotus Forms product:

  • Copy the extension file to the Extensions folder of the Lotus Forms product that will use the extension.
    • For example, in order for the multiply function to work in the Viewer, you would copy the file fciExtension.ifx to the following folder:
               <Viewer Program folder>\Extensions

To distribute your extensions so that they may be used by all Lotus Forms products:

  • Copy the extension file to the Forms System Global Extensions folder.
    • For example in order for the multiply function to work in the Viewer you would copy the file fciExtension.ifx to the following folder:
               C:\<Windows System>\PureEdge\Extensions

FCI Library summary

By working through this section you have successfully built an extension. In the process you have learned how to initialize, compile and test FCI applications and use the following functions from the FCI Library:

  • IFSObject_AllocateObject
  • FunctionCall_SetObjectProc
  • IFXRegisterInterface
  • FCMRegisterFunctionCall

This FCI application has been included with this API and can be found in the folder <API Program folder>\Samples\Win32\Fci\Demo\Multiply.

To view the forms provided with these sample applications, you must have a licensed or evaluation copy of the Lotus Forms Viewer installed.

Note: Files that are compatible with the Visual C++ development environment can be found in the <API Program folder>\Samples\Win32.

COM Tutorials

Learn how to manipulate and extend forms in Microsoft Visual Basic with IBM Lotus Forms Server - COM API.


Developing an application in Visual Basic

In this tutorial, you will create an application that shows you how to read, modify, and write forms using the Form Library

By working through the tutorial, you will perform all of the steps involved in creating a simple application that uses the API functions, including:

  • Initializing the Form Library.
  • Reading a form into your application.
  • Setting and retrieving form data.
  • Removing a form from memory.
  • Destroying a form.

The sample application in this tutorial reads an input form called CalculateAge.xfd into memory. It retrieves the user's birth day, month, and year as well as the current date from the form. It then places these values into hidden fields in the form. This triggers the form to compute the user's age and display the result. When complete, the application saves the changes made to calculateAge.xfd as a new form called Output.xfd.

Note: The sample application described in this tutorial is included with the API and can be found in the folder: <API Program Folder>\Samples\COM\Form\Demo\Calculate_Age\

The tutorial describes the following tasks:

Setting Up Your Application

This example assumes that you are developing a program in Microsoft Visual Basic using Microsoft Studio. To begin, you must first set up your development environment to use the API type library.
  1. Create a new Visual Basic project.
  2. Any project using the API must include the following type library:
    • IFS_COM_API.tlb

      To add this to your Visual Basic Project, open the References ; dialog from the Project menu and select “InternetForms API”.

  3. Set up the rest of your application. This generally includes setting up your main algorithm and declaring any variables you will need. The following code sets up the Calculate Age application:
       ' Create the Main method for the program.
    
       Sub Main()
          
          ' Declare a number of variables. TheForm represents the form, while the
          ' other variables are values we will read from the form.
    
          Dim TheForm As IFormNodeP
          Dim BirthYear As Integer
          Dim BirthMonth As Integer
          Dim BirthDay As Integer
    
          ' The program's Main consists of a number of calls to other functions.
    
          Initialize
    
          Set TheForm = LoadForm
    
          BirthYear = GetBirthYear(TheForm)
          BirthMonth = GetBirthMonth(TheForm)
          BirthDay = GetBirthDay(TheForm)
    
          SetBirthYear BirthYear, TheForm
          SetBirthMonth BirthMonth, TheForm
          SetBirthDay BirthDay, TheForm
    
          SaveForm TheForm
    
          ' Free the memory in which the form was stored.
    
          TheForm.Destroy
    
       End Sub

Initializing the Form Library

All applications that use the API functions must initialize the Form Library to ensure correct error and memory handling behavior. The sample application does this in a separate method calledInitialize. In turn, Initialize calls the Form Library function IFSInitialize and passes it the name of the current program.

Define the Initialize function to call the function IFSInitialize. IFSInitialize initializes the API environment.
   Sub Initialize()

      Dim DTK As DTK

      ' Get the DTK object. You need this call the IFSInitialize function.

      Set DTK = CreateObject("PureEdge.DTK")

      ' Call DTK.IFSInitialize.  DTK is a static class representing the Java

      ' API development toolkit.  The parameters are:
      '   1. CalculateAge: the name of the application being run.
      '   2. 1.0.0 : the version of the application being run.
      '   3. 2.6.0 : the version of the API being run.
      ' An exception will be thrown if there is a problem.

      DTK.IFSInitialize "CalculateAge", "1.0.0", "2.6.0"

   End Sub

Loading a Form

Before your program can begin working with a form, you must load it into memory. CalculateAge does this by defining a LoadForm function to handle these tasks.

Call ReadForm within the implementation of your loadForm function to read in the form, calculateAge.xfd.
   Function LoadForm() As IFormNodeP

      Dim XFDL As XFDL

      ' Get the XFDL object. You need this to call the ReadForm function.
      Set XFDL = CreateObject("PureEdge.xfdl_XFDL")
      ' Call XFDL.ReadForm.  The parameters are:
      '   1. calculateAge.xfd : indicates the file on the local drive to read
      '       the form from.
      '   2. 0 : no special behavior.
      '   readForm will return a reference to the root node of the
      '   new form structure once it is loaded into memory.  An exception
      '   will be thrown if there is a problem.

      Set LoadForm = XFDL.ReadForm("c:\calculateage.xfd", 0)

   End Function

Retrieving A Value from a Form

Once you have set up and initialized your application with the API and loaded a form into memory, your application is ready to start working with the form. The following code uses GetLiteralByRefEx to get a specific value from the form:

Retrieve the birth date from the form as three separate values: the birth day, birth month, and birth year. To do this, we will use three separate functions. Each function uses GetLiteralByRefEx to retrieve one of the values.
   Function GetBirthDay(TheForm) As Integer

      Dim BDay As String

      ' Call IFormNodeP.GetLiteralByRefEx to get the literal information for
      ' the PAGE1.BIRTHDAY.value node.  An exception will be thrown if
      ' there is a problem.

      BDay = TheForm.GetLiteralByRefEx(vbNullString, _
         "PAGE1.BIRTHDAY.value",  0, vbNullString, Nothing)

      ' If a literal value was returned, convert it into an integer value;
      ' otherwise, indicate that no value was entered into the field
      ' and throw an exception.

      If (Len(BDay) > 0) Then
         GetBirthDay = CInt(BDay)
      Else
         MsgBox "The birth day was not entered.", vbCritical
         Stop
      End If
    
   End Function

' Similar to GetBirthDay

   Function GetBirthMonth(TheForm) As Integer

      Dim BMonth As String

      BMonth = TheForm.GetLiteralByRefEx(vbNullString, _
         "PAGE1.BIRTHMONTH.value", 0, vbNullString, Nothing)

      If (Len(BMonth) > 0) Then
         GetBirthMonth = CInt(BMonth)
      Else
         MsgBox "The birth month was not entered.", vbCritical
         Stop
      End If

   End Function

' Similar to getBirthDay()

   Function GetBirthYear(TheForm) As Integer

      Dim BYear As String

      BYear = TheForm.GetLiteralByRefEx(vbNullString, _
         "PAGE1.BIRTHYEAR.value", 0, vbNullString, Nothing)

      If (Len(BYear) > 0) Then
         GetBirthYear = CInt(BYear)
      Else
         MsgBox "The birth year was not entered.", vbCritical
         Stop
      End If

   End Function

Setting a Value in a Form

Once a form is loaded into memory, a developer can set the values associated with any of the item or option nodes located in the form by calling SetLiteralByRefEx.

Change the values of hidden fields in the original form. These hidden fields are arguments for a compute in the SHOWAGE label that calculates the user's age. To do this, we will use three separate functions. Each function uses SetLiteralByRefEx to set one of the values.
   Sub SetBirthDay(BDay As Integer, TheForm As IFormNodeP)

      Dim Day As String
      
      ' Convert the birthday to a String

      Day = CStr(BDay)

      ' Call TheForm.SetLiteralByRefEx. The parameters are:
      '   1. vbNullString : reserved. Must be vbNullString.
      '   2. PAGE1.HIDDENDAY.value : the reference to the node.
      '   3. 0 : must be zero.
      '   4. vbNullString : sets the character set to ANSI.
      '   5. Nothing : no namespace node required.
      '   6. Day : the value to assign to the literal.
      ' An Exception will be thrown if there is a problem.

      TheForm.SetLiteralByRefEx vbNullString, "PAGE1.HIDDENDAY.value", _
         0, vbNullString, Nothing, Day

   End Sub

   ' Similar to SetBirthDay()

   Sub SetBirthMonth(BMonth As Integer, TheForm As IFormNodeP)

      Dim Month As String

      ' Convert the birth month to a String
      
      Month = CStr(BMonth)

      ' Set the birth month as a value in the form.
      TheForm.SetLiteralByRefEx vbNullString, "PAGE1.HIDDENMONTH.value", _
         0, vbNullString, Nothing, Month

   End Sub

   ' Similar to setBirthDay()

   Sub SetBirthYear(BYear As Integer, TheForm As IFormNodeP)

      Dim Year As String

      ' Convert the birth year to a String

      Year = CStr(BYear)

      ' Set the birth year as a value in the form.

      TheForm.SetLiteralByRefEx vbNullString, "PAGE1.HIDDENYEAR.value", _
         0, vbNullString, Nothing, Year

   End Sub

Writing a Form to Disk

Once you have finished making the desired changes to the form, you should save it to disk. If you want to retain the original form (calculateAge.xfd), you should save the modified form under a new name. This program saves the modified form as Output.xfd.

The following example implements the function SaveForm. This function calls the API function WriteForm that writes a form to disk.
   Sub SaveForm(TheForm)

      ' Call theForm.writeForm.  theForm is the root node of the form to
      ' be written.  The parameters are:
      '   1. output.xfd : the filename you want to use (you could also use
      '        a path here).
      '   2. Nothing : since we do not want to set a triggeritem.
      '   3. 0 : since we do not want to allow the transmit options to work.
      ' An exception is thrown if there is a problem.

      TheForm.WriteForm "output.xfd", Nothing, 0
   
   End Sub

Closing a Form

Next, you must free the memory used by the form. This is the last operation in the main function of the program.

The program's main method calls the API's Destroy method to delete TheForm object.
      ' Now that we are done with the form, we can free the memory by
      ' calling Destroy.  The object, 'TheForm', is a reference to
      ' the root node of the form.  This causes the root node and all
      ' of its children (the complete form) to be deleted from memory.
      
      TheForm.Destroy

   End Sub

Testing your Application

Use the sample form that accompanies the API to test the Calculate Age application.

  1. Copy the file calculateAge.xfd to the folder that contains your application. The file is located in the following folder:
       <API Program folder>\Samples\\form\demo\calculate_age\
       <API Program folder>\Samples\Win32\COM\demo\calculate_age\
  2. Open the form in the Viewer to see the original settings.
  3. Run the application that you have just created.
  4. A new file will be created called Output.xfd.
Note: To view the forms provided with this API, you must have a licensed or evaluation copy of IBM Lotus Forms Viewer installed.

Distributing Applications That Use the Form Library

If you distribute applications that use the Form Library, you will also need to distribute a number of API files. Refer to Developing and distributing applications for information about distributing applications that use the Form Library.

Form Library summary

By working through this section you have successfully built the Calculate Age application. In the process, you have learned how to initialize, compile, and test form applications using the following methods from the Form Library:

  • IFSInitialize
  • ReadForm
  • GetLiteralByRefEx
  • SetLiteralByRefEx
  • WriteForm
  • Destroy

The source code for the Calculate Age application is included with this API and can be found in the following folder:

   <API Program folder>\Samples\COM\Form\Demo\Calculate_Age\

To view the forms provided with the sample application, you must have a copy of the Viewer installed.

evaluate method

Description

This method performs the necessary work for your custom-built function. You will have to insert the details of your custom functions within this method.

Method

public void evaluate(
   String thePackageName, 
   String theFunctionName,
   int theFunctionID,
   int theFunctionInstance,
   short theCommand,
   com.PureEdge.xfdl.FormNodeP theForm, 
   com.PureEdge.xfdl.FormNodeP theComputeNode, 
   com.PureEdge.IFSUserDataHolder theFunctionData, 
   com.PureEdge.IFSUserDataHolder theFunctionInstanceData, 
   com.PureEdge.xfdl.FormNodeP[ ] theArgList, 
   com.PureEdge.xfdl.FormNodeP theResult
   ) throws UWIException;

Parameters

Expression Type Description
thePackageName String The name of the package that contains the function.
theFunctionName String The name of the function.
theFunctionID int A unique number that can be used to identify the function.
theFunctionInstance int A unique number that differentiates one instance of the function from another instance. See Notes for more information.
theCommand short The name of the command for this method to perform. See Notes for more information. Other commands can be found within the manual.
theForm FormNodeP The form that contains the function.
theComputeNode FormNodeP The node within the form that stores the function. See Notes for more information.
theFunctionData IFSUserDataHolder Reserved. Although this expression is not used, it must be present.
theFunctionInstanceData IFSUserDataHolder Reserved. Although this expression is not used, it must be present.
theArgList FormNodeP [ ] The list of arguments. See Notes for more information.
theResult FormNodeP The FormNodeP object in which you should store the result. Simply use setLiteralEx on this object to store the result.

Returns

Nothing if call is successful or throws a generic exception (UWIException) if an error occurs.

Notes

  • theCommand — the value of theCommand represents the command that evaluate will perform.
    • The value of theCommand depends on the value of the parameter called theFlags in the method called registerFunctionCall.
    • Usually theCommand will be set to FCICOMMAND_RUN. This indicates that a function must be evaluated.
    • Other possible values for theCommand include:
    • FCICOMMAND_INSTANCEDEREGISTER — This constant indicates that evaluate should execute some procedure when an instance of the function has been deregistered.
    • FCICOMMAND_DEREGISTER — This constant indicates that evaluate should execute some procedure when the function has been deregistered.
    • FCICOMMAND_REGISTER — This constant indicates that evaluate should execute some procedure when the function is registered.
    • FCICOMMAND_INSTANCEREGISTER — This constant indicates that evaluate should execute some procedure when an instance of the function is registered.
  • theFunctionInstance — is a unique number that differentiates one instance of the function with another instance. For example, if a form contains two calls to the function testPackage.multiply then two unique values for theFunctionInstance variable will exist.
  • theComputeNode — is the node within the form that contains the function. For example, if you have an item such as:
       <LABEL SID = "L1">
          <VALUE COMPUTE = "testPackage.multiply('7', '6')"></VALUE>
       </LABEL>

Then theComputeNode will point to the node that represents the value option.

  • theFunctionInstanceData - is data specific to an instance of a function. It will always be returned when the instance of the function is called. This object is only provided when the FCI_WANTS_INSTANCE_DATA flag is provided during the registerFunctionCall call.
  • theArgList — Each argument's value is stored as a literal within a FormNodeP object. For example, to get the value of the first argument, type the following:
       theArgList[0].getLiteralEx(null)
Note: To get the number of arguments in theArgList use: theArgList.length

Example

   public class FciFunctionCall extends com.PureEdge.xfdl.FunctionCallImplBase 
   implements FunctionCall
   {
   public static final int FUNCTION_ID = 1;
      
      /* Additional Code Removed */
      public void evaluate(String thePackageName, 
         String theFunctionName, int theFunctionID, 
         int theFunctionInstance, short theCommand, 
         com.PureEdge.xfdl.FormNodeP theForm, 
         com.PureEdge.xfdl.FormNodeP theComputeNode, 
         com.PureEdge.IFSUserDataHolder theFunctionData, 
         com.PureEdge.IFSUserDataHolder theFunctionInstanceData, 
         com.PureEdge.xfdl.FormNodeP [] theArgList, 
         com.PureEdge.xfdl.FormNodeP theResult) throws UWIException
      {
   /* The first switch in this method is based on theCommand.  The only case
      that we are interested in handling is FCICOMMAND_RUN that indicates
      that we should evaluate a function. */
         switch (theCommand)
         {
         case FunctionCall.FCICOMMAND_RUN:
   /* The second switch is based on theFunctionID that you set for each 
      of your custom functions. This makes it easy for a single FunctionCall
      object to support multiple functions. */
            switch(theFunctionID)
            {
            case FciFunctionCall.FUNCTION_ID:
            /* Insert the Details of your custom function here */
               break;
            }
            break;
   
            default:
            break;
         }
      }
      
      /* Additional code Removed */
   }

help method

Description

Provides help information about each of your custom functions in the form development environment (for example, Lotus Forms Designer).

Method

public void help(
   String thePackageName, 
   String theFunctionName,
   int theFunctionID, 
   com.PureEdge.IFSUserDataHolder theFunctionData, 
   com.PureEdge.StringHolder theQuickDesc, 
   com.PureEdge.StringHolder theFunctionDesc, 
   com.PureEdge.StringHolder theSampleCode, 
   com.PureEdge.StringListHolder theArgsNameList, 
   com.PureEdge.StringListHolder theArgsDescList, 
   com.PureEdge.ShortListHolder theArgsFlagList, 
   com.PureEdge.StringHolder theRetValDesc, 
   com.PureEdge.ShortHolder theRetValFlag
   ) throws UWIException;

Parameters

Expression Type Description
thePackageName String The name of the package that contains the function.
theFunctionName String The name of the function.
theFunctionID int A unique number that can be used to identify the function.
theFunctionData IFSUserDataHolder Reserved. Although this expression is not used, it must be present.
theQuickDesc StringHolder The method sets a short one-line description of what the function does.
theFunctionDesc StringHolder The method will set a longer more detailed description of the function.
theSampleCode StringHolder The method will set an example of the XFDL code used to call your function, including an example of the function parameters.
theArgsNameList StringListHolder The method will set a list of arguments that your function takes. See Notes for more information.
theArgsDescList StringListHolder The method will set a description of each of the arguments in the theArgsNameList. See Notes for more information..
theArgsFlagList ShortListHolder The method will set a list of bit flags representing the type of each argument that the function takes. See Notes for more information.
theRetValDesc StringHolder The method will set a description of your custom function's return value.
theRetValFlag ShortHolder The method will set a bit flag representing the type of the return value. See Notes for more information. Simply use setLiteralEx on this object to store the result.

Returns

Nothing if call is successful or throws a generic exception (UWIException) if an error occurs.

Notes

  • Refer to the table FunctionCall Class Constants for possible values for:
    • theArgsFlagList
    • theRetValFlag
  • For both theArgsNameList and theArgsDescList, if you have no arguments you must set the value to null. For example:
       theArgsNameList.value = null;

Example

   public void help(String thePackageName, 
      String theFunctionName, int theFunctionID, 
      com.PureEdge.IFSUserDataHolder theFunctionData, 
      com.PureEdge.StringHolder theQuickDesc, 
      com.PureEdge.StringHolder theFunctionDesc, 
      com.PureEdge.StringHolder theSampleCode, 
      com.PureEdge.StringListHolder theArgsNameList, 
      com.PureEdge.StringListHolder theArgsDescList, 
      com.PureEdge.ShortListHolder theArgsFlagList, 
      com.PureEdge.StringHolder theRetValDesc, 
      com.PureEdge.ShortHolder theRetValFlag) throws UWIException
   {
   /* Switch on theFunctionID. This makes it easy for a single FunctionCall
      object to support multiple functions. */
      switch(theFunctionID)
      {
   /* Remember that you must define an ID number for each custom function
      that you create. In the example below the constant MULTIPLY represents
      the identification number for the multiply function. */
         case FciFunctionCall.MULTIPLY:
            theQuickDesc.value = "multiplies two numbers together";
            theFunctionDesc.value = "This function takes two numeric " + 
               "parameters and multiplies the two numbers together and " +
               "returns the result.";
            theSampleCode.value = "\tlabel1 = new label\n" + "\t{\n" + 
               "\t\tvalue = testPackage.multiply(\"10\", field2.value);\n" +
               "\t\tsize = [\"10\", \"1\"];\n" + "\t}\n"      + 
               "\tfield2 = new field\n"               + 
               "\t{\n" + "\t\tvalue = \"7\";\n" + "\t}\n";
            
   /* Notice that in defining theArgsNameList below, you must create 
     the list before providing a value for each element in the list. */
            theArgsNameList.value = new String[2];
            theArgsNameList.value[0] = "number1";
            theArgsNameList.value[1] = "number2";
   /* Notice that in defining theArgsDescList below, you must create 
      the list before providing a value for each element in the list. */
            theArgsDescList.value = new String[2];
            theArgsDescList.value[0] = "The first number";
            theArgsDescList.value[1] = "The second number";
            theRetValDesc.value = "The result";
            break;
      }
}

registerFunctionCall method

Description

Registers your custom function with the Function Call Manager.

Method

public void registerFunctionCall(
   com.PureEdge.xfdl.FunctionCall theFCIInterface, 
   String thePackageName,
   String theFunctionName,
   int theFunctionID,
   int theFlags,
   String theCallingParams,
   int theVersion,
   String theQuickDesc
  ) throws UWIException;

Parameters

Expression Type Description
theFCIInterface FunctionCall The FunctionCall object that will handle requests for the function. Setting: The FunctionCall object that is registering the function. See Notes for more information.
thePackageName String The name of the package that will contain the function.
theFunctionName String The name of the function.
theFunctionID int A unique number that can be used to identify the function. See Notes for more information.
theFlags int A set of flags which indicate how the custom function will be evaluated. Setting: Typically FCI_FOLLOWS_STRICT_CALLING_PARAMETERS or 0. See Notes for more information.
theCallingParams String The list of parameters that this function takes. Setting: S, O, or R. See Notes for more information.
theVersion int The version number of the function. Setting: Function Version Number. See Defining a Version Number for more information.
theQuickDesc String A short, one-line description of what the function does.

Returns

Nothing if call is successful or throws a generic exception (UWIException) if an error occurs.

Notes

  • theFCIInterface — Typically a FunctionCall object will register its own function with the Function Call Manager. Use the keyword this to represent the current object.
  • theFunctionID — Each function that you create as part of a particular package must have a unique identification number. Define each function's ID number as a constant at the beginning of the class. For example, the multiply function has an ID number of 1:
       public static final int MULTIPLY_ID = 1;
  • theCallingParams — List the type of each parameter that the function will take and separate each value with a comma.
    • Use S to indicate a string parameter.
    • If the parameter is optional, then an O is added after the S.
    • If the parameter can repeat, then an R is added after the S.
    • For example, if you were to register a function that had to have one parameter and optionally a second parameter then the theCallingParams would look like the following:
         "S,SO"
    • If there are no parameters, use an empty string ("").

Defining a Version Number

  • If multiple FunctionCall objects register the same function for the same package, then the function with the highest version number is used.
  • Version numbers are defined in hexadecimal format as follows, where the 0300 is a constant and must be present :
  • 0x<major><minor><0300>
  • For example, a function that is version 2.1 would be represented as
  • 0x02010300
  • Define a function's version number in the parameter theVersion.
Note: For more information about using version numbers refer to page.

Example

   public class FciFunctionCall extends com.PureEdge.xfdl.FunctionCallImplBase 
   implements FunctionCall
   {
   public static final int FUNCTION_ID = 1;
      
      /* Additional Code Removed */
       theFCM.registerFunctionCall(this,"sample_package", 
         "multiply",FciFunctionCall.FUNCTION_ID, 
         FCI.FCI_FOLLOWS_STRICT_CALLING_PARAMETERS, "S,S", 0x01000300, 
         "Multiplies two numbers");
   }

registerInterface method

Description

Registers a FunctionCall object with the IFX Manager.

Method

public void registerInterface(
   com.PureEdge.GenericInterface theInterface,
   String theInterfaceName,
   int theInterfaceVersion,
   int theMinInterfaceVersion,
   int theImplementationVersion,
   int theFlags,
   String [] theCriteriaList,
   com.PureEdge.ifx.IFXCriteriaMatchingHandler theCriteriaHandler
  ) throws UWIException;

Parameters

Expression Type Description
theInterface GenericInterface The object that you are registering with the IFX Manager. Typical setting: this (if the object is registering itself)
theInterfaceName String The name of the Interface that you are registering. In this case a Function Call Interface. Typical setting: FunctionCall.FUNCTIONCALL_INTERFACE_ NAME
theInterfaceVersion int The function call interface version. Typical setting: FunctionCall.FUNCTIONCALL_CURRENT_ VERSION
theMinInterface Version int The minimum version that the interface will support. Typical setting: FunctionCall.FUNCTIONCALL_ MIN_VERSION_SUPPORTED
theImplementation Version int The version of the object you are registering. This is typically 0x01000300. If there are multiple objects with the same name available, the one with the highest version number is registered.
theFlags int Reserved. Setting: 0
theCriteriaList String [ ] Reserved. Setting: null
theCriteriaHandler com.PureEdge.ifx.IFX Criteria-Matching Handler Reserved. Setting: theFCM.getDefaultListener( )

Returns

Nothing if call is successful or throws a generic exception (UWIException) if an error occurs.

Notes

  • Typically, you will have to retrieve the Function Call Manager from the IFX Manager using getFunctionCallManager before you call registerInterface.
  • Typically the registerInterface parameter called theCriteriaHandler is set to:
          theFCM.getDefaultListener( )

Note that theFCM is a FunctionCallManager object which represents the Function Call Manager.

Example

In the following example, theIFX represents the IFX Manager

   public FciFunctionCall(IFX IFXMan) throws UWIException
      {
      FunctionCallManager theFCM;
         if ((theFCM = IFSSingleton.getFunctionCallManager()) == null) 
            throw new UWIException("Needed Function Call Manager");
         IFXMan.registerInterface(this, 
            FunctionCall.FUNCTIONCALL_INTERFACE_NAME,
            FunctionCall.FUNCTIONCALL_CURRENT_VERSION,
            FunctionCall.FUNCTIONCALL_MIN_VERSION_SUPPORTED, 
            0x01000300, 0, null, theFCM.getDefaultListener( ));
      }

FunctionCall Class Constants

The following table lists the constants that are used within the FunctionCall class along with a short description of each constant:

Named Constants Description
FunctionCall.FCI_FOLLOWS_ STRICT_CALLING_ PARAMETERS Used in the method registerFunctionCall as a possible value for the parameter theFlags.

Indicates that the user of your custom function must provide the parameters you define in the registerFunctionCall parameter theCallingParams.

FunctionCall.FCI_WANTS_ INSTANCE_DEREGISTER_ CALL Used in the method registerFunctionCall as a possible value for the parameter theFlags.

Indicates that the Forms System should call evaluate with theCommand set to FCICOMMAND_ INSTANCEDEREGISTER when an instance of the function is deregistered.

FunctionCall.FCI_WANTS_ INSTANCE_REGISTER_CALL Used in the method registerFunctionCall as a possible value for the parameter theFlags.

Indicates that the Forms System should call evaluate with theCommand set to FCICOMMAND_INSTANCEREGISTER when an instance of the function is registered.

FunctionCall.FCI_WANTS_ REGISTER_CALL Used in the method registerFunctionCall as a possible value for the parameter theFlags.

Indicates that the Forms System should call evaluate with theCommand set to FCICOMMAND_REGISTER when the function is registered.

FunctionCall.FCIARGFLAG_ OPTIONAL Used as a possible value for the flag theArgsFlagList in the method help. This value represents an optional parameter.
FunctionCall.FCIARGFLAG_ OPTIONAL Used as a possible value for the flag theRetValFlag in the method help. This value represents a return value that is optional.
FunctionCall.FCIARGFLAG_ REPEATING Used as a possible value for the flag theArgsFlagList in the method help. This value represents a repeating parameter.
FunctionCall.FCIARGFLAG_ STRING Used as a possible value for the flag theArgsFlagList in the method help. This value represents a parameter of type String.
FunctionCall.FCIARGFLAG_ STRING Used as a possible value for the flag theRetValFlag in the method help. This value represents a return value of type String.
FunctionCall.FCICOMMAND_ DEREGISTER Used in the method evaluate as a possible value for the parameter theCommand.

This constant indicates that evaluate should execute some procedure when the function has been deregistered.

FunctionCall.FCICOMMAND_

INSTANCEDEREGISTER

Used in the method evaluate as a possible value for the parameter theCommand.

This constant indicates that evaluate should execute some procedure when an instance of the function has been deregistered.

FunctionCall.FCICOMMAND_

INSTANCEREGISTER

Used in the method evaluate as a possible value for the parameter theCommand.

This constant indicates that evaluate should execute some procedure when an instance of the function is registered.

FunctionCall.FCICOMMAND_ REGISTER Used in the method evaluate as a possible value for the parameter theCommand.

This constant indicates that evaluate should execute some procedure when the function is registered.

FunctionCall.FCICOMMAND_ RUN Used in the method evaluate as a possible value for the parameter theCommand.

This constant indicates that evaluate should evaluate a given function.

FunctionCall.FUNCTIONCALL_

CURRENT_VERSION

Current version of the Function Call Interface.

Used in the methods registerInterface as a value for the parameter theInterfaceVersion.

FunctionCall.FUNCTIONCALL_

INTERFACE_NAME

Name of the Function Call Interface.

Used in the methods registerInterface as a value for the parameter theInterfaceName

FunctionCall.FUNCTIONCALL_ MIN_VERSION_SUPPORTED The minimum version of the Function Call Interface that is supported.

Used in the methods registerInterface as a value for the parameter theMinInterfaceVersion.

Developing and distributing applications


Overview of the XFDL Form Structure

This section provides an overview of an XFDL form as it is represented in memory. You must understand the memory structure of a form to effectively develop applications using the API.

The Node Structure

When a form is loaded into memory, it is constructed as a series of linked nodes. Each node represents an element of the form, and together these nodes create a tree that describes the form. The following diagram illustrates the general composition of a single node.

A box divided into four, containing the names contained within a single node. The names are: Type, Literal, Identifier and Compute.

Each node within the tree has the following properties:

  • Type — For page and item nodes, this describes the type of node, such as button, line, field, and so on. Page nodes are always of type page.
  • Literal — The literal value of the node (for example, a literal string). If the node has a formula, the result of the formula will be stored here.
  • Identifier — The page tag, item tag, option name, or custom name assigned to the node.
  • Compute — The compute assigned to the node (for example, "field_1.value + field_2.value"). The result of the compute will be stored in the literal of the node.

Depending on the node type, some of these properties may be null.

The Node Hierarchy

Every node is part of an overall hierarchy that describes the complete form. This hierarchy follows a standard tree structure, with the top of the tree being the top (or root) of the hierarchy.

The diagram in Figure 1 shows the tree structure for a simple form.

The elements of the hierarchy, in descending order, are:

  • Form — Each form has one form level node. This is the root node of the tree.
  • Page — Each form contains pages, which are represented as children of the form node. Each form has at least two page nodes - one for the globalpage, which stores the global settings, and one for the first page of the form.
  • Item — Each page contains items, which are represented as children of the page node. An item node is created for each item, including the global item which stores page settings.
  • Option — Each item contains options, which are represented as children of the item node. An option node is created for each option.
  • Argument — Options often contain further settings, or arguments, which are represented as children of the option node or as children of other argument nodes. There may be more than one level of argument node created below an option node, depending on the settings of the option. The easiest way to access a particular node in the hierarchy is to use a reference. References allow you to locate a specific node without first having to locate the parent of that node.

A sample node hierarchy diagram is shown below:

Figure 1. Sample Node Hierarchy
The diagram shows a sample node hierarchy in descending order, breaking down the nodes into their properties.

About references

References allow you to identify a specific page, item, option, or argument by providing a "path" to that element. This means that you can access an element directly without having to locate any of its ancestors. The syntax of a reference follows this general pattern:

   page.item.option[argument]

Each element of the reference is constructed as follows:

  • Page and Item — Pages and items are identified by their scope identifiers (sid). For example, Page1 or Field1.
  • Options — Options are identified by their tag name. For example, value or itemlocation.
  • Arguments — Arguments are identified by their tag name or a zero-based numeric index. Argument references are always enclosed in brackets. For example, [1] or [message].

    Arguments can also have any depth. For example, you might have an argument that contains arguments. You can reference additional levels of depth by adding another bracketed reference. For example, to refer to the first argument in the first argument of the printsettings option, you could use either [0][0] or the tag names in brackets, such as [pages][filter].

You can create references to any level of the node hierarchy. For example, the following table illustrates a number of references starting at different levels of the form:

Start At Ref to Page Ref to Item Ref to Option Ref to Argument
Page Page1 Page1.Field1 Page1.Field1.format Page1.Field1.format[message]
Item Field1 Field1.format Field1.format[message]
Option format format[message]
Argument [message]

Dereferencing

When making a reference to an item node, there may be times when you do not know which node to reference because it depends on some action from the user of the form. Consider a situation in which a user selects a cell from a list. Because you don't know beforehand which cell the user will choose, it is not possible to explicitly reference the item node for the chosen cell. In such cases you would use dereferencing to retrieve the node indirectly.

Essentially, dereferencing allows you to make a dynamic reference that is evaluated at runtime. This is accomplished by placing the -> symbol to the right of the dynamic reference.

For example, consider a list item called List1 that has three cells called Cell1, Cell2, Cell3. If you want to access the item node of the cell selected by the user, use the following reference string:

   List1.value->

At runtime, the portion of the expression that is to the left of the dereference symbol is evaluated and replaced. If the user chooses the second cell, List1.value is evaluated and replaced with:

   Cell2

As a result, the item node for Cell2 is returned.

In some cases, instead of accessing the item node of the chosen cell, you may want to access one of the cell's option nodes. Again, dereferencing is used. The reference string would be:

   List1.value->value

As before, the above expression is evaluated at runtime. The expression to the left of the dereference symbol is evaluated and replaced, just as before. So if the second cell is selected, List1.value is evaluated as Cell2. This value is then concatenated with the expression to the right of the dereference symbol. This produces:

   Cell2.value

As a result, the option node for Cell2.value is returned.

Note: Do not include any spaces before or after the dereference symbol (->).

Namespace in References

References that include options or arguments in any namespace other than XFDL normally require the inclusion of the namespace prefix in the reference. For example, if you want to reference "myOption" in the "custom" namespace, refer to that option as "custom:myOption" as shown:

   page_1.myItem.custom:myOption

If you are referencing named arguments, you should also use the appropriate namespace. For example:

   page_1.myItem.custom:myOption[custom:myArgument]

However, if you are referencing an argument by index number you do not need to worry about namespace. All arguments, regardless of namespace, are indexed in order. For example, if "myOption" contains two arguments, the first in the XFDL namespace and the second in the custom namespace, use the following reference for the second argument:

   page_1.myItem.custom:myOption[1]
Note: Page and item references never require a namespace prefix because they are uniquely identified by their sid.
The null Namespace

In some cases, forms may have no default namespace or may have a default namespace that is explicitly set to an empty string. In these cases, you can use null as the prefix for the empty namespace. For example, the following field declares a default namespace that is empty:

   <page sid="Page1">
      <field sid="myField" xmlns="">
         <value>Test Value</value>
      </field>
   </page>

In this case, to reference the value of the field, you would use the null prefix as shown:

   Page1.null:myField.null:value

Advanced Information about the Node Structure

When an XFDL form is stored in memory, it exists as a series of nodes that are linked in a tree structure. As described in The Node Hierarchy, the tree structure follows this hierarchy: form, page, item, option, and argument.

Within a single branch of the tree, all elements of the same level are treated as siblings, each of which has a common parent, and each of which may have its own children.

The following example illustrates the node structure of a simple form, and gives a top-down description of the node structure.

A Sample Hierarchy

The following XFDL code creates the node hierarchy shown in Figure 1. The result is a simple form that contains three items (a line and two labels).

   <?xml version = "1.0"?>
   <XFDL xmlns="http://www.ibm.com/xmlns/prod/XFDL/7.5"
      xmlns:xfdl="http://www.ibm.com/xmlns/prod/XFDL/7.5">
      <globalpage sid="global">
         <global sid="global"></global>
      </globalpage>
      <page sid = "PAGE1">
         <global sid="global"></global>
         <line sid = "REFLINE">
            <size>
               <width>20</width>
               <height>0</height>
            </size>
         </line>
         <label sid = "LABEL1">
            <value>Hello</value>
         </label>
         <label sid = "LABEL2">
            <value>World</value>
            <itemlocation>
               <after>LABEL1</ae>
               <expandr2r>REFLINE</expandr2r>
            </itemlocation>
         </label>
      </page>
   </XFDL>

The Sample Tree Structure

Each tree begins with the form, or root, node. This node contains no information - it simply represents the starting point of the tree structure.

Below the form node are the page nodes. In the previous example, there are two page nodes: "global" and "PAGE1". The "global" page node stores any global settings that apply to the form, and "PAGE1" stores the contents of the first form page. Additional pages are stored as siblings of the "PAGE1" node.

Below each page node are the item nodes. As shown in the previous example, the first item node of a page is always the "global" item. The "global" item stores settings that apply to the items on that page. Each additional item in the page is stored as a sibling of the global item.

Below each item node are the option nodes. Each option node represents an option setting for that item, such as a background color or font setting.

Below each option node are the argument nodes. These nodes contain the settings for the parent option. For example, the background color might be set to "blue". There can be an infinite number and depth of these nodes, depending upon the number and depth of the settings for that option.

For instance, in the sample form, the size node for "REFLINE" has two argument nodes: one for the width and one for the height. In contrast, the printsettings option can have multiple argument nodes which themselves have argument nodes as children. The following is an example of the node structure of the printsettings option:

A small sample code for print settings. Arrows match argument node levels to the corresponding lines of code.
printsettings Node Structure
A node hierarchy for print settings that shows two argument nodes are created.

Thus, in storing the printsettings option, two levels of argument nodes are created. The first level describes the number of array elements in the option (two). The second level gives the arguments for each element.

Due to their potential complexity, pay careful attention to the mapping of argument nodes.

Note: In cases where an option has multiple elements in an array (for example, printsettings), there will be a single option node, but a separate argument node for each element in the array.

Node Properties

There are several levels of nodes in an XFDL form: form (or root), page, item, option, and argument (which can have an infinite number of levels). Each node has four properties: literal, type, identifier, and compute. A node does not necessarily contain information for every property.

For example, a page node can never have values for the compute or literal properties. And while a value for the user data property is optional, a page node must always have values for the type and identifier properties.

The following table illustrates what properties may be in use for each node level.

Node Property Sample

yes — node can have that property
always — node always has that property
no — node cannot have that property

Libraries

The API contains two libraries; the Form library and the FCI library. You use the Form library for reading, parsing, modifying, and writing forms. The FCI library allows you to create custom functions that extend the capabilities of forms.

Introduction to the Form Library

You use the form library to develop applications that manipulate XFDL forms. Your C and Java applications use the form library to:

  • Read and write forms.
  • Retrieve information contained in a form's elements.
  • Assign information to the elements of a form.
  • Create new elements within a form.
  • Remove elements from a form.
  • Extract images or enclosures from a form.
  • Verify digital signatures.
With the Java Streaming API, your applications can:
  • Read and write forms.
  • Retrieve information contained in a form's elements.
  • Assign information to the elements of a form.

Introduction to the FCI Library

The Function Call Interface (FCI) API provides a means for creating extremely powerful form applications in a simple and elegant manner.

The FCI Library is a collection of methods for developing custom-built functions that form developers may call from XFDL forms. By creating custom functions, you can extend the capabilities of forms without requiring an upgrade to either your forms software or the form description language (XFDL). Using the methods from this library you can:

  • Create packages of functions for forms.
  • Set up the packages as extensions for Lotus Forms products, such as Viewer or Designer.
  • Determine how and when the functions are used. For example, you can specify that a function should run when a form opens, when it closes and so on.

About Functions, Packages and Extensions

The purpose of the FCI is to make the functionality of forms extensible without requiring updates to your forms driver software. This API allows you to create self-contained modules called extensions that provide packages of functions for use in XFDL forms.

Note: The forms driver software is any application that initializes and calls on the API.

Functions can be used almost anywhere in an XFDL form; the appropriateness of their use depends mainly on their behavior. For instance the XFDL Specification contains a default package of functions called system. Every application built with the API version 4.4 or greater can use these functions.

Functions are grouped together to form packages. When you call a function from a form, you must include the function's package name in the call. For example, the function beep is part of the package called my_funcs. To call the beep function from a form and assign the result to the form option do_beep you would type the following:

   <label sid = "do_beep">
      <value compute = "my_funcs.beep( )"></value>
   </label>

The most common use of a function is to return a value that is used to set a form option, such as the value of a field. For example, the toupper function in the system package, which converts a string to upper case and returns the result, might be used to set the value of a particular form field. This method could take as its sole argument the value of a label elsewhere on the form (or on another form) and convert it to upper case as follows:

   <label sid = "SomeLabel">
      <value>"I am a label"</value>
   </label>
   <field sid = "SomeField">
      <size>
         <ae>20</ae>
         <ae>1</ae>
      </size>
      <value compute = "system.toupper(SomeLabel.value)"></value>
   </field>
FunctionCall: To create a package of functions you must create an extension. The extension provides services for function calls via an object. The FunctionCall object contains your package(s) of custom-built functions.
View of functions inside a package.

Refer to the The FCI Extension Architecture for more information. .

Use the following rules to help you define your own packages and extensions:

  • Each package can contain multiple functions.
  • Each extension can contain multiple packages, however it is easier to define one package per extension.
  • All package names must contain an underscore. IBM reserves all other package names.
  • The XFDL Specification contains a default package of functions called system. Every application built with the API version 4.4 or greater can use these functions.
  • You cannot add to the system package of functions. For details on the system functions, see the XFDL Specification.

Once you have created your extensions you can embed them directly into XFDL forms, or you can distribute them to users as Java Archive files (JARs) or as ZIP files.

Note: In order to view the forms provided with this API, you must have a licensed or evaluation copy of Lotus Forms Viewer installed.

Package Naming Conventions

The main purpose of package names is to distinguish the functions in a package from those in other packages that could potentially have the same names. All packages you create must contain an underscore in their names. For example, the convertDate function belongs to a package called sample_package.

  • Choose a name that aptly describes the set of functions you are creating and is distinct enough to be unique within its realm of usage.
  • The package name is an internal logical element of the API.
  • Package names are case sensitive.
  • All package names you define must contain an underscore.
Note: A group of functions is provided with the Forms System software as the package. The package is reserved for system functions that are defined in the XFDL Specification. You may not add to the system package or call your packages by the name system.

About the Function Call Interface (FCI)

The FCI is itself an extension. It is currently only available for Windows 32-bit applications. A set of Java wrapper classes, supplied as a Java Archive file (JAR file) or ZIP file, provide a Java interface to the DLL.

How the Form and FCI Libraries Work Together

The Form Library provides developers with tools for accessing and manipulating XFDL forms as structured data types. For instance, methods in the Form Library will provide your applications with a means for reading and writing forms, retrieving information contained in form elements or assigning information to the elements of a form.

The FCI Library of methods allows you to create an extension structure that contains one or more packages of your custom functions.

Once you have set up the framework for your custom functions you can use Java system methods, Form Library methods or even other FCI methods to implement the details of each function.

Relation between the form library and the custom FCI.

The FCI Extension Architecture

Extensions can exist in any of the following locations:

  • The extensions folder of the Lotus Forms product that will use the extension (for example, the Viewer or Designer products).
  • The API extensions folder, <Windows System>\PureEdge\extensions.
  • The Java source folder, <Windows System>\PureEdge\java\source.
  • Enclosed within XFDL forms.

When the Forms System is initialized, the API checks for extensions. If it finds any, it calls the initialization method for each extension and passes each method an object called the IFX Manager.

This image shows how the IFS API passes each method to the extension manager, and then to the extension class.

As part of the initialization, those extensions that provide a function call interface create one or more FunctionCall objects.

Image shows a magic wand creating a Function Call object inside the Extension Class.

Then, each FunctionCall object requests a FunctionCallManager object from the IFX Manager.

Image shows the function call object requesting a Function Call Manager via the Extension Manager.

Each FunctionCall object registers itself with the IFX Manager as a function call and then registers your custom-built functions and corresponding packages with the Function Call Manager.

The image shows that the Function Call has registered with the Extension Manager and has registered the functions with the Extension Manager.

The image shows the custom functions returned from the Extension Manager to the Function Call Object..

The final result is an extension containing a registered FunctionCall object. The registered FunctionCall object contains your package of custom functions.

The image shows the final image of three boxes stacked within one another.

When a function is called in a form, the forms driver requests the package and function from the API. The API will use the Function Call Manager to locate the FunctionCall object that contains the requested function and evaluate it.

The image shows the API using the Function Call Manager to call one of the custom functions from the package of custom functions.

Note: The forms driver software is any application that initializes and calls the API.

Developing applications on Windows


Setting up the C environment to use the Form library

Although this procedure is specific to Microsoft Visual C++ 6.0, you can use it as a guideline to set up alternate development environments.

To set up your development environment to use the Form Library, follow this procedure:

  1. Create a new 64-bit or 32-bit Windows project.
  2. Add the API include file to your project. This folder is located at:
    <API Installation Folder>/include/
  3. Include pe_cc.lib.
  4. Set the Preprocessor Definitions in your project to WINDOWS.
  5. If you are using Microsoft Visual Studio .NET, you must set the project to use a multi-threaded DLL. (You can find this option under Project > Properties. Open the C/C++ > Code Generation folder, and set the Run-time drop-down list to Multi-threaded DLL.)

Setting up the C environment to use the FCI library

Although this procedure is specific to Microsoft Visual C++ 6.0, you can use it as a guideline to set up alternate development environments.

To set up your development environment to use the FCI Library, follow this procedure:

  1. Create a new Win32 Dynamic-Link Library project.
  2. Add the API include file to your project. This folder is located at:
    <API Installation Folder>/include/
  3. Include pe_cc.lib in your project.
  4. Set the Preprocessor Definitions in your project to WINDOWS.
  5. If you are using Microsoft Visual Studio .NET, you must set the project to use a Multithreaded dll. (You can find this option under Project > Properties. Open the C/C++ > Code Generation folder, and set the Run-time drop-down list to Multi-threaded DLL.)
  6. Set your project to output files with an .ifx extension.

Setting Up the Java Development Environment (Classic only)

To use the Java API you must:

  • Configure your integrated development environment to use the API.
  • Configure your computer to run applications that use the API.
Note: You cannot configure your system to use both the Classic and Streaming Java APIs. You must choose only one.

To configure your integrated development environment to use the Java API:

Add the following files to your CLASSPATH:
   <WIN SYS>\PureEdge\80\java\classes\pe_api.jar
   <WIN SYS>\PureEdge\80\java\classes\uwi_api.jar
Note: You cannot add both Classic and Streaming Java API files to your classpath. If you do, you will receive errors and your application will not work.

To configure your computer to run applications that use the API:

  1. From the Start menu, select Settings > Control Panel > System.
  2. On the System Properties sheet, click the Advanced tab.
  3. Click Environment Variables.
  4. Under System Variables, select the CLASSPATH variable and click Edit.
    • If the CLASSPATH variable does not exist in your list of environment settings, you must create it: click New and type CLASSPATH in the Variable Name field.
  5. In the Variable Value field, enter the location of the following components:
    • pe_api.jar
    • pe_api_native.jar
    • uwi_api.jar
    • uwi_api_native.jar
    • commons-codec.jar
    • xmlsec-1.4.1.jar
    • current directory (represented by a period)
  6. Click OK.
  7. Click OK.

Setting Up the Java Development Environment (Streaming only)

To use the Streaming API you must:

  • Configure your integrated development environment to use the API.
  • Configure your computer to run applications that use the API.
Note: You cannot configure your system to use both the Classic and Streaming Java APIs. You must choose only one.

To configure your integrated development environment to use the Streaming API:

Add the following file to your CLASSPATH:
   <WIN SYS>\PureEdge\80\java\classes\StreamingAPI.jar   
Note: You cannot add both Classic and Streaming Java API files to your classpath. If you do, you will receive errors and your application will not work.

To configure your computer to run applications that use the API:

  1. From the Start menu, select Settings > Control Panel > System.
  2. On the System Properties sheet, click the Advanced tab.
  3. Click Environment Variables.
  4. Under System Variables, select the CLASSPATH variable and click Edit.
    • If the CLASSPATH variable does not exist in your list of environment settings, you must create it: click New and type CLASSPATH in the Variable Name field.
  5. In the Variable Value field, enter the location of the following components:
    • StreamingAPI.jar
    • current directory (represented by a period)
  6. Click OK.
  7. Click OK.

Setting Up the COM Interface

Before you can make calls to the COM API, you must include the IFS_COM_API.tlb library in your project. The steps to do this will vary depending on the programming language you are using.

For example, if you are using Microsoft Visual Basic, you can include the type library as follows:

  1. From the Project menu, select References.
  2. In the References dialog, select InternetForms API.
  3. Click OK.

For specific information about including a type library in your project, refer to the documentation for your development environment.

Developing applications on AIX, Solaris, and Linux


Setting Up the C Development Environment

To set up your computer to run applications that use the API:

  • On a Linux or Solaris system, include the following directories in the LD_LIBRARY_PATH environment variable:
       /usr/lib/
       /usr/lib/PureEdge/80/system/
       <path_to_directory_containing_the_Netscape_Security_Libraries>
  • On an AIX system, include the following directories in the LIBPATH environment variable:
       /lib 
       /usr/lib 
       /usr/lib/PureEdge/80/system 
       <path_to_JVM>/jre/bin/classic
       <path_to_JVM>/jre/bin
       <path_to_directory containing the Netscape Security Libraries>
    Note: To find the Netscape Security Libraries directory, search for the libnss3.so file.

Setting Up the Java Development Environment (Classic only) on AIX, Linux, and Solaris

You must configure your integrated development environment to use the API. You must also ensure that your computer can run applications that use the API.

Note: You cannot configure your system to use both the Classic and Streaming Java APIs. You must choose only one.

To configure an integrated development environment to work with the Classic Java API:

Include the following files in your CLASSPATH environment variable:
   /usr/lib/PureEdge/80/java/classes/pe_api.jar
   /usr/lib/PureEdge/80/java/classes/uwi_api.jar
   /usr/lib/PureEdge/80/java/classes/commons-codec.jar
   /usr/lib/PureEdge/80/java/classes/xmlsec-1.4.1.jar
Note: You cannot add both Classic and Streaming Java API files to your classpath. If you do, you will receive errors and your application will not work.

To set up your computer to run applications that use the API:

  1. Include the following files in your CLASSPATH environment variable:
       /usr/lib/PureEdge/80/java/classes/pe_api.jar
       /usr/lib/PureEdge/80/java/classes/pe_api_native.jar
       /usr/lib/PureEdge/80/java/classes/uwi_api.jar
       /usr/lib/PureEdge/80/java/classes/uwi_api_native.jar
       /usr/lib/PureEdge/80/java/classes/commons-codec.jar
       /usr/lib/PureEdge/80/java/classes/xmlsec-1.4.1.jar
  2. On a Linux or Solaris system, include the following directory in the LD_LIBRARY_PATH environment variable:
       /usr/lib/:/usr/lib/PureEdge/80/system/
       <path_to_directory_containing_the_Netscape_Security_Libraries>

    On an AIX system, include the following directories in the LIBPATH environment variable:

       /lib 
       /usr/lib 
       /usr/lib/PureEdge/80/system 
       /<path_to_JVM>/jre/bin/classic 
       /<path_to_JVM>/jre/bin
       <path_to_directory_containing_the_Netscape_Security_Libraries>
    Note: To find the Netscape Security Libraries directory, search for the libnss3.so file.

Setting Up the Java Development Environment (Streaming only) on AIX, Linux, and Solaris

You must configure your integrated development environment to use the API. You must also ensure that your computer can run applications that use the API.

Note: You cannot configure your system to use both the Classic and Streaming Java APIs. You must choose only one.

To configure your integrated development environment to use the Streaming API:

Add the following file to your CLASSPATH:
   /usr/lib/PureEdge/80/java/classes/StreamingAPI.jar
Note: You cannot add both Classic and Streaming Java API files to your classpath. If you do, you will receive errors and your application will not work.

To configure your computer to run applications that use the API:

  1. Include the following files in your CLASSPATH environment variable:
       /usr/lib/PureEdge/80/java/classes/StreamingAPI.jar
  2. On a Linux or Solaris system, include the following directory in the LD_LIBRARY_PATH environment variable:
       /usr/lib/:/usr/lib/PureEdge/80/system/
       <path_to_directory_containing_the_Netscape_Security_Libraries>

    On an AIX system, include the following directories in the LIBPATH environment variable:

       /lib 
       /usr/lib 
       /usr/lib/PureEdge/80/system 
       <path_to_JVM>/jre/bin/classic 
       <path_to_JVM>/jre/bin
       <path_to_directory_containing_the_Netscape_Security_Libraries>
    Note: To find the Netscape Security Libraries directory, search for the libnss3.so file.

Distributing applications on Windows

If you plan to distribute applications that call the API, you must ensure the following:

  • That your package includes the correct API files.
  • That the PureEdgeAPI.ini file is set up correctly on each computer.
  • That the prefs.config file is set up correctly on each computer.
  • That signature support is set up correctly on each computer.
  • That each computer has the correct environment variable settings.

Redistributing API Files

When you redistribute the API, you must copy the complete contents of the following folder, including the sub-folders, to the target's Windows System folder:

   <API Installation Folder>\redist\Win32\

Setting up the PureEdgeAPI.ini file

The PureEdgeAPI.ini file determines which applications use which version of the API. This ensures that older applications do not attempt to use newer APIs, which may not be compatible.

The PureEdgeAPI.ini file must be placed in the Windows folder. If no PureEdgeAPI.ini file exists on the target computer, you should install your own. If a PureEdgeAPI.ini file already exists, you should update the file to include an entry for your application. For more information about setting up the PureEdgeAPI.ini file for your application, refer to the IFSInitialize function if you are using C, or theinitialize method if you are using Java.

Setting Up the prefs.config File

The prefs.config file controls the configuration of the API. When you distribute an application that uses the API, you must also distribute a configuration file for that application. This file ensures that the API is configured properly to work with your application.

You can install the configuration file in any of the following locations:

   c:\Documents and Settings\<username>\Application Data\PureEdge\
      <application> <version>\Prefs\prefs.config
   c:\Documents and Settings\All Users\Application Data\PureEdge\
      <application> <version>\Prefs\prefs.config
   c:\Documents and Settings\<username>\Application Data\PureEdge\
      API <version>\Prefs\prefs.config
   c:\Documents and Settings\All Users\Application Data\PureEdge\
      API <version>\Prefs\prefs.config

These locations are listed in order of precedence, from highest to lowest. When loading the configuration information, the API first checks the lowest precedence location, then works its way to the highest. The configuration settings are loaded from each location, but settings in a higher precedence location override those in a lower precedence location.

In these paths, the <application> and <version> are determined by the parameters of the IFSInitialize function. You must call this function from your application to initialize the API, and as part of that you must supply a name and version for your application. Use the same name and version in your path.

For example, if you called the IFSInitialize function with a name of "CustomApp" and a version of "1.0", you would install the configuration file in the following location for All Users:

   c:\Documents and Settings\All Users\Application Data\PureEdge\
      CustomApp 1.0\Prefs\prefs.config

For more information about the IFSInitialize function, refer to the Lotus Forms Server API – C API User's Manual.

Setting the CLASSPATH

Before a computer can run applications that use the Java API or use Java extension files, you must set your computer's CLASSPATH environment variable to include the following files:

<WIN SYS>\PureEdge\80\java\classes\pe_api.jar
<WIN SYS>\PureEdge\80\java\classes\pe_api_native.jar
<WIN SYS>\PureEdge\80\java\classes\uwi_api.jar
<WIN SYS>\PureEdge\80\java\classes\uwi_api_native.jar
<WIN SYS>\PureEdge\80\java\classes\commons-codec.jar
<WIN SYS>\PureEdge\80\java\classes\xmlsec-1.4.1.jar

Distributing applications on AIX, Solaris, and Linux

If you plan to distribute applications that call the API, you must ensure the following:

  • That your package includes the correct API files.
  • That the PureEdgeAPI.ini file is set up correctly on each computer.
  • That the prefs.config file is set up correctly on each computer.
  • That each computer has the correct environment variable settings.

Redistributing API Files on AIX, Linux, and Solaris

Identifies the directories that need to be redistributed.

To redistribute the API, you must copy the complete contents of the following directory, including the sub-directories, to the target's /usr/lib/ directory:

   <API_Installation_Folder>/redist/<UNIX_Type>/

Where <UNIX_Type> is one of: Linux, AIX, or SunOS.

Setting up the PureEdgeAPI.ini file on AIX, Linux, and Solaris

You must have a PureEdgeAPI.ini file to successfully create Lotus Forms applications

The PureEdgeAPI.ini file is located in the following directory:

   /etc

If no PureEdgeAPI.ini file exists, you should install your own. If a PureEdgeAPI.ini file already exists, you should update the file to include an entry for your application. For more information about setting up the PureEdgeAPI.ini file for your application, refer to the IFSInitialize function if you are using C, or theinitialize method if you are using Java.

Setting up the prefs.config file on AIX, Linux, and Solaris

The prefs.config file controls the configuration of the API. When you redistribute the API with your application, you must also install an application-specific configuration file on the target computers. You should set this file to configure the API properly for your application.

You must install the configuration file in one of the following locations:
  •    /home/<username>/.PureEdge/<application>_<version>/
          prefs/prefs.config
  •    /etc/PureEdge/prefs/prefs.config
Both files are checked for configuration information, and the settings in the user specific file override the settings in the /etc/PureEdge/prefs/prefs.config file. However, if you do not require user specific settings, you only need to install the /etc/PureEdge/prefs/prefs.config file. In these paths, the <application> and <version> are determined by the parameters of the IFSInitialize function. You must call this function from your application to initialize the API, and as part of that you must supply a name and version for your application. Use the same name and version in your path.

For example, if you called the IFSInitialize function with a name of "CustomApp" and a version of "1.0", you would install the configuration file in the following location:

   /home/<username>/.PureEdge/CustomApp_1.0/prefs/prefs.config

Setting the Environmental Variables

Before a computer can run applications that use the API, you must set its CLASSPATH environment variable to include the following files:

   /usr/lib/PureEdge/80/java/classes/pe_api.jar
   /usr/lib/PureEdge/80/java/classes/pe_api_native.jar
   /usr/lib/PureEdge/80/java/classes/uwi_api.jar
   /usr/lib/PureEdge/80/java/classes/uwi_api_native.jar
   /usr/lib/PureEdge/80/java/classes/commons-codec.jar
   /usr/lib/PureEdge/80/java/classes/xmlsec-1.4.1.jar

Additionally, on a Linux or Solaris system, include the following directory in the LD_LIBRARY_PATH environment variable:

   /usr/lib/:/usr/lib/PureEdge/80/system/

On an AIX system, include the following directories in the LIBPATH environment variable:

   /lib 
   /usr/lib 
   /usr/lib/PureEdge/80/system 
   /<path to JVM>/jre/bin/classic 
   /<path to JVM>/jre/bin
Note: If you did not install the API in the /usr/lib directory, use the appropriate directory in the above settings. For example, if you installed the API in /home/jdoe then you would use /home/jdoe/.PureEdge/80/system.

Troubleshooting and support

If you are experiencing a problem with the API:
  1. Refer to the documentation for the task you are performing or the product component you are working with. These topics may contain troubleshooting information for common problems.
  2. Refer to the API technotes and flashes. These topics contain troubleshooting information for specific problems.
  3. Refer to the Lotus Forms Support web page for documents, fixes, and other resources that may help you resolve the problem.
  4. Refer to the Directory of worldwide contacts Web page and contact IBM Software Support for your region.

Notices

This information was developed for products and services offered in the U.S.A.

IBM may not offer the products, services, or features discussed in this document in other countries. Consult your local IBM representative for information on the products and services currently available in your area. Any reference to an IBM product, program, or service is not intended to state or imply that only that IBM product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any IBM intellectual property right may be used instead. However, it is the user's responsibility to evaluate and verify the operation of any non-IBM product, program, or service.

IBM may have patents or pending patent applications covering subject matter described in this document. The furnishing of this document does not grant you any license to these patents. You can send license inquiries, in writing, to:

IBM Director of Licensing
IBM Corporation
North Castle Drive
Armonk, NY 10504-1785
U.S.A.

For license inquiries regarding double-byte (DBCS) information, contact the IBM Intellectual Property Department in your country or send inquiries, in writing, to:

Intellectual Property Licensing
Legal and Intellectual Property Law
IBM Japan Ltd.
1623-14, Shimotsuruma, Yamato-shi
Kanagawa 242-8502 Japan

The following paragraph does not apply to the United Kingdom or any other country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.

This information could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or the program(s) described in this publication at any time without notice.

Any references in this information to non-IBM Web sites are provided for convenience only and do not in any manner serve as an endorsement of those Web sites. The materials at those Web sites are not part of the materials for this IBM product and use of those Web sites is at your own risk.

IBM may use or distribute any of the information you supply in any way it believes appropriate without incurring any obligation to you.

Licensees of this program who wish to have information about it for the purpose of enabling: (i) the exchange of information between independently created programs and other programs (including this one) and (ii) the mutual use of the information which has been exchanged, should contact:

IBM Corporation
5 Technology Park Drive
Westford Technology Park
Westford, MA 01886
U.S.A.

Such information may be available, subject to appropriate terms and conditions, including in some cases, payment of a fee.

The licensed program described in this document and all licensed material available for it are provided by IBM under terms of the IBM Customer Agreement, IBM International Program License Agreement or any equivalent agreement between us.

Trademarks

IBM, the IBM logo, ibm.com, Lotus, and Notes are trademarks or registered trademarks of International Business Machines Corporation in the United States, other countries, or both. These and other IBM trademarked terms are marked on their first occurrence in this information with the appropriate symbol (® or ™), indicating US registered or common law trademarks owned by IBM at the time this information was published. Such trademarks may also be registered or common law trademarks in other countries. A current list of IBM trademarks is available on the Web at http://www.ibm.com/legal/copytrade.shtml

Java and all Java-based trademarks and logos are trademarks or registered trademarks of Oracle and/or its affiliates.

Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both.

Microsoft and Windows are trademarks of Microsoft Corporation in the United States, other countries, or both.

UNIX is a registered trademark of The Open Group in the United States and other countries.

Other company, product, or service names may be trademarks or service marks of others.

End of document

Lotus swoosh footer image