There are some outstanding articles regarding transformation, and in particular custom actions, which are referenced in this post:
http://blog.balfes.net/?p=821
This is another, it may help, it may not help - some differences:
- this explains property converter as well as custom actions, and a comparison;
- this has no Notes specifics;
- starts from an example containing no transformation;
- uses a different approach in the code for the custom action than others (setField instead of publishProperty);
- shows more screenshots.
Background
In Composite Applications, fields from different containers (e.g., text boxes in the webpage, fields in the terminal session, labels in the native Windows application, cells in the Excel spreadsheet, etc.) can be wired together. If one field's value changes, other fields in the same container or any other containers, can be updated with this new value.
Problem
A key problem is the need for the value to be transformed between fields. For example:
- 3-FEB-1982 in the native Windows application to 03 02 82 in the terminal session - the field in the terminal session can not accept 3-FEB-1982 - only 03 02 82;
- USD80 in the terminal session to $80 in the webpage's form - the latter reads better;
- and so on.
Case Example
A simple example Composite Application consisting of an internal webpage and an external webpage:
When the staff initials are entered on the internal webpage on the left, the same value is automatically entered on the external webpage on the right.
This is achieved through the container for the internal webpage on the left publishing the staff initials field named "initials" (this is the HTML name), to a new, wireable propety named "staffInitials":
and through the container for the external webpage on the right receiving from another new, wireable property named "staffFullName" and putting this into the staff full name field named "fullName":
The "staffInitials" and "staffFullName" properties are then wired together:
Then when a value is entered on the internal webpage on the left, the very same value is entered on the external webpage on the right. The problem is, ideally the value - the initials - should be transformed into the full name!
Case Requirement
The requirement is that when the staff initials are entered on the internal webpage on the left (e.g., "BF"), this is automatically transformed into the corresponding full name (e.g., "Ben Fletcher") on the external webpage on the right. Like this:
Solutions
Two ways of achieving this are:
- Property Converter
- Custom Actions
Here are the pro's and con's of the two approaches:
Property Converter | Custom Actions |
| uses Javascript - requires Javascript knowledge | uses Java - requires Java knowledge |
| inflexible - Javascript can do less than what Java can do, e.g. can't (directly) access middleware/backends for the transformation | flexible - Java can do more than what Javascript can do, e.g., can directly access middleware/backends for the transformation |
| rapid prototyping - programmed and configured all within the Composite Application editor | lengthly prototyping - is programmed separately and installed as a plugin, with some further configuration in Composite Application editor |
| low-performance Javascript engine compared to Java VM engine | high-performance Java VM compared to Javascript engine |
| multiple hidden property converter components may be required - for different transformations (e.g., one for date transformation, one for currency transformation, etc.) and may have performance implications | no additional or hidden component is needed in the composite application |
Tutorials
For the IT specialist, it may be worthwhile being skilled up in both methods - and use property converter for rapid prototyping and custom actions for more advanced transformation or when high performance is needed.
Property Converter Tutorial
Property Converter is a component that can be put in a Composite Application as hidden components. The wire where the transformation is performed, can go through a Property Converter component instead to be transformed. For example:
Before:
After:
(see how the staff initials property has been re-wired to the newly added property converter component and...)
(see how the wiring to the staff full name property now comes from the property converter component instead)
The transformation code in Javascript is entered in the property converter component in the Composite Application. This is in the form of a Javascript function, that takes in an argument the original value, and that returns the transformed value. For example:
This component can be hidden by setting the "visible" flag in the Advanced dialog.
The download including the Update Site along with documentation for the Property Converter component can be found here:
http://www.opennfs.org
When installed, it needs to be added to the My Palette on the right side of the Composite Application Editor, by right-clicking and selecting Add Components and then Add Locally Installed Components. Once installed, the Property Converter component can be dragged into the Composite Application. See the documentation included with the download for more on how to use the converter.
Custom Actions Tutorial
Background
Some quick background on the Action and Event concepts. To put it simply, Events cause Actions to be executed. Events and Actions can be defined for individual containers or sets of containers. This is because different containers have different Events and Actions. For example, with the Managed Browser container, it has the following events:
- "Content Complete" (when it has completely loaded a webpage)
- "Data Change" (when the value of the specified property or field has changed)
- "View Initialize", and;
- "View Close"
and it has the following actions:
- "Receive" (to receive the value of the specified property into the specified field);
- "Publish" (to publish the value of the specified field to the specified property); and
- "SetURL" (to go to the value of the specified property as the URL).
Custom Actions
Custom actions can be developed to do more than what are already offered by the container. For example, to do transformation.
The before for the external webpage:
The after:
(see how the action has been changed from "Receive" to "Receive Initials Transformed to Full Name" for both the events)
The staff full name field can be configured to, instead of receiving directly from the wired property, for a new custom action to receive and transform. This "Receive Initials Transformed to Full Name" custom action can be developed and deployed as part of a Composite Application by doing the following:
- create a new plugin;
- modify the plugin.xml;
- develop a new class that extends the Action class;
- package into a feature;
- install into Expeditor.
- switch from "Receive" to this new custom action in the Composite Application editor (as illustrated in the "before" and the "after" above with the "Receive Initials Transformed to Full Name" custom action)
The steps 2 and 3 will be explained here. Step 6 has already been explained. The other steps are standard Expeditor development practices - see Expeditor documentation.
The new class simply needs to extend the Action class and then implement the "execute" method. For example:
package com.ibm.ca.transformers;
import com.ibm.rcp.composite.container.core.AppContainer;
import com.ibm.rcp.composite.container.core.actions.Action;
import com.ibm.rcp.composite.container.core.events.LandmarkEvent;
public class StaffNamesTransformer extends Action {
/**
* The custom action Java code. This is executed when the custom action is
* executed in the Composite Application.
*
* @see Action#execute(AppContainer, LandmarkEvent, Object)
*/
public void execute(AppContainer container, LandmarkEvent event, Object context) {
String originalValue = event.getPropertyValue();
String transformedValue = transformValue(originalValue);
container.setField(transformedValue, field, event, context);
}
/**
* Default value if the value from the Composite Application could not be transformed.
*/
protected static String defaultValue = "IBM Staff";
/**
* The transformation code.
* @param originalValue the value to transform
* @return the transformed value - or the default if could not be transformed
* @see #defaultValue
*/
protected static String transformValue(String originalValue) {
try {
// do the transformation here
// we may prefer to use, e.g., DB2 lookup for the full name
if (originalValue.equalsIgnoreCase("BF")) {
return "Ben Fletcher";
} else if (originalValue.equalsIgnoreCase("GW")) {
return "Gill Woodcock";
} else if (originalValue.equalsIgnoreCase("MP")) {
return "Matthew Perrins";
} else {
return defaultValue; // use default if not listed
}
} catch (Exception e) { // string transformation often throws NPE, out of bound, etc., a quick catch them all here
System.err.println(DateTransformer.class.getName() + " could not transform value. Value: " + originalValue + ". Exception: " + e);
return defaultValue; // use default instead
}
}
}
The code should be self explanatory. It gets the incoming value, transforms it, then sets the field. This is the same as the "Receive" action except that it does the transformation in the middle.
If the container itself needs to be directly accessed - e.g., the HOD container to play a dynamic macro, then the container can be casted to the HOD container class ("com.ibm.rcp.composite.container.hod.HODAppContainer") and used.
The plugin.xml should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension point="com.ibm.rcp.composite.container.core.actionConfiguration">
<actions>
<action
class="com.ibm.ca.transformers.StaffNamesTransformer"
id="com.ibm.ca.transformers.StaffNamesTransformer"
name="Receive Initials Transformed to Full Name"
type="com.ibm.rcp.composite.container.core.AppContainer">
</action>
</actions>
</extension>
</plugin>
The class property needs to point to the class that extends the Action class. The name property is what will be shown in the Composite Application editor in the drop-down listing the different actions when operations are defined for events. Care should be taken to ensure that the name is easy to recognise and used.
If the custom action is to be made available to all containers, then the type property should be set to the base class for containers "AppContainer". If the custom action is designed for a specific container, e.g., to play a dynamic macro in the HOD container, then the type property should be set to the class for the HOD container. The Managed Browser container, for example, will fail to be casted to the class for the HOD container - and may not want the same "play a dynamic macro" action!