ShowTable of Contents
The basic building blocks for a developing a composite application is writing a component and assembling different components together. As such the conventional way of defining properties for components (excluding containers) were to create a WSDL and declare it using the Eclipse extension points. Starting from Notes 8.5.1/XPD 6.2.1 release we are introducing an alternate way of defining such properties The primary objective of this tutorial is to learn on how to create a component and define properties to it with out using a WSDL. The component that is described here would be a simple SWT component which uses the PropertyBrokerListener pattern to create and pubish properties. The component UI comprises of a property creation UI , a basic text editor and buttons for publishing the value of the property. The idea behind creating each property is that ,upon creation they would each be associated with a Java Script which would then be stored along with the component data. This component itself would then create a preference for each and just writes out the properties using the "WiredProperty" class. "N" number of properties can be created dynamically and you will be able to attach a java script to each one.
Prerequisites
In order to start with developing a component the user need to have the Expeditor toolkit(v6.2.1) installed and/or Expeditor Client (v6.2.1) configured as target platform into Eclipse 3.4 . Alternatively if you have Notes 8.5.1 client installed then you can use the Expeditor toolkit to configure Notes as your target platform.
Creating a plugin project
To start with creating a component lets create a simple plugin project.
- Select File -> New -> Other ->
- Assign a name to the plugin project and lets call it as com.ibm.ca.wiki.component.withoutwsdl
- Assign a plugin name ComponentWithoutwsdl and make sure to select No Execution Environment .Leave the rest to defaults and Click Finish
Creating a sample Interface
Create a Interface in the same package
com.ibm.ca.wiki.component.withoutwsdl and call it IPropertyConverter
public interface IPropertyConverter {
public Map getPropertyScripts();
public String getTestValue();
public String getScript();
public void setTestResult(String result);
public void associateScript();
public void performAdditionalSave();
}
Utility Classes for sample component
1 Edit your MANIFEST file and add the required dependencies required for creating this component. Make sure the singleton attribute is set to true for the Bundle-SymbolicName as this is required while declaring extension points in the plugin.xml
2 Define packages
com.ibm.ca.wiki.component.withoutwsdl.script.listeners and
com.ibm.ca.wiki.component.withoutwsdl.script.core which would contain the script listeners and core classes
3 Declare the
Constants class in the core package to hold the static values.
public final static String JAVASCRIPT_FUNCTION_HEADER = "editProperty";
public final static String ARGUMENT = "wireValue";
4 Write the core class
WireScriptManager which uses the javax scripting engine API's to evaluate the java script. Refer to the attachment for this code.
5 Now modify the
Activator class to provide a service tracker for the Toplogy handler
private WireScriptManager _wireScriptManager;
private ServiceTracker _topologyTracker;
private TopologyHandler _handler;
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
_wireScriptManager = new WireScriptManager();
_topologyTracker = new ServiceTracker(context, TopologyHandler.class.getName(), null);
_topologyTracker.open();
_handler = (TopologyHandler)_topologyTracker.getService();
}
public ServiceTracker getTopologyTracker() {
return _topologyTracker;
}
public TopologyHandler getTopologyHandler() {
return _handler;
}
public WireScriptManager getWireScriptManager(){
return _wireScriptManager;
}
6 Create the script utility class
ScriptUtil which would load and Save all the Java Scripts declared in the component UI. This class would also determine if a component is in a Edit mode and helps to find out if it is actually hidden inside a Composite Application. All Scripts and its property are Base64 encoded and saved. Refer to the attachment for this class.
7 Write the script listener classes that are required for the component UI .The three classes required for this component would be
EditScriptListener ,
SaveListener and
TestScriptListener which would be called from the Component. Refer to the attachment for these classes.
8 Create the "BasicTableTextEditor" class to be used to edit the JavaScript in the component UI. Refer to the attachment for this class.
PropertyConverter2 sample Component
To create this SWT Component for a Composite Application you need to create a class
PropertyConverter2, extend the Eclipse "ViewPart" class and implement the interfaces for IPropertyConverter ,IComponentConfigurator PropertyBrokerListener and IPerspectiveListener.The createPartControl() would then define the UI layout for this component. The way this is designed is that the UI would be little different when in the Edit Mode (inside the Composite Application Editor) .The ScriptUtil class API would be called to determine if the application is in edit mode or not and based on that the Save Buttons for the script UI and the Add/Rename/Remove buttons for the property creation would be enabled.
if (ScriptUtil.isInEditMode(getViewSite().getSecondaryId())){
//CAE related UI code goes in here.
}
As mentioned earlier this SWT component uses the PropertyBrokerListener pattern the handleEvent(PropertyBrokerEvent e) method needs to be implemented and broker.changedProperties() needs to be called once a new property is created.
public void handleEvent(PropertyBrokerEvent e) {
if (e.getEventType() == PropertyBrokerEvent.PROPERTY_VALUE_SET){
String viewId = SWTHelper.getFullViewID(this);
if (e.getTargetEntityID().equals(viewId)){
//find the property in our map
String property = e.getPropertyValue().getProperty().getName();
String script = _scripts.get(property);
String value = (String)e.getPropertyValue().getValue();
if (script != null && value != null){
String result = Activator.getDefault().getWireScriptManager().evaluateScript(value, script);
PropertyBroker broker = PropertyBrokerFactory.getBroker();
PropertyValue pvalue = PropertyFactory.createPropertyValue(e.getPropertyValue().getProperty(), result);
try {
broker.changedProperties(new PropertyValue[]{pvalue}, viewId);
} catch (PropertyBrokerException e1) {
e1.printStackTrace();
}
}
}
}
}
Also all the new properties that are being created are being written into a "WiredProperties" preference directly using the PropertyBroker API's. This creates a preference for each one, all using the WiredProperty class in our container plugin. This would also enable these properties to be wired to another component.Note that the setProperty method is being called here to expose the new property as the wired preference for the component.
public void performAdditionalSave() {
//we need to write all of the properties out to the WiredProperties preference
TableItem[] items = _table.getItems();
StringBuffer preference = new StringBuffer();
for (int x = 0; x < items.length; x++) {
String id = buildPropId(items[x].getText());
propMgr.setProperty(id, "");
WiredProperty wp = new WiredProperty(id, items[x].getText(), null);
preference.append(wp.toPrefString());
if (x < (items.length + 1))
preference.append(";");
}
propMgr.setProperty(WiredProperty.WIREDPROPERTIES, preference.toString());
propMgr.saveAndRefresh();
}
Additionally since this component can also be a hidden one you can implement the dispose() method of the view to remove the property broker listener
public void dispose() {
if (ScriptUtil.isHiddenComponent(this.getViewSite().getSecondaryId()) == false){
PropertyBroker broker = PropertyBrokerFactory.getBroker();
broker.removePropertyBrokerListener(this);
}else{
//We need to register ourselves for when the perspective is closed to remove us as a listener
_perspective = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getPerspective();
PlatformUI.getWorkbench().getActiveWorkbenchWindow().addPerspectiveListener(this);
}
super.dispose();
}
Now If it is going to be delcared as hidden component (setting the preference com.ibm.rcp.visible to false) you need to remove the listeners in the perspective close.
public void perspectiveClosed(IWorkbenchPage arg0,IPerspectiveDescriptor arg1) {
if (arg1.equals(_perspective)){
PropertyBroker broker = PropertyBrokerFactory.getBroker();
broker.removePropertyBrokerListener(this);
_perspective = null;
getSite().getWorkbenchWindow().removePerspectiveListener(this);
}
}
Refer to the project attachment for the detailed implementation of this class.
Declaring extension points
1 Use the Eclipse view extension point to specify the view class for the component.The view class is the one that implements ViewPart.
point="org.eclipse.ui.views">
allowMultiple="true"
name="Property Converter2"
class="com.ibm.ca.wiki.component.withoutwsdl.PropertyConverter2"
id="PropertyConverter2">
2 Use the pallette entry extension point to attach the component to the CAE Pallette. You can assign a name to the component. Also define the config data section and specify the configItem name ,value attribute .You can provide a category name to assign this component to a category in the CAE pallette.
point="com.ibm.rcp.aaf.paletteEntries">
name="Property Converter2"
description="SWT Component that doesn't use a WSDL"
category="Samples"
id="PropertyConverter2">
Composite application creation using CAE
Now that the sample component is ready ,you can launch Notes 8.5.1 from your Eclipse and make sure this sample is selected during launching. Once Notes comes up you can select File -> Application -> New to create a new composite application. Enter "SampleApp" as Title and click "OK" . After the Application is opened click Actions -> Edit Application to open up the application in CAE.
The "PropertyConverter2" component should now show up in CAE under the Samples Category. You can now drag and drop this component into the CAE application layout.
Now use the "Add" button to create a new property .It creates a entry in the table called "New Property". Select that and then hit the "Rename" button and change it as "test". You will also see a java script template being created on the right side. Edit the script function and insert this
wireValue += " ready"; .
Hit the
Save Scripts button below to save the script and the property.You can now test this component by entering a test value and click
Test Script
You can right click on the component and select the "Edit component properties" and go to the Advanced tab to see the test preference being selected as wired.
Now add a Managed Browser component to this composite application and go to the wiring view . Now wire the "test" property to "set html text to browser" and hit apply
Now go back to application and test if the wiring works
Conclusion
This tutorial has given us a overall understanding on how to write a simple SWT component with out the need for a WSDL using the Property Broker Listener pattern. Also we have learned to associate a component property with Java Script and store the data along with the composite application.Moreover this component also has the feature to be hidden so that it can do the java script processing underneath the covers and output the result.This should greatly reduce the amount of Java code and custom actions many people do to manipulate strings (properties). This also means any time you need a new transformation you simply create a new property.