bea.com | products | dev2dev | support | askBEA |
![]() |
![]() |
|
![]() |
e-docs > WebLogic Platform > WebLogic Integration > BPM Topics > Programming BPM Plug-Ins > Defining Plug-In Components |
Programming BPM Plug-Ins
|
Defining Plug-In Components
This section explains how to define plug-in components. It includes the following topics:
Overview
As described in How BPM Discovers a Deployed Plug-In, the plug-in is responsible for enabling the BPM to:
This functionality is provided by the plug-in component. The following table describes the plug-in component requirements for supporting the specified functionality.
To enable the plug-in to read (parse) incoming data, both the plug-in data interface and run-time component class must implement the load() (parsing) method of their parent interface, com.bea.wlpi.common.plugin.PluginObject.
Lastly, you must define the plug-in component value object to describe the component data.
The following sections describe the PluginObject interface, explain how to define the plug-in component to support the functionality listed in the previous table, and define the plug-in component value object.
Note: For a summary of the steps that must be accomplished to define each type of plug-in component, see Plug-In Component Definition Roadmap.
PluginObject Interface
The com.bea.wlpi.common.plugin.PluginObject interface enables the plug-in to read (parse) the plug-in data.
This interface must be extended by:
The PluginObject interface defines one method, load(), as shown in the following table.
The Plug-in Manager calls the load() method when it encounters the plug-in section (for example, a <plugin-data> element) in an XML document. This might happen, for example, when the Plug-in Manager opens a template, template definition, or plug-in configuration XML document in the WebLogic Integration Studio. Note: For information about the BPM DTDs, see DTD Formats in Programming BPM Client Applications. You must also implement required content handler methods, including the startElement() and endElement() methods. The Plug-in Manager sets the plug-in as the parser content handler, and uses the startElement() and endElement() methods as the first and last calls to the content handler when a <plugin-data> element is reached. The content handler uses the intervening SAX notifications to store the plug-in-specific data. For more information about the content handler methods, see the org.xml.sax Javadoc. In the plug-in sample, a separate class file is provided for certain plug-in components that extends the PluginObject interface and defines the required methods. This file does not need to be defined separately. It is useful in this case, however, because it provides a single definition for the multiple classes in the example that share the file. The following sections provide code examples showing how the PluginObject interface for plug-in Done and Start nodes is implemented. In addition to these examples, refer to the following files in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory:
For more information about the plug-in sample, see BPM Plug-In Sample.
Done Node Example
The following code listing shows how to define a class that implements the PluginObject interface for a Done node. The input to the example code is a user response to a decision dialog box (yes or no). Notable lines of code are shown in bold.
Note: This class is not available as part of the plug-in sample.
Listing 4-1 Implementing the PluginObject Interface for a Done Node
package com.bea.wlpi.test.plugin;
import java.io.IOException;
import com.bea.wlpi.common.plugin.PluginObject;
import org.xml.sax.*;
public class DoneObject implements PluginObject
{
protected String yesOrNo = null;
protected static String YESORNO_TAG = "yesorno";
protected transient String lastValue;
public DoneObject()
{
}
public DoneObject(String yesOrNo)
{
this.yesOrNo = yesOrNo;
}
public void load(XMLReader parser)
{
}
void setYesOrNo(String decision)
{
yesOrNo = decision;
}
String getYesOrNo()
{
return yesOrNo;
}
public void setDocumentLocator(Locator locator)
{
}
public void startDocument()
throws SAXException
{
}
public void endDocument()
throws SAXException
{
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException
{
}
public void endPrefixMapping(String prefix)
throws SAXException
{
}
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
throws SAXException
{
lastValue = null;
}
public void endElement(String namespaceURI, String localName, String name)
throws SAXException
{
if(name.equals(YESORNO_TAG))
yesOrNo = lastValue;
}
public void characters(char[] ch, int start, int length)
throws SAXException
{
String value = new String(ch, start, length);
if(lastValue == null)
lastValue = value;
else
lastValue = lastValue + value;
}
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException
{
}
public void processingInstruction(String target, String data)
throws SAXException
{
}
public void skippedEntity(String name)
throws SAXException
{
}
}
Refer to the following related example listings:
Start Node Example
The following code listing is an excerpt from the plug-in sample that shows how to define a class that implements the PluginObject interface for a Start node. Note that the load(), startelement(), and endelement() method are defined. This excerpt is taken from the StartObject.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold.
Listing 4-2 Implementing the PluginObject Interface for a Start Node
public class StartObject implements PluginObject {
.
.
.
public void load(XMLReader parser) {
}
.
.
.
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
throws SAXException {
lastValue = null;
}
public void endElement(String namespaceURI, String localName, String name)
throws SAXException {
if (name.equals(EVENTDESC_TAG))
eventDesc = lastValue;
}
.
.
.
Refer to the following related example listings:
For more information about the plug-in sample, see BPM Plug-In Sample.
Reading and Saving Plug-In Data
To read (parse) and save plug-in data in XML format, you must implement the plug-in data interface.
Note: For each plug-in data interface class that is defined by a BPM plug-in value object via the KEY_DATA, KEY_PANEL, and KEY_RENDERER values, you must provide a public constructor that requires no arguments to support remote class loading on the client. This public constructor is not required to be supplied for the plug-in defined classes that are referenced by this class. For more information about using BPM plug-in value objects, see Plug-In Development Fundamentals.
This is a requirement for WebLogic Integration Release 2.1 Service Pack 1. If you do not provide a no-argument constructor for classes generated using an earlier release of WebLogic Integration, the classes will be instantiated, but you may receive exceptions if the client and server platforms are incompatible.
To enable the plug-in to read (parse) incoming data, the plug-in data interface class must implement the load() (parsing) method of its parent interface, com.bea.wlpi.common.plugin.PluginObject.
To enable the plug-in to save its data in XML format, you must implement one of the plug-in data interfaces defined in the following table based on the type of plug-in component being defined. Data must be saved in XML format, for example, when you are saving a template, template definition, or plug-in configuration XML document in the Studio.
Note: You do not need to implement the plug-in data interface to read and save data for the following plug-in components: functions, message types, and variable types.
Note: For information about the BPM DTDs and examples of plug-in-specific output, see DTD Formats in Programming BPM Client Applications. Each plug-in data interface is defined in more detail in the following sections. Implementing the PluginData Interface You must implement the com.bea.wlpi.common.plugin.PluginData interface to enable the plug-in component to save its data in XML format. Note: When defining actions, you should implement the PluginActionData interface, as described in Implementing the PluginActionData Interface. The following table describes the methods defined by the PluginData interface that you must implement. Note: The contents of the PluginData interface methods may be empty or simply return a message to the log, but they must be implemented.
The following sections provide code examples showing how the PluginData interface is implemented. Done Node Example The following code listing shows how to define a class that implements the PluginData interface for a Done node. Notable lines of code are shown in bold. Note: This class is not available as part of the plug-in sample. Listing 4-3 Implementing the PluginData Interface for a Done Node Refer to the following related example listings:
package com.bea.wlpi.test.plugin;
import com.bea.wlpi.common.XMLWriter;
import com.bea.wlpi.common.plugin.PluginData;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.xml.sax.*;
public class DoneNodeData extends DoneObject implements PluginData
{
public static int count = 0;
private int c;
public DoneNodeData()
{
c=count++;
}
public DoneNodeData(String yesOrNo)
{
super(yesOrNo);
c=count++;
}
public void save(XMLWriter writer, int indent) throws IOException
{
writer.saveElement(indent, YESORNO_TAG, yesOrNo);
}
}
Event Node Example
The following code listing is an excerpt from the plug-in sample that shows how to define a class that implements the PluginData interface for an Event node. This excerpt is taken from the EventNodeData.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold.
Listing 4-4 Implementing the PluginData Interface for an Event Node
package com.bea.wlpi.tour.po.plugin;
import com.bea.wlpi.common.XMLWriter;
import com.bea.wlpi.common.plugin.PluginData;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Map;
import org.xml.sax.*;
public class EventNodeData extends EventObject implements PluginData {
private SampleBundle bundle;
public EventNodeData() {
this(Locale.getDefault());
}
public EventNodeData(Locale lc) {
eventDesc = SamplePluginConstants.CONFIRM_EVENT;
bundle = new SampleBundle(lc);
}
public void save(XMLWriter writer, int indent) throws IOException {
writer.saveElement(indent, EVENTDESC_TAG, eventDesc);
}
public List getReferencedPublishables(Map publishables) {
return null;
}
public String getPrintableData() {
return bundle.getString("confirmOrderName");
}
public Object clone() {
return new EventNodeData(bundle.getLocale());
}
}
Refer to the following related example listings:
For more information about the plug-in sample, see BPM Plug-In Sample.
Start Node Example
The following code listing is an excerpt from the plug-in sample that shows how to define a class that implements the PluginData interface for a Start node. This excerpt is taken from the StartNodeData.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold.
Listing 4-5 Implementing the PluginData Interface for a Start Node
package com.bea.wlpi.tour.po.plugin;
import com.bea.wlpi.common.XMLWriter;
import com.bea.wlpi.common.plugin.PluginData;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Map;
import org.xml.sax.*;
public class StartNodeData extends StartObject implements PluginData {
private SampleBundle bundle;
public StartNodeData() {
this(Locale.getDefault());
}
public StartNodeData(Locale lc) {
eventDesc = SamplePluginConstants.START_ORDER_EVENT;
bundle = new SampleBundle(lc);
}
public void save(XMLWriter writer, int indent) throws IOException {
writer.saveElement(indent, EVENTDESC_TAG, eventDesc);
}
public List getReferencedPublishables(Map publishables) {
return null;
}
public String getPrintableData() {
return bundle.getString("startOrderLabel");
}
public Object clone() {
return new StartNodeData(bundle.getLocale());
}
}
Refer to the following related example listings:
For more information about the plug-in sample, see BPM Plug-In Sample.
Workflow Template Properties Example
The following code listing shows how to define a class that implements the PluginData interface for workflow template properties. The code reads and saves the user's response to a decision dialog box (yes or no). Notable lines of code are shown in bold.
Note: This class is not available as part of the plug-in sample.
Listing 4-6 Implementing the PluginData Interface for Workflow Template Properties
package com.bea.wlpi.test.plugin;
import com.bea.wlpi.common.XMLWriter;
import com.bea.wlpi.common.plugin.PluginData;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.xml.sax.*;
public class TemplatePropertiesData extends DoneObject implements PluginData {
public TemplatePropertiesData() {
}
public TemplatePropertiesData(String yesOrNo){
super(yesOrNo);
}
public void save(XMLWriter writer, int indent) throws IOException {
writer.saveElement(indent, YESORNO_TAG, yesOrNo);
}
public List getReferencedPublishables(Map publishables) {
return null;
}
public String getPrintableData() {
return null;
}
}
Refer to the following related example listings:
Workflow Template Definition Properties Example
The following code listing shows how to define a class that implements the PluginData interface for workflow template definition properties. The code reads and saves the user's response to a decision dialog box (yes or no). Notable lines of code are shown in bold.
Note: This class is not available as part of the plug-in sample.
Listing 4-7 Implementing the PluginData Interface for Workflow Template Definition Properties
package com.bea.wlpi.test.plugin;
import com.bea.wlpi.common.XMLWriter;
import com.bea.wlpi.common.plugin.PluginData;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.xml.sax.*;
public class TemplateDefinitionPropertiesData extends DoneObject implements PluginData
{
public TemplateDefinitionPropertiesData()
{
}
public TemplateDefinitionPropertiesData(String yesOrNo)
{
super(yesOrNo);
}
public void save(XMLWriter writer, int indent) throws IOException
{
writer.saveElement(indent, YESORNO_TAG, yesOrNo);
}
public List getReferencedPublishables(Map publishables) {
return null;
}
public String getPrintableData() {
return null;
}
public Object clone() {
return new TemplateDefinitionPropertiesData(yesOrNo);
}
}
Refer to the following related example listings:
Implementing the PluginActionData Interface
You must implement the com.bea.wlpi.common.plugin.PluginActionData interface to enable the plug-in action to save its data in XML format.
Note: The PluginActionData interface extends the PluginData interface. For more information about the PluginData interface methods, see the table PluginData Interface Methods.
The following table describes the method defined by the PluginActionData interface that you must implement.
Note: The contents of the PluginActionData interface methods may be empty or simply return a message to the log, but they must be implemented.
The following code listing is an excerpt from the plug-in sample that shows how to define a class that implements the PluginActionData interface. This excerpt is taken from the CheckInventoryActionData.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Note: Refer to SendConfirmationActionData.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory for another example of how to define a class the implements the PluginActionData interface. Listing 4-8 Implementing the PluginActionData Interface Refer to the following related example listings:
package com.bea.wlpi.tour.po.plugin;
import com.bea.wlpi.common.XMLWriter;
import com.bea.wlpi.common.plugin.PluginData;
import com.bea.wlpi.common.plugin.PluginActionData;
import java.io.IOException;
import java.util.ResourceBundle;
import java.util.Locale;
import java.util.List;
import java.util.Map;
import org.xml.sax.*;
public class CheckInventoryActionData extends CheckInventoryActionObject
implements PluginActionData {
private SampleBundle bundle;
public CheckInventoryActionData() {
getBundle(Locale.getDefault());
}
public CheckInventoryActionData(Locale lc) {
getBundle(lc);
}
public CheckInventoryActionData(Locale lc, String inputVariableName,
String outputVariableName) {
super(inputVariableName, outputVariableName);
getBundle(lc);
}
public void save(XMLWriter writer, int indent) throws IOException {
writer.saveElement(indent, INPUTVARIABLE_TAG, inputVariableName);
writer.saveElement(indent, OUTPUTVARIABLE_TAG, outputVariableName);
}
private void getBundle(Locale lc) {
bundle = new SampleBundle(lc);
}
public List getReferencedPublishables(Map publishables) {
return null;
}
public String getPrintableData() {
return bundle.getString("checkInventoryDesc");
}
public Object clone() {
return new CheckInventoryActionData(bundle.getLocale(),
new String(this.inputVariableName),
new String(this.outputVariableName));
}
public String getLabel() {
return bundle.getString("checkInventoryDesc");
}
}
For more information about the plug-in sample, see BPM Plug-In Sample.
Displaying the Plug-In GUI Component
To display the plug-in GUI component within the design client, all plug-ins must define a class that extends the plug-in panel class.
For example, in the figure Plug-In Example: Start Node, when a user selects the Start Order event as the Start node trigger, the Plug-in Manager loads the plug-in panel class, StartNodePanel, and it is instantiated by the Studio client using the no-argument constructor. The Studio client subsequently displays the plug-in GUI component in the Start Properties dialog box. (For more information about remote class loading, see Accessing the Plug-In Implementation.)
Note: For each plug-in GUI component class that is defined by a BPM plug-in value object via the KEY_DATA, KEY_PANEL, and KEY_RENDERER values, you must provide a public constructor that requires no arguments to support remote class loading on the client.This public constructor is not required to be supplied for the plug-in defined classes that are referenced by this class. For more information about using BPM plug-in value objects, see Plug-In Development Fundamentals.
This is a requirement for WebLogic Integration Release 2.1 Service Pack 1. If you do not provide a no-argument constructor for classes generated using an earlier release of WebLogic Integration, the classes will be instantiated, but you may receive exceptions if the client and server platforms are incompatible.
The following table describes the plug-in panel classes that you must extend based on the type of plug-in component being defined.
Note: You do not need to implement the plug-in panel interface to display a GUI component for the following plug-in components: functions and message types.
Each plug-in panel class is defined in more detail in the following sections. Defining the PluginPanel Class To define the plug-in GUI component displayed in the design client, you must define a class that extends the com.bea.wlpi.common.plugin.PluginPanel class. Note: When defining actions, Start or Event nodes, or variable types, you should extend the corresponding plug-in panel class defined in the table Plug-In Panel Classes, which extends the PluginPanel class. The following table describes the class methods defined by the PluginPanel class. Note: You can override any method that is not declared as final.
The following sections provide code examples showing how the PluginPanel class is defined. Done Node Example The following code listing shows how to define the PluginPanel class for a Done node. The code displays a decision dialog box (yes or no) within the Done Properties dialog box. Notable lines of code are shown in bold. Note: This class is not available as part of the plug-in sample. Listing 4-9 Defining the PluginPanel Class for a Done Node The following figure illustrates the resulting PluginPanel GUI component. Figure 4-1 PluginPanel GUI Component for a Done Node
package com.bea.wlpi.test.plugin;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import java.util.List;
import java.util.Locale;
import com.bea.wlpi.common.plugin.PluginPanel;
import com.bea.wlpi.common.plugin.PluginPanelContext;
import com.bea.wlpi.client.studio.Studio;
import com.bea.wlpi.common.VariableInfo;
public class DoneNodePanel extends PluginPanel
{
JPanel ButtonPanel = new JPanel();
ButtonGroup YesNoButtonGroup = new ButtonGroup();
JRadioButton YesButton = new JRadioButton();
JRadioButton NoButton = new JRadioButton();
TitledBorder titledBorder = new TitledBorder(new EtchedBorder());
public DoneNodePanel()
{
super(Locale.getDefault(), "jackolantern");
setLayout(null);
setBounds(12,12,420,300);
setPreferredSize(new Dimension(420,300));
ButtonPanel.setBorder(titledBorder);
ButtonPanel.setLayout(null);
add(ButtonPanel);
ButtonPanel.setBounds(72,60,300,144);
YesButton.setText("Yes");
YesButton.setSelected(true);
YesNoButtonGroup.add(YesButton);
ButtonPanel.add(YesButton);
YesButton.setBounds(60,36,46,23);
NoButton.setText("No");
YesNoButtonGroup.add(NoButton);
ButtonPanel.add(NoButton);
NoButton.setBounds(60,60,46,23);
titledBorder.setTitle("Yes or No?");
}
public void load() {
DoneNodeData myData = (DoneNodeData)getData();
if(myData != null) {
if(myData.getYesOrNo() != null && myData.getYesOrNo().equals(TestPluginConstants.DONE_NO)) {
NoButton.setSelected(true);
} else {
YesButton.setSelected(true);
}
}
}
public boolean validateAndSave()
{
DoneNodeData myData = (DoneNodeData)getData();
if(myData != null) {
if(YesButton.isSelected()) {
myData.setYesOrNo(TestPluginConstants.DONE_YES);
} else {
myData.setYesOrNo(TestPluginConstants.DONE_NO);
}
}
return true;
}
Refer to the following related example listings:
Workflow Template Properties Example
The following code listing shows how to define the PluginPanel class for workflow template properties. The code displays a decision dialog box (yes or no) within the Workflow Template Properties dialog box. Notable lines of code are shown in bold.
Note: This class is not available as part of the plug-in sample.
Listing 4-10 Defining the PluginPanel Class for Workflow Template Properties
package com.bea.wlpi.test.plugin;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import java.util.List;
import java.util.Locale;
import com.bea.wlpi.common.plugin.PluginPanel;
import com.bea.wlpi.common.plugin.PluginPanelContext;
import com.bea.wlpi.client.studio.Studio;
import com.bea.wlpi.common.VariableInfo;
public class TemplatePropertiesPanel extends PluginPanel
{
JPanel ButtonPanel = new JPanel();
ButtonGroup YesNoButtonGroup = new ButtonGroup();
JRadioButton YesButton = new JRadioButton();
JRadioButton NoButton = new JRadioButton();
TitledBorder titledBorder = new TitledBorder(new EtchedBorder());
public TemplatePropertiesPanel()
{
super(Locale.getDefault(), "stpatty");
setLayout(null);
setBounds(12,12,420,300);
ButtonPanel.setBorder(titledBorder);
ButtonPanel.setLayout(null);
add(ButtonPanel);
ButtonPanel.setBounds(72,60,300,144);
YesButton.setText("Yes");
YesButton.setSelected(true);
YesNoButtonGroup.add(YesButton);
ButtonPanel.add(YesButton);
YesButton.setBounds(60,36,46,23);
NoButton.setText("No");
YesNoButtonGroup.add(NoButton);
ButtonPanel.add(NoButton);
NoButton.setBounds(60,60,46,23);
titledBorder.setTitle("Yes or No?");
}
public void load() {
TemplatePropertiesData myData = (TemplatePropertiesData)getData();
if(myData != null) {
if(myData.getYesOrNo() != null && myData.getYesOrNo().equals(TestPluginConstants.DONE_NO)) {
NoButton.setSelected(true);
} else {
YesButton.setSelected(true);
}
}
}
public boolean validateAndSave()
{
TemplatePropertiesData myData = (TemplatePropertiesData)getData();
if(myData != null) {
if(YesButton.isSelected()) {
myData.setYesOrNo(TestPluginConstants.DONE_YES);
} else {
myData.setYesOrNo(TestPluginConstants.DONE_NO);
}
}
return true;
}
The following figure illustrates the resulting PluginPanel GUI component.
Figure 4-2 PluginPanel GUI Component for Workflow Template Properties
Refer to the following related example listings:
Workflow Template Definition Properties Example
The following code listing shows how to define the PluginPanel class for workflow template definition properties. The code displays a decision dialog box (yes or no) within the Workflow Template Definition Properties dialog box. Notable lines of code are shown in bold.
Note: This class is not available as part of the plug-in sample.
Listing 4-11 Defining the PluginPanel Class for Workflow Template Definition Properties
package com.bea.wlpi.test.plugin;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import java.util.List;
import java.util.Locale;
import com.bea.wlpi.common.plugin.PluginPanel;
import com.bea.wlpi.common.plugin.PluginPanelContext;
import com.bea.wlpi.client.studio.Studio;
import com.bea.wlpi.common.VariableInfo;
public class TemplateDefinitionPropertiesPanel extends PluginPanel
{
JPanel ButtonPanel = new JPanel();
ButtonGroup YesNoButtonGroup = new ButtonGroup();
JRadioButton YesButton = new JRadioButton();
JRadioButton NoButton = new JRadioButton();
TitledBorder titledBorder = new TitledBorder(new EtchedBorder());
public TemplateDefinitionPropertiesPanel()
{
super(Locale.getDefault(), "valentine");
setLayout(null);
setBounds(12,12,420,300);
ButtonPanel.setBorder(titledBorder);
ButtonPanel.setLayout(null);
add(ButtonPanel);
ButtonPanel.setBounds(72,60,300,144);
YesButton.setText("Yes");
YesButton.setSelected(true);
YesNoButtonGroup.add(YesButton);
ButtonPanel.add(YesButton);
YesButton.setBounds(60,36,46,23);
NoButton.setText("No");
YesNoButtonGroup.add(NoButton);
ButtonPanel.add(NoButton);
NoButton.setBounds(60,60,46,23);
titledBorder.setTitle("Yes or No?");
}
public void load() {
TemplateDefinitionPropertiesData myData = (TemplateDefinitionPropertiesData)getData();
if(myData != null) {
if(myData.getYesOrNo() != null && myData.getYesOrNo().equals(TestPluginConstants.DONE_NO)) {
NoButton.setSelected(true);
} else {
YesButton.setSelected(true);
}
}
}
public boolean validateAndSave()
{
TemplateDefinitionPropertiesData myData = (TemplateDefinitionPropertiesData)getData();
if(myData != null) {
if(YesButton.isSelected()) {
myData.setYesOrNo(TestPluginConstants.DONE_YES);
} else {
myData.setYesOrNo(TestPluginConstants.DONE_NO);
}
}
return true;
}
The following figure illustrates the resulting PluginPanel GUI component.
Figure 4-3 PluginPanel GUI Component for Workflow Template Definition Properties
Refer to the following related example listings:
Defining the PluginActionPanel Class
To define the GUI component displayed in the design client when defining a plug-in action, you must define a class that extends the com.bea.wlpi.common.plugin.PluginActionPanel class. In the Studio, the PluginActionPanel class is used by the Action Plugin dialog box, which provides generic support for subactions.
The PluginActionPanel class defines no additional methods.
Note: The PluginActionPanel class extends the PluginPanel class. For more information about the PluginPanel class methods, see the table PluginPanel Class Methods.
The following code listing is an excerpt from the plug-in sample that shows how to define the PluginActionPanel class. This excerpt is taken from the CheckInventoryActionPanel.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Note: Refer to the SendConfirmationActionPanel.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory for another example of how to define a PluginActionPanel class. Listing 4-12 Defining the PluginActionPanel Class The following figure illustrates the resulting PluginActionPanel GUI component. Figure 4-4 PluginActionPanel GUI Component
package com.bea.wlpi.tour.po.plugin;
import java.awt.*;
import javax.swing.*;
import java.util.List;
import java.util.Locale;
import com.bea.wlpi.common.VariableInfo;
import com.bea.wlpi.common.plugin.PluginActionPanel;
import com.bea.wlpi.common.plugin.PluginPanelContext;
public class CheckInventoryActionPanel extends PluginActionPanel {
private JLabel inputLabel = new JLabel();
private JLabel outputLabel = new JLabel();
private JComboBox inputComboBox = new JComboBox();
private JComboBox outputComboBox = new JComboBox();
private List variables = null;
public CheckInventoryActionPanel() {
this(Locale.getDefault());
}
public CheckInventoryActionPanel(Locale lc) {
super(lc, "checkinventory");
setLayout(null);
setBounds(12, 12, 420, 210);
setPreferredSize(new Dimension(420, 210));
add(inputLabel);
inputLabel.setBounds(12, 48, 96, 24);
add(outputLabel);
outputLabel.setBounds(12, 108, 166, 24);
add(inputComboBox);
inputComboBox.setBounds(190, 48, 212, 24);
inputComboBox.setEditable(true);
add(outputComboBox);
outputComboBox.setBounds(190, 108, 212, 24);
outputComboBox.setEditable(true);
}
public void load() {
setResourceBundle("com.bea.wlpi.tour.po.plugin.SamplePlugin");
inputLabel.setText(getString("inputLabel"));
outputLabel.setText(getString("outputLabel"));
CheckInventoryActionData myData = (CheckInventoryActionData)getData();
variables = getContext().getVariableList(VariableInfo.TYPE_INT);
// load is called before displaying this panel each time. Make sure to
// remove items from the combo box before filling with currently
// defined variables.
inputComboBox.removeAllItems();
String inputVar = myData.getInputVariableName();
int n = variables == null ? 0 : variables.size();
for (int i = 0; i < n; i++) {
VariableInfo varInfo = (VariableInfo)variables.get(i);
inputComboBox.addItem(varInfo.getName());
if (inputVar != null && inputVar.equals(varInfo.getName())) {
inputComboBox.setSelectedIndex(i);
}
}
if (inputVar == null && n > 0)
inputComboBox.setSelectedIndex(0);
outputComboBox.removeAllItems();
String outputVar = myData.getOutputVariableName();
for (int i = 0; i < n; i++) {
VariableInfo varInfo = (VariableInfo)variables.get(i);
outputComboBox.addItem(varInfo.getName());
if (outputVar != null && outputVar.equals(varInfo.getName())) {
outputComboBox.setSelectedIndex(i);
}
}
if (outputVar == null && n > 0)
outputComboBox.setSelectedIndex(0);
}
public boolean validateAndSave() {
CheckInventoryActionData myData = (CheckInventoryActionData)getData();
String input = (String)inputComboBox.getEditor().getItem();
try {
VariableInfo varInfo = getContext().checkVariable(input,
new String[]{ VariableInfo.TYPE_INT });
if (varInfo == null)
return false;
if (!(varInfo.getType().equals(VariableInfo.TYPE_INT))) {
JOptionPane.showMessageDialog(SwingUtilities.windowForComponent(this),
getString("Message_100"),
getString("variableErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return false;
}
input = varInfo.getName();
} catch (Exception e) {
JOptionPane.showMessageDialog(SwingUtilities.windowForComponent(this),
e.getLocalizedMessage(),
getString("variableErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return false;
}
String output = (String)outputComboBox.getEditor().getItem();
try {
VariableInfo varInfo = getContext().checkVariable(output,
new String[]{ VariableInfo.TYPE_INT });
if (varInfo == null)
return false;
if (!(varInfo.getType().equals(VariableInfo.TYPE_INT))) {
JOptionPane.showMessageDialog(SwingUtilities.windowForComponent(this),
getString("Message_100"),
getString("variableErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return false;
}
output = varInfo.getName();
} catch (Exception e) {
JOptionPane.showMessageDialog(SwingUtilities.windowForComponent(this),
e.getLocalizedMessage(),
getString("variableErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return false;
}
if (input == null || output == null) {
JOptionPane.showMessageDialog(null, getString("Message_101"),
getString("invalidDataTitle"),
JOptionPane.ERROR_MESSAGE);
return false;
}
myData.setInputVariableName(input);
myData.setOutputVariableName(output);
return true;
}
}
Refer to the following related example listings:
For more information about the plug-in sample, see BPM Plug-In Sample.
Defining the PluginTriggerPanel Class
To define the GUI component to be displayed in the design client when defining a plug-in Start or Event node, you must defne a class that extends the com.bea.wlpi.common.plugin.PluginTriggerPanel class. In the Studio, the Start and Event node PluginTriggerPanel classes are used by the Start Properties and Event Properties dialog box, respectively.
The following table describes the class methods that are defined by the PluginTriggerPanel class.
Note: The PluginTriggerPanel class extends the PluginPanel class. For more information about the PluginPanel class methods, see the table PluginPanel Class Methods.
The following sections provide code examples showing how the PluginTriggerPanel class is defined. Start Node Example The following code listing is an excerpt from the plug-in sample that shows how to define the PluginTriggerPanel class for a Start node. This excerpt is taken from the StartNodePanel.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Listing 4-13 Defining the PluginTriggerPanel Class for a Start Node The START_ORDER_EVENT and ORDER_FIELDS field element values are included within the SamplePluginConstants.java class file. They define the plug-in Start node event descriptor and field element values as follows: For more information about defining the plug-in field to access a plug-in-specific external event, see Defining the Run-Time Component Class for a Message Type. The following figure illustrates the resulting PluginTriggerPanel GUI component. Figure 4-5 PluginTriggerPanel GUI Component for a Start Node
package com.bea.wlpi.tour.po.plugin;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import java.util.List;
import java.util.Locale;
import com.bea.wlpi.common.plugin.PluginTriggerPanel;
import com.bea.wlpi.common.plugin.PluginPanelContext;
import com.bea.wlpi.common.VariableInfo;
public class StartNodePanel extends PluginTriggerPanel {
private JLabel StartOrderLabel = new JLabel();
private JTextArea StartOrderText = new JTextArea();
public StartNodePanel() {
this(Locale.getDefault());
}
public StartNodePanel(Locale lc) {
super(lc, "startorder");
setLayout(null);
setBounds(12, 12, 420, 240);
setPreferredSize(new Dimension(420, 240));
add(StartOrderLabel);
StartOrderLabel.setFont(new Font("Dialog", Font.BOLD, 16));
StartOrderLabel.setBounds(120, 12, 156, 24);
StartOrderText.setLineWrap(true);
StartOrderText.setWrapStyleWord(true);
StartOrderText.setEditable(false);
add(StartOrderText);
StartOrderText.setBounds(30, 48, 348, 144);
}
public void load() {
setResourceBundle("com.bea.wlpi.tour.po.plugin.SamplePlugin");
StartOrderLabel.setText(getString("startOrderLabel"));
StartOrderText.setText(getString("startOrderText"));
}
public boolean validateAndSave() {
return true;
}
public String[] getFields() {
return SamplePluginConstants.ORDER_FIELDS;
}
public String getEventDescriptor() {
return SamplePluginConstants.START_ORDER_EVENT;
}
}final static String START_ORDER_EVENT = "startOrder";
final static String[] ORDER_FIELDS = {
"CustomerName", "CustomerID", "OrderStatus", "OrderID",
"CustomerEmail", "ItemName", "ItemID", "ItemQuantity",
"CustomerState"
};
Refer to the following related example listings:
For more information about the plug-in sample, see BPM Plug-In Sample.
Event Node Example
The following code listing is an excerpt from the plug-in sample that shows how to define the PluginTriggerPanel class for an Event node. This excerpt is taken from the EventNodePanel.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold.
Listing 4-14 Defining the PluginTriggerPanel Class for an Event Node
package com.bea.wlpi.tour.po.plugin;
import java.awt.*;
import javax.swing.*;
import java.util.Locale;
import com.bea.wlpi.common.plugin.PluginTriggerPanel;
import com.bea.wlpi.common.plugin.PluginPanelContext;
import com.bea.wlpi.common.VariableInfo;
public class EventNodePanel extends PluginTriggerPanel {
private JLabel confirmOrderLabel = new JLabel();
private JTextArea confirmOrderText = new JTextArea();
/**
* Create a new EventNodePanel.
*/
public EventNodePanel() {
this(Locale.getDefault());
}
public EventNodePanel(Locale lc) {
super(lc, "confirmevent");
setLayout(null);
setBounds(12, 12, 420, 240);
setPreferredSize(new Dimension(420, 240));
add(confirmOrderLabel);
confirmOrderLabel.setFont(new Font("Dialog", Font.BOLD, 16));
confirmOrderLabel.setBounds(144, 12, 120, 24);
confirmOrderText.setRequestFocusEnabled(false);
confirmOrderText.setLineWrap(true);
confirmOrderText.setWrapStyleWord(true);
confirmOrderText.setEditable(false);
add(confirmOrderText);
confirmOrderText.setBounds(30, 48, 348, 144);
}
public void load() {
setResourceBundle("com.bea.wlpi.tour.po.plugin.SamplePlugin");
confirmOrderLabel.setText(getString("confirmOrderLabel"));
confirmOrderText.setText(getString("confirmOrderText"));
}
public boolean validateAndSave() {
// There are no UI controls on this panel which accept user input.
// Therefore, there is nothing to do in this method.
return true;
}
public String[] getFields() {
return SamplePluginConstants.CONFIRM_FIELDS;
}
public String getEventDescriptor() {
return SamplePluginConstants.CONFIRM_EVENT;
}
}
The CONFIRM_EVENT and CONFIRM_FIELD are included within the SamplePluginConstants.java class. They define the plug-in Event node event descriptor and field element values as follows:
final static String CONFIRM_EVENT = "confirmOrder";
final static String[] CONFIRM_FIELDS = { "Status", "TotalPrice" };
For more information about defining the plug-in field to access a plug-in-specific external event, see Defining the Run-Time Component Class for a Message Type.
The following figure illustrates the resulting PluginTriggerPanel GUI component.
Figure 4-6 PluginTriggerPanel GUI Component for a Event Node
Refer to the following related example listings:
For more information about the plug-in sample, see BPM Plug-In Sample.
Defining the PluginVariablePanel Class
To define the GUI component displayed in the design client when defining a plug-in variable that enables users to edit a plug-in variable type, you must define a class that extends the com.bea.wlpi.common.plugin.PluginVariablePanel class. In the Studio, the PluginVariablePanel class is used by the Update Variable dialog box.
The following table describes the class methods that are defined by the PluginVariablePanel class.
Note: The PluginVariablePanel class extends the PluginPanel class. For more information about the PluginPanel class methods, see the table PluginPanel Class Methods.
The following code listing shows how to define the PluginVariablePanel class. Notable lines of code are shown in bold. Note: This class is not available as part of the plug-in sample. Listing 4-15 Defining the PluginVariablePanel Class The following figure illustrates the resulting PluginVariablePanel GUI component. Figure 4-7 PluginVariablePanel GUI Component
package com.bea.wlpi.test.plugin;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import java.util.List;
import java.util.Locale;
import com.bea.wlpi.client.studio.Studio;
import com.bea.wlpi.common.VariableInfo;
import com.bea.wlpi.common.plugin.PluginVariablePanel;
public class VariablePanel extends PluginVariablePanel {
JTextField highField, lowField;
public VariablePanel() {
super(Locale.getDefault(), "augustus");
setLayout(null);
setBounds(12,12,420,60);
highField = new JTextField();
highField.setLocation(20, 10);
highField.setSize(300, 20);
add(highField);
lowField = new JTextField();
lowField.setLocation(20, 40);
lowField.setSize(300, 20);
add(lowField);
}
public void load() {
if (variableValue != null) {
highField.setText(((MySpecificObject)variableValue).getHigh());
lowField.setText(((MySpecificObject)variableValue).getLow());
} else {
highField.setText("");
lowField.setText("");
}
}
public boolean validateAndSave() {
try {
variableValue = new MySpecificObject(lowField.getText(), highField.getText());
} catch (Exception e) {
return false;
}
return true;
}
}
Refer to the related example listing, Defining the PluginVariableRenderer Class, which shows how to display the value of a plugin-defined variable type in the cell of a javax.swing.JTable. Defining the PluginVariableRenderer Class To display the value of a plugin-defined variable type in the cell of a javax.swing.JTable, implement the com.bea.wlpi.common.plugin.PluginVariableRenderer interface. Note: Classes implementing this interface must be subclasses of java.awt.Component. The following table describes the PluginVariableRenderer interface method that you must implement.
The following code listing shows how to display the value of a plugin-defined variable type in the cell of a javax.swing.JTable. Notable lines of code are shown in bold. Note: This class is not available as part of the plug-in sample. Listing 4-16 Defining the PluginVariableRenderer Class Refer to Defining the PluginVariablePanel Class, which shows how to display the plug-in GUI component in the design client.
package com.bea.wlpi.test.plugin;
import java.io.Serializable;
import javax.swing.JLabel;
import com.bea.wlpi.common.plugin.PluginVariableRenderer;
public class VariableRenderer extends JLabel implements PluginVariableRenderer, Serializable {
public VariableRenderer() {
}
public void setValue(Object value) {
if (value == null)
setText("null");
else
setText(value.toString());
}
}
Executing the Plug-In
To execute the plug-in, you must define the run-time component class for the plug-in.
The following table describes the plug-in component interfaces that you must implement based on the type of plug-in component being created. To enable the plug-in to read (parse) the incoming data, the run-time component class must implement the load() (parsing) method of its parent interface, com.bea.wlpi.common.plugin.PluginObject.
Note: The following two plug-in components do not need to define execution information: variable types, workflow template properties, or workflow template definition properties.
Note: At run time you can use context interfaces that are passed by the Plug-in Manager to access the run-time context and services for the associated plug-in. For information about the context interfaces, see Using Plug-In Run-Time Contexts. The following sections explain in detail how to define each of the plug-in run-time component classes. Defining the Run-Time Component Class for an Action To define the run-time component class for a plug-in action, you must:
Defining the Execution Information for a Plug-In Action
To define the execution information for a plug-in action, you must implement the com.bea.wlpi.server.plugin.PluginAction interface and its methods, as described in the following table.
The following code listing is an excerpt from the plug-in sample that shows how to define the run-time component class for an action. This excerpt is taken from the CheckInventoryAction.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Note: Refer to the SendConfirmationAction.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory for another example of how to define the plug-in action run-time component class. Listing 4-17 Defining the Run-Time Component Class for an Action Refer to the following related example listings:
package com.bea.wlpi.tour.po.plugin;
import java.io.IOException;
import com.bea.wlpi.server.plugin.PluginAction;
import com.bea.wlpi.common.WorkflowException;
import com.bea.wlpi.common.plugin.PluginException;
import com.bea.wlpi.common.Messages;
import com.bea.wlpi.common.VariableInfo;
import com.bea.wlpi.evaluator.Expression;
import com.bea.wlpi.evaluator.EvaluatorException;
import com.bea.wlpi.server.common.ExecutionContext;
import com.bea.wlpi.evaluator.ExpressionParser;
import com.bea.wlpi.server.plugin.ActionContext;
import org.xml.sax.*;
public class CheckInventoryAction extends CheckInventoryActionObject
implements PluginAction {
private Expression inputValueExpression;
static int[] quantities = {
250, 120, 5, 75, 0, 300, 550, 25, 16, 630, 3
};
public CheckInventoryAction() {
}
public void fixup(ExpressionParser parser) {
System.out.println("SamplePlugin: CheckInventoryAction.fixup called");
try {
inputValueExpression =
inputVariableName != null
? new Expression("$" + inputVariableName, parser) : null;
} catch (EvaluatorException ee) {
System.out.println("EvaluationException ocurred in CheckInventoryAction");
}
}
public int execute(ActionContext actionContext, ExecutionContext context)
throws WorkflowException {
System.out.println("SamplePlugin: CheckInventoryAction.execute called");
Object valueObject = inputValueExpression != null
? inputValueExpression.evaluate(context) : null;
if (valueObject == null)
throw new PluginException("Sample Plugin", "itemNo is null");
if (!(valueObject instanceof Long))
throw new PluginException("Sample Plugin", "itemNo not an integer");
int itemNo = ((Long)valueObject).intValue();
int quantity = quantities[itemNo % quantities.length] + itemNo;
System.out.println("CheckInventoryAction: Output = " + quantity);
context.setVariableValue(outputVariableName, new Long(quantity));
return ExecutionContext.CONTINUE;
}
public void response(ActionContext actionContext, ExecutionContext execContext, Object data)
throws WorkflowException {
}
public void startedWorkflowDone(ActionContext actionContext,
ExecutionContext context,
VariableInfo[] output) {
}
For more information about the plug-in sample, see BPM Plug-In Sample.
Customizing the Action Tree
To support plug-in actions, you must customize the actions and/or action categories listed in the action trees that are displayed in various dialog boxes within the Studio.
For example, the following figure illustrates the Add Action dialog box with a customized version of the action tree.
Figure 4-8 Customized Action Tree
As shown in the previous figure, the BPM action tree has been customized to add one new action category, Sample Actions, that provides the following plug-in actions:
You can customize the action tree by performing the following steps:
When the Plug-in Manager calls the getPluginCapabilitiesInfo() method, it must pass the existing action category tree as a com.bea.wlpi.common.plugin.CategoryInfo object to enable the plug-in to traverse the tree and determine where to add the custom actions and/or action categories. Once the Plug-in Manager retrieves this valid tree structure, it merges the retrieved tree structure with the existing tree structure and assigns a new systemID to each new category.
The Plug-in Manager can call the getPluginCapabilitiesInfo() method multiple times, and you must return a newly initialized action tree each time. If you reuse an existing CategoryInfo object, the Plug-in Manager raises an IllegalStateException when it calls the setSystemID() method for the second time.
You can add new actions and/or subcategories to existing action categories at any leve., You cannot, however, remove actions or subcategories from an existing category.
The following code listing is an excerpt from the plug-in sample that shows how to define the following methods:
This excerpt is taken from the SamplePluginBean.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. The example defines both the Check Inventory and Send Confirmation actions. Notable lines of code are shown in bold.
Listing 4-18 Customizing an Action Tree
private CategoryInfo[] getCategoryInfo(SampleBundle bundle) {
ActionInfo checkInventoryAction =
new ActionInfo(SamplePluginConstants.PLUGIN_NAME, 1,
bundle.getString("checkInventoryName"),
bundle.getString("checkInventoryDesc"), ICON_BYTE_ARRAY,
ActionCategoryInfo.ID_NEW,
ActionInfo.ACTION_STATE_ALL,
SamplePluginConstants.CHECKINV_CLASSES);
ActionInfo sendConfirmAction =
new ActionInfo(SamplePluginConstants.PLUGIN_NAME, 2,
bundle.getString("sendConfirmName"),
bundle.getString("sendConfirmDesc"), ICON_BYTE_ARRAY,
ActionCategoryInfo.ID_NEW,
ActionInfo.ACTION_STATE_ALL,
SamplePluginConstants.SENDCONF_CLASSES);
ActionCategoryInfo[] actions =
new ActionCategoryInfo[]{ checkInventoryAction, sendConfirmAction};
CategoryInfo[] catInfo =
new CategoryInfo[]{ new CategoryInfo(SamplePluginConstants.PLUGIN_NAME,
0, bundle.getString("catName"),
bundle.getString("catDesc"),
ActionCategoryInfo.ID_NEW,
actions)};
return catInfo;
}
public PluginCapabilitiesInfo getPluginCapabilitiesInfo(Locale lc,
CategoryInfo[] info) {
PluginInfo pi;
FieldInfo orderFieldInfo;
FieldInfo confirmFieldInfo;
FieldInfo[] fieldInfo;
FunctionInfo fi;
FunctionInfo[] functionInfo;
StartInfo si;
StartInfo[] startInfo;
EventInfo ei;
EventInfo[] eventInfo;
SampleBundle bundle = new SampleBundle(lc);
log("getPluginCapabilities called");
pi = createPluginInfo(lc);
orderFieldInfo =
new FieldInfo(SamplePluginConstants.PLUGIN_NAME, 3,
bundle.getString("orderFieldName"),
bundle.getString("orderFieldDesc"),
SamplePluginConstants.ORDER_FIELD_CLASSES, false);
confirmFieldInfo =
new FieldInfo(SamplePluginConstants.PLUGIN_NAME, 4,
bundle.getString("confirmFieldName"),
bundle.getString("confirmFieldDesc"),
SamplePluginConstants.CONFIRM_FIELD_CLASSES, false);
fieldInfo = new FieldInfo[]{ orderFieldInfo, confirmFieldInfo};
ei = new EventInfo(SamplePluginConstants.PLUGIN_NAME, 6,
bundle.getString("confirmOrderName"),
bundle.getString("confirmOrderDesc"), ICON_BYTE_ARRAY,
SamplePluginConstants.EVENT_CLASSES,
confirmFieldInfo);
eventInfo = new EventInfo[]{ ei};
fi = new FunctionInfo(SamplePluginConstants.PLUGIN_NAME, 7,
bundle.getString("calcTotalName"),
bundle.getString("calcTotalDesc"),
bundle.getString("calcTotalHint"),
SamplePluginConstants.FUNCTION_CLASSES, 3, 3);
functionInfo = new FunctionInfo[]{ fi};
si = new StartInfo(SamplePluginConstants.PLUGIN_NAME, 5,
bundle.getString("startOrderName"),
bundle.getString("startOrderDesc"), ICON_BYTE_ARRAY,
SamplePluginConstants.START_CLASSES, orderFieldInfo);
startInfo = new StartInfo[]{ si};
PluginCapabilitiesInfo pci = new PluginCapabilitiesInfo(pi,
getCategoryInfo(bundle), eventInfo, fieldInfo, functionInfo, startInfo,
null, null, null, null, null);
return pci;
}
Refer to the following related example listings:
For more information about the plug-in sample, see BPM Plug-In Sample.
Defining the Run-Time Component Class for a Done Node
To define the run-time component class for a Done node, implement the com.bea.wlpi.server.plugin.PluginDone interface.
Note: The PluginDone interface extends com.bea.wlpi.server.plugin.PluginTemplateNode. For more information about the PluginTemplateNode interface and its methods, see PluginTemplateNode Interface.
The PluginDone interface adds no other methods.
The following code listing shows how to define the run-time component class for a Done node. Notable lines of code are shown in bold.
Note: This class is not available as part of the plug-in sample.
Listing 4-19 Defining the Run-Time Component Class for a Done Node
package com.bea.wlpi.test.plugin;
import com.bea.wlpi.common.Messages;
import com.bea.wlpi.common.WorkflowException;
import com.bea.wlpi.evaluator.ExpressionParser;
import com.bea.wlpi.server.common.ExecutionContext;
import com.bea.wlpi.server.plugin.PluginDone;
import java.io.IOException;
import java.util.Map;
import org.xml.sax.*;
public class DoneNode extends DoneObject implements PluginDone {
public DoneNode() {
}
public int activate(ExecutionContext context)
throws WorkflowException {
System.out.println("TestPlugin: DoneNode activated");
// Initialize the plugin instance data.
Map instanceData = (Map)context.getPluginInstanceData(TestPluginConstants.PLUGIN_NAME);
if (instanceData != null) {
Object started = instanceData.get(TestPluginConstants.INST_DATA_STARTED);
System.out.println("instance data = " + started);
}
int stopMode;
if (yesOrNo.equals(TestPluginConstants.DONE_YES)) {
System.out.println("TestPlugin: DoneNode = YES");
stopMode = ExecutionContext.CONTINUE;
} else {
System.out.println("TestPlugin: DoneNode = NO");
stopMode = ExecutionContext.STOP;
}
return stopMode;
}
public void fixup(ExpressionParser parser) {
}
Refer to the following related example listings:
Defining the Run-Time Component Class for an Event Node
To define the run-time component class for an event node, implement the com.bea.wlpi.server.plugin.PluginEvent interface.
The following table describes the PluginEvent interface methods that you must implement as part of the run-time component class.
The following code listing is an excerpt from the plug-in sample that shows how to define the run-time component class for an Event node. This excerpt is taken from the StartNode.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Listing 4-20 Defining the Run-Time Component Class for an Event Node Refer to the following related example listings:
package com.bea.wlpi.tour.po.plugin;
import java.io.IOException;
import com.bea.wlpi.server.plugin.PluginEvent;
import com.bea.wlpi.common.WorkflowException;
import com.bea.wlpi.common.Messages;
import com.bea.wlpi.evaluator.Expression;
import com.bea.wlpi.evaluator.EvaluatorException;
import com.bea.wlpi.server.common.ExecutionContext;
import com.bea.wlpi.server.plugin.EventContext;
import com.bea.wlpi.server.workflow.Workflow;
import com.bea.wlpi.server.workflow.Variable;
import com.bea.wlpi.evaluator.ExpressionParser;
import com.bea.wlpi.server.workflow.TemplateNode;
import org.xml.sax.*;
public class EventNode extends EventObject implements PluginEvent {
public EventNode() {
}
public int activate(EventContext eventContext, ExecutionContext execContext)
throws WorkflowException {
System.out.println("SamplePlugin: EventNode activated");
eventContext.activateEvent(execContext,
SamplePluginConstants.CONTENTTYPE,
eventDesc, null, null);
return ExecutionContext.CONTINUE;
}
public int trigger(EventContext context, ExecutionContext execContext)
throws WorkflowException {
System.out.println("SamplePlugin: EventNode triggered");
context.removeEventWatch(execContext);
return ExecutionContext.CONTINUE;
}
public void fixup(ExpressionParser parser) {
}
}
For more information about the plug-in sample, see BPM Plug-In Sample.
Defining the Run-Time Component Class for a Function
To define the run-time component class for a function, implement the com.bea.wlpi.common.plugin.PluginFunction interface. The following table describes the PluginFunction interface method that you must implement.
The following code listing is an excerpt from the plug-in sample that shows how to define the run-time component class for a function. This excerpt is taken from the CalculateTotalPriceFunction.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Listing 4-21 Defining a Run-Time Component Class for a Function For more information about the plug-in sample, see BPM Plug-In Sample. Defining the Run-Time Component Class for a Message Type To define the run-time component class for a message type, you must implement the com.bea.wlpi.common.plugin.PluginField interface to define a plug-in field. A plug-in field enables you to parse custom plug-in data that is associated with an external event received by a Start or Event node. The data can then be referenced from an evaluator expression. The plug-in determines the content type of the external event by accessing the associated event descriptor. The plug-in framework uses the plug-in field data to populate the Expression Builder dialog box. For example, the following figure shows an Expression Builder dialog box in which the plug-in Fields category is selected, resulting in the display of a list of valid field elements. Figure 4-9 Plug-In Fields Displayed in an Expression Builder Dialog Box
package com.bea.wlpi.tour.po.plugin;
import com.bea.wlpi.common.Messages;
import com.bea.wlpi.common.plugin.PluginFunction;
import com.bea.wlpi.common.plugin.PluginException;
import com.bea.wlpi.evaluator.*;
import com.bea.wlpi.tour.po.BadStateException;
import java.lang.NumberFormatException;
/**
* This sample function calculates the total price of an order. The price is
* calculated using the itemID, quantity, and the State/Province of the order.
* The State/Province is used to look up the sales tax rate.
*/
public class CalculateTotalPriceFunction implements PluginFunction {
static StateTax[] stateTax = {
new StateTax("AB", 0.07), new StateTax("AK", 0.06),
new StateTax("AL", 0.06), new StateTax("AR", 0.03),
new StateTax("AZ", 0.05), new StateTax("BC", 0.05),
new StateTax("CA", 0.04), new StateTax("CO", 0.08),
new StateTax("CT", 0.03), new StateTax("DC", 0.05),
new StateTax("DE", 0.05), new StateTax("FL", 0.00),
new StateTax("GA", 0.06), new StateTax("HI", 0.07),
new StateTax("IA", 0.07), new StateTax("ID", 0.08),
new StateTax("IL", 0.06), new StateTax("IN", 0.03),
new StateTax("KS", 0.05), new StateTax("KY", 0.07),
new StateTax("LA", 0.06), new StateTax("MA", 0.05),
new StateTax("MB", 0.05), new StateTax("MD", 0.04),
new StateTax("ME", 0.04), new StateTax("MI", 0.03),
new StateTax("MN", 0.05), new StateTax("MO", 0.06),
new StateTax("MS", 0.07), new StateTax("MT", 0.07),
new StateTax("NB", 0.08), new StateTax("NC", 0.07),
new StateTax("ND", 0.08), new StateTax("NE", 0.03),
new StateTax("NF", 0.06), new StateTax("NH", 0.09),
new StateTax("NJ", 0.03), new StateTax("NM", 0.06),
new StateTax("NV", 0.03), new StateTax("NY", 0.06),
new StateTax("NS", 0.08), new StateTax("NT", 0.07),
new StateTax("OH", 0.07), new StateTax("OK", 0.02),
new StateTax("ON", 0.08), new StateTax("OR", 0.08),
new StateTax("PA", 0.07), new StateTax("PE", 0.07),
new StateTax("PQ", 0.05), new StateTax("RI", 0.05),
new StateTax("SC", 0.05), new StateTax("SD", 0.04),
new StateTax("SK", 0.04), new StateTax("TN", 0.06),
new StateTax("TX", 0.06), new StateTax("UT", 0.07),
new StateTax("VA", 0.07), new StateTax("VT", 0.08),
new StateTax("WA", 0.07), new StateTax("WI", 0.07),
new StateTax("WV", 0.08), new StateTax("WY", 0.05),
new StateTax("YT", 0.07)
};
static double[] prices = {
29.95, 524.79, 33.21, 9.99, 12.28, 152.50, 43.55, 32.90, 328.55, 72.50,
87.50
};
public CalculateTotalPriceFunction() throws EvaluatorException {
System.out.println("CalculateTotalPriceFunction: constructor called");
}
public Object evaluate(EvaluationContext context, Object[] args)
throws PluginException {
int itemNo;
int quantity;
String state;
System.out.println("CalculateTotalPriceFunction: evaluate called");
try {
itemNo = ((Long)args[0]).intValue();
} catch (Exception e) {
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"Invalid ItemID argument");
}
try {
quantity = ((Long)args[1]).intValue();
} catch (Exception e2) {
e2.printStackTrace();
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"Invalid Quantity argument");
}
if (!(args[2] instanceof String)) {
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"Invalid State argument");
}
state = (String)args[2];
int i;
// Find the state/province in the stateTax array
for (i = 0; i < stateTax.length; ++i) {
if (stateTax[i].equals(state))
break;
}
if (i == stateTax.length)
throw new PluginException(new BadStateException("Invalid state abbreviation: "
+ state));
double total = (prices[itemNo % prices.length] + itemNo / prices.length)
* quantity * (1 + stateTax[i].getTax());
return new Double(total);
}
}
class StateTax {
String abbrev;
double tax;
public boolean equals(String abbrev) {
return this.abbrev.equalsIgnoreCase(abbrev);
}
public double getTax() {
return tax;
}
public StateTax(String abbrev, double tax) {
this.abbrev = abbrev;
this.tax = tax;
}
}
To define a plug-in field, implement the com.bea.wlpi.common.plugin.PluginField interface. The following table describes the PluginField interface methods that you must implement.
The following code listing is an excerpt from the plug-in sample that shows how to define a run-time component class for a message type. The plug-in field processes a single message type containing data associated with a customer order. The data is in String format, and the individual data elements are separated by semicolons. The plug-in field expects the external event data to be provided as a string buffer containing values that are delimited by semicolons. In the execute() method, the class performs some simple validation of the event data, and returns the String object for the requested field name. This excerpt is taken from the OrderField.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Listing 4-22 Defining the Run-Time Component Class for a Message Type The ORDER_FIELDS value is defined within the SamplePluginConstants.java class file as follows: The figure Plug-In Fields Displayed in an Expression Builder Dialog Box shows the field elements populated within the Expression Builder dialog box. For more information about the plug-in sample, see BPM Plug-In Sample. Defining the Run-Time Component Class for a Start Node To define the run-time component class for a Start node, implement the com.bea.wlpi.server.plugin.PluginStart2 interface. The following table describes the PluginStart2 interface method that you must implement. Note: The PluginStart2 interface inherits methods from the com.bea.wlpi.server.plugin.PluginTemplateNode interface. For more information, see PluginTemplateNode Interface.
package com.bea.wlpi.tour.po.plugin;
import com.bea.wlpi.common.plugin.PluginException;
import com.bea.wlpi.common.plugin.PluginField;
import com.bea.wlpi.evaluator.EvaluationContext;
import com.bea.wlpi.server.eventprocessor.EventData;
import java.util.StringTokenizer;
/*
* This sample field type expects a string buffer with semicolon delimited
* field values. The fields are in a fixed order.
*/
public final class OrderField implements PluginField {
private String docType;
private String name;
public void init(String name, String eventDescriptor)
throws PluginException {
this.name = name;
docType = eventDescriptor;
}
public void setQualifier(PluginField qualifier) throws PluginException {
System.out.println("OrderField.setQualifier(" + qualifier + ')');
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"Qualifiers are not supported");
}
public Object evaluate(EvaluationContext context) throws PluginException {
// Get the event data and check that it is a String object.
EventData eventData = context.getEventData();
if (eventData == null)
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"The event data is null.");
docType = eventData.getEventDescriptor();
if (!docType.equals(SamplePluginConstants.START_ORDER_EVENT))
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"The event descriptor is invalid.");
Object object = eventData.getContent();
if (!(object instanceof String))
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"The event data is invalid.");
// Check to make sure the field name is valid
int i;
for (i = 0; i < SamplePluginConstants.ORDER_FIELDS.length; i++) {
if (SamplePluginConstants.ORDER_FIELDS[i].equals(name))
break;
}
// Was the field name found in the list of valid field names?
if (i == SamplePluginConstants.ORDER_FIELDS.length)
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"The field name " + name
+ " is invalid.");
String data = (String)object;
StringTokenizer st = new StringTokenizer(data, ";");
String token = null;
while (st.hasMoreTokens() && i >= 0) {
token = st.nextToken();
i--;
}
// Did the data ran out of fields prior to finding the one required?
if (i >= 0) {
throw new PluginException(SamplePluginConstants.PLUGIN_NAME,
"The event data is invalid.");
}
String value = token;
System.out.println("OrderField: name = " + name + ", value = " + value);
// Return the text value.
return value;
}
}final static String[] ORDER_FIELDS = {
"CustomerName", "CustomerID", "OrderStatus", "OrderID",
"CustomerEmail", "ItemName", "ItemID", "ItemQuantity",
"CustomerState"
};
The following code listing is an excerpt from the plug-in sample that shows how to define the run-time component class for a Start node. This excerpt is taken from the StartNode.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold. Listing 4-23 Defining the Run-Time Component Class for a Start Node Refer to the following related example listings:
package com.bea.wlpi.tour.po.plugin;
import java.io.IOException;
import com.bea.wlpi.server.plugin.PluginStart2;
.
.
.
public class StartNode extends StartObject implements PluginStart2 {
public StartNode() {
}
.
.
.
public void setTrigger(EventContext context, String orgExpr,
boolean orgIsExpr)
throws WorkflowException {
System.out.println("SamplePlugin: StartNode - setTrigger called");
context.postStartWatch(SamplePluginConstants.CONTENTTYPE, eventDesc,
null, null);
}
public void fixup(ExpressionParser parser) {
}
}
For more information about the plug-in sample, see BPM Plug-In Sample.
PluginTemplateNode Interface
The com.bea.wlpi.server.plugin.PluginTemplateNode interface provides methods for activating Done and Start nodes, and compiling their expressions.
The PluginTemplateNode interface is extended by the following interfaces:
The following table describes the PluginTemplateNode interface methods that you must implement as part of the run-time component class when defining a Done or Start node.
For more information about the PluginTemplateNode interface, see the com.bea.wlpi.server.plugin.PluginTemplateNode Javadoc.
Using Plug-In Run-Time Contexts
To define the run-time execution information for the plug-in, you must implement a run-time interface for the plug-in component, as defined in Executing the Plug-In. At run time, the plug-in communicates with the process engine using a process called context passing: the Plug-in Manager obtains an instance of the plug-in component run-time interface and passes the context to it.
The following figure illustrates context passing.
Figure 4-10 Context Passing
Each context interface provides restricted access to the Plug-in Manager functionality, enabling the plug-in to execute and manage its own application logic, and introduce the plug-in instance data into the BPM run-time environment. The following table describes the plug-in run-time context interfaces.
The following section describes the context interfaces in more detail. Action Context The com.bea.wlpi.server.plugin.ActionContextinterface provides the run-time context and services for plug-in actions. This context is passed via the com.bea.wlpi.server.plugin.PluginAction interface execute() method. The following table describes the ActionContext interface methods that you can use to access information about the action context.
Evaluation Context The com.bea.wlpi.evaluator.EvaluationContextinterface provides the run-time evaluation parameters for the elements in an expression. This context is passed via the evaluate() method to the com.bea.wlpi.server.plugin.PluginField interface and the com.bea.wlpi.server.plugin.PluginFunction interface. The following table describes the EvaluationContext interface methods that you can use to access information about the evaluation context.
Event Context The com.bea.wlpi.server.plugin.EventContextinterface provides the run-time context and services to plug-in events. This context is passed via the following methods:
The following table describes the EventContext interface methods that you can use to access information about the event context.
Execution Context The com.bea.wlpi.server.common.ExecutionContextinterface provides the run-time context and services for a running workflow instance. This context is passed via the following methods:
The following table describes the ExecutionContext interface methods that you can use to access information about the action context.
For more information, see the com.bea.wlpi.server.common.ExecutionContextJavadoc. PluginPanelContext The com.bea.wlpi.common.plugin.PluginPanelContextinterface provides the run-time context and services for the design client (for example, the Studio), including:
Note: Not all methods are applicable in all dialog box contexts. If the plug-in invokes a method in an invalid context, a java.lang.UnsupportedOperationException exception is thrown.
You can access the plug-in panel context using the com.bea.wlpi.common.plugin.PluginPanel get and set methods defined in the table PluginPanel Class Methods.
The following table describes the PluginPanelContext interface methods that you can use to access information about the action context.
For more information, see the com.bea.wlpi.server.plugin.PluginPanelContextJavadoc.
Defining the Plug-In Component Value Objects
The final step consists of defining the value object for the plug-in component to further define the component data. To define the plug-in component value object, use the associated constructor. Each of the plug-in value objects described in the table Plug-In Value Objects, provides one or more constructors for creating object data. The constructors for creating value objects are described in Plug-In Value Object Summary.
You must pass the plug-in value objects for each of the plug-in components when defining the com.bea.wlpi.common.plugin.PluginCapabilitiesInfo object, as described in the getPluginCapabilities() method description, in the table Remote Interface Plug-In Information Methods.
The following code listing is an excerpt from the plug-in sample that shows how to implement the getPluginCapabilitiesInfo() method. This excerpt is taken from the SamplePluginBean.java file in the SAMPLES_HOME/integration/samples/bpm_api/plugin/src/com/bea/wlpi/tour/po/plugin directory. Notable lines of code are shown in bold.
Listing 4-24 Implementing the getPluginCapabilitiesInfo() Method
public PluginCapabilitiesInfo getPluginCapabilitiesInfo(Locale lc,
CategoryInfo[] info) {
PluginInfo pi;
FieldInfo orderFieldInfo;
FieldInfo confirmFieldInfo;
FieldInfo[] fieldInfo;
FunctionInfo fi;
FunctionInfo[] functionInfo;
StartInfo si;
StartInfo[] startInfo;
EventInfo ei;
EventInfo[] eventInfo;
SampleBundle bundle = new SampleBundle(lc);
log("getPluginCapabilities called");
pi = createPluginInfo(lc);
orderFieldInfo =
new FieldInfo(SamplePluginConstants.PLUGIN_NAME, 3,
bundle.getString("orderFieldName"),
bundle.getString("orderFieldDesc"),
SamplePluginConstants.ORDER_FIELD_CLASSES, false);
confirmFieldInfo =
new FieldInfo(SamplePluginConstants.PLUGIN_NAME, 4,
bundle.getString("confirmFieldName"),
bundle.getString("confirmFieldDesc"),
SamplePluginConstants.CONFIRM_FIELD_CLASSES, false);
fieldInfo = new FieldInfo[]{ orderFieldInfo, confirmFieldInfo };
ei = new EventInfo(SamplePluginConstants.PLUGIN_NAME, 6,
bundle.getString("confirmOrderName"),
bundle.getString("confirmOrderDesc"), ICON_BYTE_ARRAY,
SamplePluginConstants.EVENT_CLASSES,
confirmFieldInfo);
eventInfo = new EventInfo[]{ ei };
fi = new FunctionInfo(SamplePluginConstants.PLUGIN_NAME, 7,
bundle.getString("calcTotalName"),
bundle.getString("calcTotalDesc"),
bundle.getString("calcTotalHint"),
SamplePluginConstants.FUNCTION_CLASSES, 3, 3);
functionInfo = new FunctionInfo[]{ fi };
si = new StartInfo(SamplePluginConstants.PLUGIN_NAME, 5,
bundle.getString("startOrderName"),
bundle.getString("startOrderDesc"), ICICON_BYTE_ARRAYON,
SamplePluginConstants.START_CLASSES, orderFieldInfo);
startInfo = new StartInfo[]{ si };
PluginCapabilitiesInfo pci = new PluginCapabilitiesInfo(pi,
getCategoryInfo(bundle), eventInfo,
fieldInfo, functionInfo, startInfo,
null, null, null, null, null);
return pci;
}
![]() |
![]() |
![]() |
![]() |
||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |