Server Access Kit
The following topics discuss the Info*Engine Server Access Kit (SAK) and provide an example of an SAK application.
About the Server Access Kit
The Info*Engine Server Access Kit (SAK) allows Java applications to execute Info*Engine tasks, pass parameters to them, and inspect their results. Tasks are instantiated as Java classes. After constructing a task instance, methods on the task object can be called to add parameters and establish execution options before the task is invoked. After adding parameters and establishing options, the invoke method for the task can be called to execute the task. When the task completes, methods on the task object can be called to obtain the group objects it produced.
Documentation for the Info*Engine APIs that are available through the SAK can be found in the Javadoc files that reside in the codebase/infoengine/docs/apidocs directory where Info*Engine is installed.
Connecting to Info*Engine
Before creating or attempting to execute any task instances, an application must initialize its connection with the Info*Engine Naming Service. The Naming Service enables the tasks executed by the application to locate adapters and other services deployed across the enterprise network. The Naming Service connection is established by calling a static factory method as follows:
import com.infoengine.au.NamingService;
:
:
NamingService namingService =
NamingService.newInstance
("com.myCompany.namingService",
"ldap://ldap.mycompany.com/dc=myCompany,dc=com");
This static factory method locates a Naming Service definition named “com.myCompany.namingService” (a Naming Service that serves a particular enterprise) in the LDAP directory. It searches the LDAP directory tree for the Naming Service definition. The root where the search starts is defined by the directory entry with the distinguished name dc=myCompany,dc=com and the host on which the LDAP server resides is named “ldap.mycompany.com”. This value could be a path to the ie.properties file or an LDAP URL that points to the place in the directory to find the properties. To avoid confusion it is best to point to the ie.properties file.
You must replace this Naming Service name, the distinguished name, and the LDAP host name with ones that apply to your network and LDAP directory structure. The LDAP directory structure and the Naming Service definition are typically created when the Info*Engine software is first installed.
Upon locating the Naming Service definition, the SAK reads its connection parameters, automatically loads all Info*Engine configuration properties from the LDAP directory service, and then returns control to the calling application. At that point, the application can create and execute task instances.
Executing Tasks
To create an instance of a task object, use the constructor that takes a URL as a parameter. For example:
import com.infoengine.SAK.Task;
:
:
Task task = new Task ("/com/acme/infoapp/QueryBOM.xml");
The parameter of this
Task constructor is the URL of an Info*Engine task. A variety of URL formats can be specified. For example URLs, see
Info*Engine JSP Pages.
After constructing a task instance, the application can add parameters to the task by calling the addParam method. This method accepts the name of the parameter to be added and its value. For example:
import com.infoengine.SAK.Task;
:
:
Task task = new Task ("/com/acme/infoapp/QueryBOM.xml");
task.addParam ("class", "wt.part.WTPart");
task.addParam ("where", "name='Engine'");
task.addParam ("group_out", groupOutName);
The same parameter name can be specified in more than one call to addParam in order to add multivalued parameters. Parameter values can be of any object type. Parameters are referenced within a task by using normal Info*Engine substitution against the @FORM context group. Thus, each call to the method addParam adds an attribute with the specified name and value to the @FORM context group of the task to be executed.
In addition to adding parameters to a task, an application can also establish execution options against the task before invoking it. For example, an application can set the username under which the task should execute. This username can then be used by Info*Engine as a credentials mapping key to select the credentials (for example, username and password) that are provided to each adapter with which the task communicates. The task’s username can be set as follows:
task.setUsername ("guest");
This sets the auth-user attribute in the @SERVER context group of the task. Other attributes can be added to the @SERVER context group also. This context group usually contains information about the runtime environment in which a task is executing. For example, when a task is executed using the Info*Engine servlet, the @SERVER context group is populated with attributes derived from information provided by the web server including all HTTP protocol headers. Applications that create and execute task instances can use the setServerAttribute method to populate the @SERVER group with runtime environment information. For example:
task.setServerAttribute ("accept-language", "en-US");
By default, Info*Engine executes tasks within the Java Virtual Machine (JVM) of the calling application. Sometimes it is more appropriate to execute tasks in a non-local JVM that is hosting an Info*Engine task processor. This is particularly true when the source code of the task can be accessed only by that non-local task processor. For example, if the task source contains sensitive information, such as privileged passwords, access to it may be restricted. When a task must be executed by a non-local task processor, an application can call the addProcessor method to specify the names of the Info*Engine task processors in which the task can be executed. For example:
task.addProcessor ("com.mycompany.engineering.windchill");
After adding all necessary parameters and service options, the task is executed by calling its invoke method as follows:
task.invoke ();
Catching Errors
If any error conditions are detected while executing the task, Java exceptions are thrown. The calling application can use normal Java try/catch logic to catch and inspect exceptions when that is desirable. Of course, if the task executes successfully without detecting any error conditions, no exceptions are thrown.
When the addProcessor method is used to specify that a task must be executed in a non-local task processor, Info*Engine automatically establishes communications with the task processor, conveys the request to execute the non-local task (including transmission of all parameters and service options), and retrieves all results. If a remotely executed task throws an exception, the exception is conveyed back to the local JVM and rethrown there. If more than one task processor is specified by calling addProcessor more than once, Info*Engine attempts to establish communications with the specified processors in the order in which their names were added. The task is executed in the first processor with which communications are established successfully.
In general, when Info*Engine detects error conditions during the course of executing tasks, it throws exceptions. When underlying services and APIs used by Info*Engine throw exceptions, Info*Engine wraps these in its own exception classes. Consequently, all Info*Engine exception classes can contain nested Throwable objects. The Info*Engine exception classes provide methods for obtaining these nested Throwable objects so that applications can determine the root causes of error indications.
For details on the com.infoengine.util.IEException class and its subclasses, see the Javadoc.
Inspecting Task Results
The application resumes control when the task completes its execution. The application can then inspect the results. Results are usually returned as Info*Engine group objects stored in the task Virtual Database (VDB). The names of all groups currently stored in the VDB at any point in time can be obtained by calling the getGroupNames method as follows:
java.util.Enumeration groupNames = task.getGroupNames ();
Any group can be obtained by name from the VDB using the getGroup method provided by the Task class. For example:
import com.infoengine.SAK.Task;
import com.infoengine.object.factory.Group;
:
:
Task task = new Task ("/com/acme/infoapp/QueryBOM.xml");
task.addParam ("class", "wt.part.WTPart");
task.addParam ("where", "name='Engine'");
task.addParam ("group_out", "engine_parts");
task.invoke ();
Group group = task.getGroup ("engine_parts");
Groups can be added to the VDB by an application, too. This is particularly useful when a task is designed to operate upon a group that is generated by an application. In this case, the application adds the group to the task’s VDB before calling the invoke method. For example:
import com.infoengine.object.factory.Group;
import com.infoengine.SAK.Task;
:
:
Group bomGroup = new Group ("product-structure");
:
<bomGroup generated>
:
Task task = new Task ("/com/acme/infoapp/UpdateBOM.xml");
task.addParam ("group_in", bomGroup.getName ());
task.addGroup (bomGroup);
task.invoke ();
Resulting Data
A Group object (class com.infoengine.object.factory.Group) is a container for Element objects (class com.infoengine.object.factory.Element), and an Element object is a container for Att objects (class com.infoengine.object.factory.Att). Usually, an Element object represents a business object or a row from a database table (in the case of simple database adapters). An Att object represents a single attribute of a business object. Each Att object has a name and one or more values. A value of an Att object can be any class of object. Therefore, a Group is a container for one or more business objects. Each business object is represented as an Element object and each Element object contains one or more name/value pairs represented as Att objects.
Resulting Metadata
In addition to regular data, Group, Element, and Att objects can contain metadata. Applications can, and Info*Engine itself does, use metadata to register information about an object on the object itself. Each metadata item is a name/value pair. Most metadata items created and used by Info*Engine have names beginning with com.infoengine. Applications can add their own metadata items, but they should avoid using names that begin with com.infoengine because this namespace is reserved by Info*Engine. All of the information classes provide methods that support inspection, creation, and management of metadata. For details on these methods, see the Javadoc.
Common Methods
The Group, Element, and Att classes all support a variety of methods for inspecting and managing their content. For details on these methods, see the Javadoc. These classes commonly include the following methods:
Common Group Methods
getAttributeValue
Retrieves the value of a specific attribute (Att) of a specific Element object contained in the Group.
addElement
Adds a new Element object to the Group.
getElementCount
Returns the number of Element objects contained in the Group.
getElements
Returns all of the Element objects of the Group as an enumeration.
getElementAt
Retrieves a specific Element object from the Group by index.
removeElementAt
Removes a specific Element object from the Group by index.
toXML
Renders the entire Group to XML and returns the result as a string or writes it to an output stream.
Common Element Methods
addAtt
Adds a new attribute (Att) to the Element, or adds a new value to an existing attribute of the Element.
getAtt
Retrieves a specific attribute (Att) object from the Element by name.
getAtts
Returns all attribute objects of the Element as an enumeration.
getValue
Retrieves the value of a specific attribute (Att) of the Element.
getValues
Retrieves all values of a specific attribute (Att) of the Element as a vector.
removeAtt
Removes a specific attribute (Att) from the Element by name.
toXML
Renders the Element to XML and writes it to an output stream.
Common Att Methods
addValue
Adds a value to the attribute.
getValue
Retrieves the value of the attribute.
getValues
Retrieves all values of the attribute as an enumeration.
toXML
Renders the attribute to XML and writes it to an output stream.
SAK Example Method
The following example method traverses a Group object to display all of its Element objects and their attributes:
private void displayObjects (Group objects) {
//
// xmlDisplay is a boolean instance variable that defines
// whether the Group should be rendered as XML or as plain
// text.
//
if ( xmlDisplay ) {
PrintWriter pw = new PrintWriter (System.out);
objects.toXML (pw, true, true);
}
else {
int n = objects.getElementCount ();
for ( int i = 0; i < n; ++i ) {
//
// Print one empty line between Elements
//
System.out.println ("");
Element object = objects.getElementAt (i);
Enumeration atts = object.getAtts ();
while ( atts.hasMoreElements () ) {
//
// Render each attribute as "name: value"
// If an attribute is multivalued, indent each
// value such that they are vertically aligned.
//
Att att = (Att)atts.nextElement ();
String name = att.getName ();
System.out.print (name + ": ");
Enumeration values = att.getValues ();
int v = 0;
while ( values.hasMoreElements () ) {
Object value = values.nextElement ();
if ( v++ > 0 ) {
System.out.print (" ");
for ( int s = 0; s < name.length (); ++s )
System.out.print (" ");
}
System.out.println (value);
}
}
System.out.println ("");
}
}