Interface IPluginActionNodeHandler<TData extends BaseActionProps>
-
- Type Parameters:
TData
- Type of the node's properties model, which must extendBaseActionProps
. The properties themselves are stored as JSON and serialized to / deserialized from this type automatically. You should make sure this type can be serialized / deserialized viaJSON
. This means you should only basic field types such as number, booleans, or strings, or nested types. Furthermore, If you wish, you can also use the typeJSONObject
to skip serialization / deserialization and work with the raw JSON data.
- All Superinterfaces:
IBaseActionClientHandlerNode<TData>
,IBaseActionNode<TData>
,IBeanValidatingElement<TData,WorkflowNode>
,IBeanValidatingNode<TData>
,ICustomParametersUpdateable
,IElementHandler<TData,WorkflowNode>
,IExecutingLikeActionNode<TData>
,IExecutionResultDescriptor
,IFCPlugin
,IHierarchyValidatingNode<TData>
,INamedUiElement
,INameProviding
,INodeHandler<TData>
,IPluginGenericCustomGUI<IPluginWorkflowNodeBean>
,IPluginWorkflowNode
,IResourceBundleLocator
,ISingleBaseActionNodePrototype<TData>
,ISingleElementPrototype<TData,WorkflowNode>
,ISingleNodePrototype<TData>
,ITransferable
,IWorkflowElementTypeProviding
,IWorkflowNodeFlowAnalyzer<TData>
,IWorkflowNodeTypeProviding
,Serializable
- All Known Implementing Classes:
APluginActionNodeHandler
public interface IPluginActionNodeHandler<TData extends BaseActionProps> extends IPluginWorkflowNode, INodeHandler<TData>, IBaseActionNode<TData>, IExecutingLikeActionNode<TData>, IBaseActionClientHandlerNode<TData>, IBeanValidatingNode<TData>, ISingleBaseActionNodePrototype<TData>
Mixin meant forIPluginWorkflowNode
plugins that only wish to provide a workflow action that executes some business logic. TheINodeHandler
offers many methods that are irrelevant for this use case - this mixin implements most methods with the appropriate defaults.By default, you only need to implement
execute(INodeExecutionParams)
andgetName()
, as well asgetPropertiesViewXhtmlName()
for the UI. Make sure that thegetName()
is unique among all plugins. This name is also used as thegetType()
of the workflow node.The XHTML page with the UI for editing the action's property must be placed in the directory
getPropertiesViewXhtmlPath()
, with the file namegetPropertiesViewXhtmlName()
. You can also add properties files ingetResourceBundlePath()
with localized messages for the UI.Assume the
getType()
isMyActionPlugin
. Then, if you do not override the defaults:- For each language you want to support, add a properties file in
/src/main/resources/WEB-INF/properties/i18n_LOCALECODE.properties
. TheLOCALECODE
isen
for English,de
for German,fr
for French etc. These properties are then available in the XHTML page via the variablemsg
, seeIElementHandler.getPropertiesViewXhtml()
- Add an entry in the properties file for the keys
MyActionPlugin.name
,MyActionPlugin.desc
,MyActionPlugin.label
to customize the name of the plugin, the description of the plugin, and the name of the workflow action.
You can also override most methods of this mixin to customize the action plugin. The following lists a few common use cases:
- To use a localized name or description
- Add an entry to your
getResourceBundle(Locale)
. For the name of the plugin as it appears in the backend plugin configuration menu, usegetI18nKeyDisplayName()
. For the description that also appears in the backend plugin configuration menu, usegetI18nKeyDescription()
. For the label of the action as it appears in the workflow designer, usegetI18nKeyActionLabel()
. - To update the properties model for new versions of the plugin
- First make sure the
MANIFEST.MF
of your plugin contains the appropriate version information, seegetVersion()
. Then, overrideICustomParametersUpdateable.updateCustomParams(de.xima.fc.interfaces.IUpdateCustomParametersParams)
. If you are using the SemVer (semantic version) format (i.e. your version looks likex.y.z
), you may want to use the default methods provided by the mixinISemverUpdating
. - To return a value form the exec method and have it displayed in the workflow designer
- Override
getSuccessValueDescriptor(IValueDescriptorFactory)
(which defines which values the exec method may return, and also contain a human-readable description for each) and adjust the return value ofexecute(INodeExecutionParams)
accordingly. - To provide pre-configured actions to the drawer panel to the left of the workflow designer
- Override
INodeHandler.getNodePrototypes(de.xima.fc.interfaces.workflow.params.IGetNodePrototypesParams)
, optionally adding the list of prototypes (which contains just one item) returned by the super method implementation. - To display the action in a different category in the workflow designer
- Override
ISingleElementPrototype.getSubCategory(IGetElementPrototypesParams)
- To use a custom UI
- Create an XHTML page in
getPropertiesViewXhtmlPath()
; and overridegetPropertiesViewXhtmlName()
with the name of the XHTML page. For example, if you name the XHTML pagemyCustomUi
and do not override the XHTML path, add the file/src/main/resources/WEB-INF/ui/myCustomUi.xhtml
. If you need a custom bean as a controller, also overridegetMainPluginBeanClass()
. SeeIElementHandler.getPropertiesViewXhtml()
for more details on the XHTML page. - To use more than one bean
- Override
getUnmanagedBeans()
, but make sure to includegetMainPluginBeanClass()
. The additional beans can be used in XHTML pages, or referenced viaInject
. - To customize the serialization / deserialization process of the properties model
- Use the
JSONField
annotation on the fields of your properties model class, and/or overrideIElementHandler.getFastJsonConverter()
Examples
A simple skeletal implementation for an action that sends an HTTP post request might look like as follows. Note that you replace
APluginActionNodeHandler
with this interfaceIPluginActionNodeHandler
if you need a custom super class (you only need to implement the gettergetPluginInitializeData()
).package com.example; import java.net.MalformedURLException; import java.net.URL; import de.xima.fc.exceptions.AbstractAbruptCompletionException; import de.xima.fc.interfaces.workflow.execution.INormalCompletionResult; import de.xima.fc.interfaces.workflow.params.INodeExecutionParams; import de.xima.fc.plugin.escalation.MyPostRequestPlugin.EMyPostRequestError; import de.xima.fc.plugin.escalation.MyPostRequestPlugin2.MyPostRequestProps; import de.xima.fc.workflow.mixin.APluginActionNodeHandler; import de.xima.fc.workflow.taglib.model.BaseActionProps; @SuppressWarnings("serial") public class MyPostRequestPlugin extends APluginActionNodeHandler<MyPostRequestProps> { public static class MyPostRequestProps extends BaseActionProps { private String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } public Class<EMyPostRequestError> getErrorCodeClass() { return EMyPostRequestError.class; } @Override public String getName() { return "My Awesome Post Plugin"; } @Override public INormalCompletionResult execute(INodeExecutionParams<MyPostRequestProps params) throws AbstractAbruptCompletionException { try { URL url = new URL(params.getData().getUrl()); // todo: implement sending an HTTP post request // ... } catch (MalformedURLException e) { // Do not catch unexpected "Exception" - this is handled by the system. // Only catch exceptions you anticipate may occur. throw params.throwingException().cause(e).build(); } return params.normalResult().build(); } }
A more advanced version with custom return values for the success and error case might look like this:
package com.example; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import org.apache.commons.lang3.tuple.Pair; import de.xima.fc.exceptions.AbstractAbruptCompletionException; import de.xima.fc.interfaces.workflow.execution.INormalCompletionResult; import de.xima.fc.interfaces.workflow.params.INodeExecutionParams; import de.xima.fc.interfaces.workflow.value.IRecordValueDescriptor; import de.xima.fc.interfaces.workflow.value.IUnionValueDescriptor; import de.xima.fc.interfaces.workflow.value.IValueBuilder; import de.xima.fc.interfaces.workflow.value.IValueDescriptorFactory; import de.xima.fc.plugin.escalation.MyPostRequestPlugin.EMyPostRequestError; import de.xima.fc.plugin.escalation.MyPostRequestPlugin.MyPostRequestProps; import de.xima.fc.workflow.mixin.APluginActionNodeHandler; import de.xima.fc.workflow.taglib.model.BaseActionProps; @SuppressWarnings("serial") public class MyPostRequestPlugin extends APluginActionNodeHandler<MyPostRequestProps> { public static enum EMyPostRequestError { MALFORMED_URL, } public static class MyPostRequestProps extends BaseActionProps { private String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } @Override public String getName() { return "My New Action Plugin"; } @Override public INormalCompletionResult execute(INodeExecutionParams<MyPostRequestProps> params) throws AbstractAbruptCompletionException { MyPostRequestProps props = params.getData(); try { // do something awesome Pair<Integer, String> result = sendPostRequest(props.getUrl()); return params.normalResult().success(f -> f.asRecord() // .property("responseCode", result.getLeft()) // .property("responseMessage", result.getRight())) // .build(); } catch (MalformedURLException e) { throw params.throwingException().error(EMyPostRequestError.MALFORMED_URL.name(), Map.class, b -> b.asRecord() // .property("message", e.getMessage()) // .property("invalidUrl", props.getUrl()) // .build() // ).build(); } // Do not catch unexpected "Exception" - this is handled by the system. // Only catch exceptions you anticipate may occur. } private Pair<Integer, String> sendPostRequest(String urlString) throws MalformedURLException { URL url = new URL(urlString); // todo: implement sending an HTTP post request return Pair.of(404, "Not Found"); } public Class<EMyPostRequestError> getErrorCodeClass() { return EMyPostRequestError.class; } @Override public IUnionValueDescriptor<String> getErrorValueDescriptor(IValueDescriptorFactory factory) { return factory.unionStringBuilder() // // When GENERAL error occurs, a string with the error message is returned .addAndUseAsDefault(EMyPostRequestError.GENERAL.name(), f -> f.string()) // // When the malformed URL error occurs, an JSON object with two properties is returned .add(EMyPostRequestError.MALFORMED_URL.name(), f -> f.recordBuilder() // .requiredProperty("message", v -> v.string()) // .requiredProperty("invalidUrl", v -> v.string()) // .build()) // .build(); } @Override public IRecordValueDescriptor getSuccessValueDescriptor(IValueDescriptorFactory factory) { return factory.recordBuilder() // .requiredProperty("responseCode", f -> f.integer(200)) // .requiredProperty("responseMessage", f -> f.string()) // .build(); } }
- Since:
- 7.0.0
- Author:
- XIMA MEDIA GmbH
-
-
Field Summary
-
Fields inherited from interface de.xima.fc.interfaces.workflow.elements.IElementHandler
CURRENT_HANDLER_VERSION
-
Fields inherited from interface de.xima.fc.plugin.interfaces.IFCPlugin
CONFIG_FILENAME
-
Fields inherited from interface de.xima.fc.interfaces.INamedUiElement
ATTR_DISPLAY_NAME
-
Fields inherited from interface de.xima.fc.entities.interfaces.INameProviding
ATTR_NAME, COL_NAME
-
-
Method Summary
All Methods Instance Methods Abstract Methods Default Methods Modifier and Type Method Description INormalCompletionResult
execute(INodeExecutionParams<TData> params)
Executes the business logic of this action plugin, and returns the values made available by this action.default String
extractDescription(TData data)
Retrieves the name that will be stored asAWorkflowElement.getDescription()
.default String
extractName(TData data)
Retrieves the name that will be stored asAWorkflowElement.getName()
.default IValueDescriptor<?,? extends IValueBuilder<?>>
getAlwaysValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns a void value descriptor.default Class<? extends TData>
getDataModelClass()
This default implementation attempts to read the type of theTData
parameter via reflection.default String
getDescription(Locale locale)
The default implementation returns the localized value of thegetI18nKeyDescription()
in thegetResourceBundle(Locale)
.default String
getDisplayName(Locale locale)
The default implementation returns the localized value of thegetI18nKeyDisplayName()
in thegetResourceBundle(Locale)
.default Class<? extends Enum<?>>
getErrorCodeClass()
Returns the type of the enumeration that defines the error types that may occur during the execution of a node.default IUnionValueDescriptor<String>
getErrorValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns the error codes from thegetSoftErrorCodeClass()
, if any.default String
getI18nKeyActionLabel()
default String
getI18nKeyActionSearchText()
default String
getI18nKeyActionSubLabel()
default String
getI18nKeyActionTitle()
default String
getI18nKeyDescription()
default String
getI18nKeyDisplayName()
default IElementCategory
getMainCategory(IGetElementPrototypesParams params)
default Class<? extends INodePropertyPluginBean<TData>>
getMainPluginBeanClass()
String
getName()
Getter for the name of this plugin.default INodeHandler<TData>
getNodeHandler()
IPluginInitializeData
getPluginInitializeData()
default Class<? extends INodePropertiesBean<TData>>
getPropertiesBeanClass()
Returns the class of the bean that should be used when editing the properties of a workflow element.default URL
getPropertiesViewXhtml()
This default implementation returns the XHTML page located atgetPropertiesViewXhtmlPath()
/getPropertiesViewXhtmlName()
.String
getPropertiesViewXhtmlName()
default String
getPropertiesViewXhtmlPath()
default IGuiIcon
getPrototypeIcon(IGetElementPrototypesParams params)
This default implementation returns an icon resembling a jigsaw puzzle piece, which is the default icon for an action plugin.default String
getPrototypeLabel(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionLabel()
in thegetResourceBundle(Locale)
.default String
getPrototypeSearchText(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionSearchText()
in thegetResourceBundle(Locale)
.default String
getPrototypeSubLabel(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionSubLabel()
in thegetResourceBundle(Locale)
.default String
getPrototypeTitle(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionTitle()
in thegetResourceBundle(Locale)
.default ResourceBundle
getResourceBundle(Locale locale)
This default implementation attempts to read the resource bundle from thegetResourceBundlePath()
.default String
getResourceBundlePath()
default Class<? extends Enum<?>>
getSoftErrorCodeClass()
Returns the type of the enumeration that defines thesoft error
types that may occur during the execution of a node.default IUnionValueDescriptor<String>
getSoftErrorValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns the error codes from thegetSoftErrorCodeClass()
, if any.default IValueDescriptor<?,? extends IValueBuilder<?>>
getSuccessValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns a void value descriptor.default String
getType()
This default implementation simply returns thegetName()
of the plugin as the type.default Iterable<Class<? extends IPluginWorkflowNodeBean>>
getUnmanagedBeans()
This must return a list of backing bean classes that control the user interface and are required by theXHTML Facelet view
.default String
getVersion()
Instead of the formcycle version, this default implementation returns the current version of this plugin.-
Methods inherited from interface de.xima.fc.workflow.mixin.IBaseActionClientHandlerNode
getActionViewType, getCascadingStyleSheet, getJavaScript, isAlwaysCompletesAbruptly, isSelectable
-
Methods inherited from interface de.xima.fc.workflow.mixin.IBaseActionNode
isValidChildCount, isValidChildType, isValidParentType, validateLocal
-
Methods inherited from interface de.xima.fc.interfaces.workflow.mixin.IBeanValidatingElement
getValidationGroups
-
Methods inherited from interface de.xima.fc.interfaces.workflow.ICustomParametersUpdateable
updateCustomParams
-
Methods inherited from interface de.xima.fc.interfaces.workflow.elements.IElementHandler
extractSearchTerms, getCascadingStyleSheet, getDisplayLabel, getElementSummaryModel, getElementSummaryXhtml, getFastJsonConverter, getFilterCriteriaForEntities, getHelpPageLocation, getJavaScript, isAvailable, isHasUserVisibleName, readEntityReferences, readPlaceholders, validateGlobal, writeEntityReferences, writePlaceholders
-
Methods inherited from interface de.xima.fc.interfaces.workflow.mixin.IExecutingLikeActionNode
createFlowGraph
-
Methods inherited from interface de.xima.fc.interfaces.workflow.execution.IExecutionResultDescriptor
getFileValueDescriptor
-
Methods inherited from interface de.xima.fc.plugin.interfaces.IFCPlugin
getDescription, initialize, initPlugin, install, shutdown, shutdown, uninstall, validateConfigurationData
-
Methods inherited from interface de.xima.fc.interfaces.workflow.nodes.INodeHandler
getLocalizedTypeName, getRelatedNodeTypes, isCreateProtocolEntryAfterExecution, isCreateProtocolEntryAfterExecution, isReplacePlaceholderBeforeExecution
-
Methods inherited from interface de.xima.fc.plugin.interfaces.workflow.IPluginWorkflowNode
getXhtmlView
-
Methods inherited from interface de.xima.fc.workflow.mixin.ISingleBaseActionNodePrototype
getPrototypeModelData, getThemeColor
-
Methods inherited from interface de.xima.fc.interfaces.workflow.mixin.ISingleElementPrototype
getPrototypeSortKey, getPrototypeTags, getSubCategory
-
Methods inherited from interface de.xima.fc.interfaces.workflow.mixin.ISingleNodePrototype
getNodePrototypes, getPrototypeElement
-
-
-
-
Method Detail
-
execute
INormalCompletionResult execute(INodeExecutionParams<TData> params) throws AbstractAbruptCompletionException
Executes the business logic of this action plugin, and returns the values made available by this action.In case the action was executed successfully, you need to return a value that conforms to the data type described by
getSuccessValueDescriptor(IValueDescriptorFactory)
. See that method for an example on how to use a custom result type. If you did not override that method, no value is returned by this action, and you can simply use:return params.normalResult().build();
When the action could not be completed normally, you need to throw an appropriate exception indicating the reason for why the action could not be completed. Most commonly this happens when the business logic threw an exception. In this case you should use the provided
INodeExecutionParams.throwingException()
to build theNodeThrewException
, and throw it:throw params.throwingResult().cause(exceptionThatWasThrown).build();
If you did overridegetErrorValueDescriptor(IValueDescriptorFactory)
, you should also include the error code and error details viaINodeThrewExceptionBuilder.error(String, Object)
orINodeThrewExceptionBuilder.error(String, Class, IValueCreator)
.- Specified by:
execute
in interfaceINodeHandler<TData extends BaseActionProps>
- Parameters:
params
- Data this action plugin may use. Most importantly, you will needINodeExecutionParams.getData()
, which contains the configuration as set by the user in the workflow designer.- Returns:
- The values returned by this action, as specified by
getSuccessValueDescriptor(IValueDescriptorFactory)
}. Any value not set explicitly will use its default value from the success vale descriptor. - Throws:
AbstractAbruptCompletionException
- When the action could not be completed normally. Use the providedINodeExecutionParams.throwingException()
andINodeExecutionParams.returningException()
to create an instance of the exception.NodeThrewException
- When this exception is thrown, execution of the workflow task is aborted, unless an exception handler was defined in the workflow configuration.NodeReturnedException
- When this exception is thrown, the action is judged to have been executed successfully, and execution of the workflow task is stopped.RuntimeException
- A runtime exception may be thrown to indicate an unforeseen error, such as general database errors. For all errors you expect to happen, you should throw an appropriateNodeThrewException
with the details of the exception. When a runtime exception is thrown, it is wrapped in aNodeThrewException
and treated as if that exception had been thrown.
-
extractDescription
default String extractDescription(TData data)
Description copied from interface:IElementHandler
Retrieves the name that will be stored asAWorkflowElement.getDescription()
. For example, actions may let the user enter a description for the action, which would be returned by this method. A condition node may an explanation of the test condition as the description.The default implementation checks whether the
IElementHandler.getDataModelClass()
implementsIDescriptionProviding
and if it does, returnsIDescriptionProviding.getDescription()
. Otherwise returns an empty string.- Specified by:
extractDescription
in interfaceIElementHandler<TData extends BaseActionProps,WorkflowNode>
- Parameters:
data
- The data of the workflow element for which to retrieve the description.- Returns:
- The description of the workflow element with the given data.
-
extractName
default String extractName(TData data)
Description copied from interface:IElementHandler
Retrieves the name that will be stored asAWorkflowElement.getName()
. For example, actions may let the user enter the name of the action, which would be returned by this method. A condition node may use a summary of the test condition as the name. A button trigger event may use the name of the button.The default implementation checks whether the
IElementHandler.getDataModelClass()
implementsINameProviding
and if it does, returnsINameProviding.getName()
.- Specified by:
extractName
in interfaceIElementHandler<TData extends BaseActionProps,WorkflowNode>
- Parameters:
data
- The data of the workflow element for which to retrieve the name.- Returns:
- The name of the workflow element with the given data.
-
getAlwaysValueDescriptor
default IValueDescriptor<?,? extends IValueBuilder<?>> getAlwaysValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns a void value descriptor. This is appropriate when this plugin does not need to return any values. If you wish to return values (and make them available to other action via variables / placeholders), override this method. If you do, make sure you also modifyexecute(INodeExecutionParams)
and supply the appropriate values upon execution.- Specified by:
getAlwaysValueDescriptor
in interfaceIExecutionResultDescriptor
- Parameters:
factory
- Factory that may be used for creating the descriptor. You may also useValueDescriptorFactory.getInstance()
if you wish to cache the descriptor in a static or instance field.- Returns:
- The value descriptor for that data that is made available to the workflow when the node is executed, regardless of whether is succeeded or failed.
- See Also:
IExecutionResultDescriptor.getAlwaysValueDescriptor(IValueDescriptorFactory)
-
getDataModelClass
default Class<? extends TData> getDataModelClass()
This default implementation attempts to read the type of theTData
parameter via reflection. If that does not work, or you need to optimize, override this method and return the type directly.- Specified by:
getDataModelClass
in interfaceIElementHandler<TData extends BaseActionProps,WorkflowNode>
- Returns:
- The class corresponding to the type parameter
TData
. - See Also:
IElementHandler.getDataModelClass()
-
getDescription
default String getDescription(Locale locale)
The default implementation returns the localized value of thegetI18nKeyDescription()
in thegetResourceBundle(Locale)
. When no value exists for that key, returns an empty string (= no description).- Specified by:
getDescription
in interfaceIFCPlugin
- Parameters:
locale
- The locale for which to get the description.- Returns:
- An HTML markup string with the description for this plugin, or
null
if no description is available. - See Also:
IFCPlugin.getDescription()
-
getDisplayName
default String getDisplayName(Locale locale)
The default implementation returns the localized value of thegetI18nKeyDisplayName()
in thegetResourceBundle(Locale)
. When no value exists for that key, returns thegetName()
of this plugin.- Specified by:
getDisplayName
in interfaceIFCPlugin
- Specified by:
getDisplayName
in interfaceINamedUiElement
- Returns:
- Wert, der das entsprechende Objekt an Oberfläche repräsentiert (wird i.A. zur Laufzeit ermittelt).
- See Also:
IFCPlugin.getDisplayName(Locale)
-
getErrorCodeClass
default Class<? extends Enum<?>> getErrorCodeClass()
Returns the type of the enumeration that defines the error types that may occur during the execution of a node. The default returnsnull
, which corresponds to no custom errors. In that case, if the plugin throws an exception, it is treated as a general exception.- Returns:
- The enumeration class that defines the possible error codes.
-
getSoftErrorCodeClass
default Class<? extends Enum<?>> getSoftErrorCodeClass()
Returns the type of the enumeration that defines thesoft error
types that may occur during the execution of a node. The default returnsnull
, which corresponds to no custom soft errors. In that case the plugin cannot add any soft errors.- Returns:
- The enumeration class that defines the possible soft error codes.
-
getErrorValueDescriptor
default IUnionValueDescriptor<String> getErrorValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns the error codes from thegetSoftErrorCodeClass()
, if any. No error data is made available for the error codes. When the action can have errors with error data, override this method and useIValueDescriptorFactory.unionStringBuilder()
to add the errors.public IUnionValueDescriptor<String> getSoftErrorValueDescriptor(IValueDescriptorFactory f) { return f.recordBuilder() // .add("FILE_NOT_FOUND", f.recordBuilder().requiredProperty("file", f.string("")).build()) // .add("NETWORK_ERROR", f.recordBuilder().requiredProperty("url", f.string("")).build()) // .build();
Note that it is recommended that you keep the available error codes in an enum, so you can reuse them later.In your
execute(INodeExecutionParams)
method, you can then add a soft error when necessary while building an error result:public INormalCompletionResult execute(INodeExecutionParams<TData> params) throws AbstractAbruptCompletionException { try { // Run business logic... return params.normalResult().success(result).build(); } catch (final IOException e) { // Add the soft error final var errorData = new HashMap<String, Object>(); errorData.put("file", fileName); throw throw params.throwingException().error("FILE_NOT_FOUND", errorData).cause(e).build(); } }
Instead of the factory passed in to this method, you may also use
ValueDescriptorFactory.getInstance()
if you wish to cache the descriptor in a static or instance field. *- Specified by:
getErrorValueDescriptor
in interfaceIExecutionResultDescriptor
- Parameters:
factory
- Factory that may be used for creating the descriptor. You may also useValueDescriptorFactory.getInstance()
if you wish to cache the descriptor in a static or instance field.- Returns:
- The value descriptor for the data that is made available to the workflow when the execution of the node failed (such as by throwing an exception).
- See Also:
IExecutionResultDescriptor.getErrorValueDescriptor(IValueDescriptorFactory)
-
getI18nKeyActionLabel
default String getI18nKeyActionLabel()
- Returns:
- The i18n key for the name of the action, as shown in the workflow designer. Defaults to the
getI18nKeyDisplayName()
.
-
getI18nKeyActionSearchText
default String getI18nKeyActionSearchText()
- Returns:
- The i18n key for the search text of the action, not shown in the UI but used for filtering. Defaults to
"
.getName()
.searchtext"
-
getI18nKeyActionSubLabel
default String getI18nKeyActionSubLabel()
- Returns:
- The i18n key for the sub label of the action, as shown in the workflow designer below the name of the item. Defaults to
"
.getName()
.sublabel"
-
getI18nKeyActionTitle
default String getI18nKeyActionTitle()
- Returns:
- The i18n key for the title of the action, as shown in the workflow designer when hovering over the item with the mouse. Defaults to
"
.getName()
.title"
-
getI18nKeyDescription
default String getI18nKeyDescription()
- Returns:
- The i18n key for the description of this plugin. Defaults to
"
.getName()
.desc"
-
getI18nKeyDisplayName
default String getI18nKeyDisplayName()
- Returns:
- The i18n key for the display name of this plugin, as shown in the plugin configuration backend menu. Defaults to
"
.getName()
.name"
-
getMainCategory
default IElementCategory getMainCategory(IGetElementPrototypesParams params)
- Specified by:
getMainCategory
in interfaceISingleElementPrototype<TData extends BaseActionProps,WorkflowNode>
- Parameters:
params
- Parameters with the current client, locale, entity context etc.- Returns:
IElementCategory
element's main category, which is used for grouping the elements.
-
getMainPluginBeanClass
default Class<? extends INodePropertyPluginBean<TData>> getMainPluginBeanClass()
- Returns:
- The class of the bean that should be made available in the
getPropertiesViewXhtml()
page. When this returnsnull
, no bean is made available This is usually sufficient for most simple use cases, seeIElementHandler.getPropertiesViewXhtml()
for further details.
-
getName
String getName()
Description copied from interface:IFCPlugin
Getter for the name of this plugin. This name may appear on the user interface.- Specified by:
getName
in interfaceIFCPlugin
- Specified by:
getName
in interfaceINameProviding
- Returns:
String
The name of this plugin.
-
getNodeHandler
default INodeHandler<TData> getNodeHandler()
- Specified by:
getNodeHandler
in interfaceIPluginWorkflowNode
- Returns:
- The node handler that implements all the logic required by the workflow node. This lets you customize all features available to built-in workflow nodes.
-
getPluginInitializeData
IPluginInitializeData getPluginInitializeData()
- Returns:
- The
IPluginInitializeData
, as they were passed toIFCPlugin.initialize(IPluginInitializeData)
. Implementation should usually just store the data in aprivate volatile
field and return it in this method.
-
getPropertiesBeanClass
default Class<? extends INodePropertiesBean<TData>> getPropertiesBeanClass()
Description copied from interface:IElementHandler
Returns the class of the bean that should be used when editing the properties of a workflow element. May benull
if you do not required any bean or custom logic. When you only wish to access the properties of yourIElementHandler.getDataModelClass()
, you do have to use a custom bean - the model is available via the expression language variablemodel
. SeeIElementHandler.getPropertiesViewXhtml()
for further details.The default returns
null
, which uses no extra bean. An extra bean may not be required for simple UIs if you only need to access the properties model of the workflow element - seeIElementHandler.getPropertiesViewXhtml()
.- Specified by:
getPropertiesBeanClass
in interfaceIElementHandler<TData extends BaseActionProps,WorkflowNode>
- Specified by:
getPropertiesBeanClass
in interfaceINodeHandler<TData extends BaseActionProps>
- Returns:
- The class of the bean to use for editing a workflow node's properties.
- See Also:
IElementHandler.getPropertiesViewXhtml()
-
getPropertiesViewXhtml
default URL getPropertiesViewXhtml() throws MalformedURLException
This default implementation returns the XHTML page located atgetPropertiesViewXhtmlPath()
/getPropertiesViewXhtmlName()
.- Specified by:
getPropertiesViewXhtml
in interfaceIElementHandler<TData extends BaseActionProps,WorkflowNode>
- Returns:
- Path to the XHTML view. If the action can be configured, this must not return
null
. If you do returnnull
, it will be treated as an error and an appropriate message is displayed to the user informing them that the properties panel could not be loaded. If the action cannot be configured (i.e. when the action is not selectable), this should returnnull
. - Throws:
MalformedURLException
- This exception is declared for convenience - normally you would usenew URL(String)
with a constant URL string that should not throw. In case an exception is thrown, it is treated the same as if this returnednull
.- See Also:
IElementHandler.getPropertiesViewXhtml()
-
getPropertiesViewXhtmlName
String getPropertiesViewXhtmlName()
- Returns:
- The file name (without the path) to the XHTML page with the custom UI. The file extension
.xhtml
is added automatically if the returned name does not contain it already. - See Also:
getPropertiesViewXhtmlPath()
-
getPropertiesViewXhtmlPath
default String getPropertiesViewXhtmlPath()
- Returns:
- The path (without the file name) to the XHTML page with the custom UI. Defaults to
WEB-INF/ui
. That is, you should put the file insrc/main/resources/WEB-INF/ui
. - See Also:
getPropertiesViewXhtmlName()
-
getPrototypeIcon
default IGuiIcon getPrototypeIcon(IGetElementPrototypesParams params)
This default implementation returns an icon resembling a jigsaw puzzle piece, which is the default icon for an action plugin.- Specified by:
getPrototypeIcon
in interfaceISingleElementPrototype<TData extends BaseActionProps,WorkflowNode>
- Parameters:
params
- Parameters with the current client, locale, entity context etc.- Returns:
- The icon for the element prototype, shown in the element drawer panel to the left of the workflow designer.
See
IElementPrototypeDescriptor.getIcon()
. - See Also:
ISingleElementPrototype.getPrototypeIcon(IGetElementPrototypesParams)
-
getPrototypeLabel
default String getPrototypeLabel(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionLabel()
in thegetResourceBundle(Locale)
. If no localized value exists for that key, defaults thegetName()
of this plugin.- Specified by:
getPrototypeLabel
in interfaceISingleElementPrototype<TData extends BaseActionProps,WorkflowNode>
- Parameters:
params
- Parameters with the current client, locale, entity context etc.- Returns:
- The icon for the element prototype, shown in the element drawer panel to the left of the workflow designer.
See
IElementPrototypeDescriptor.getLabel()
. - See Also:
ISingleElementPrototype.getPrototypeLabel(IGetElementPrototypesParams)
-
getPrototypeSearchText
default String getPrototypeSearchText(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionSearchText()
in thegetResourceBundle(Locale)
. If no localized value exists for that key, no title is used.- Specified by:
getPrototypeSearchText
in interfaceISingleElementPrototype<TData extends BaseActionProps,WorkflowNode>
- Parameters:
params
- Parameters with the current client, locale, entity context etc.- Returns:
- The search text for the element prototype, never shown to the user but used for filtering. See
IElementPrototypeDescriptor.getSearchText()
. - See Also:
ISingleElementPrototype.getPrototypeSearchText(IGetElementPrototypesParams)
-
getPrototypeSubLabel
default String getPrototypeSubLabel(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionSubLabel()
in thegetResourceBundle(Locale)
. If no localized value exists for that key, no sub label is used.- Specified by:
getPrototypeSubLabel
in interfaceISingleElementPrototype<TData extends BaseActionProps,WorkflowNode>
- Parameters:
params
- Parameters with the current client, locale, entity context etc.- Returns:
- The sub label for the element prototype, shown in the element drawer panel to the left of the workflow
designer. See
IElementPrototypeDescriptor.getLabel()
. - See Also:
ISingleElementPrototype.getPrototypeSubLabel(IGetElementPrototypesParams)
-
getPrototypeTitle
default String getPrototypeTitle(IGetElementPrototypesParams params)
This default implementation returns the localized value of thegetI18nKeyActionTitle()
in thegetResourceBundle(Locale)
. If no localized value exists for that key, no title is used.- Specified by:
getPrototypeTitle
in interfaceISingleElementPrototype<TData extends BaseActionProps,WorkflowNode>
- Parameters:
params
- Parameters with the current client, locale, entity context etc.- Returns:
- The title for the element prototype, shown in the element drawer panel to the left of the workflow
designer. See
IElementPrototypeDescriptor.getLabel()
. - See Also:
ISingleElementPrototype.getPrototypeTitle(IGetElementPrototypesParams)
-
getResourceBundle
default ResourceBundle getResourceBundle(Locale locale)
This default implementation attempts to read the resource bundle from thegetResourceBundlePath()
. In most cases this is fine and does not have to be overridden, although you may want to override thegetResourceBundlePath()
.- Specified by:
getResourceBundle
in interfaceIElementHandler<TData extends BaseActionProps,WorkflowNode>
- Specified by:
getResourceBundle
in interfaceIResourceBundleLocator
- Parameters:
locale
- A locale, for which a resource bundle shall be retrieved. Must not benull
.- Returns:
- The resource bundle to use for localized messages.
- See Also:
IElementHandler.getResourceBundle(Locale)
-
getResourceBundlePath
default String getResourceBundlePath()
- Returns:
- The path to the resource bundle with the localized message for this plugin. Defaults to
WEB-INF/properties/i18n
. That is, you should create the properties filessrc/main/resources/WEB-INF/properties/i18n_en.properties
(for English),src/main/resources/WEB-INF/properties/i18n_de.properties
(for German), etc.
-
getSoftErrorValueDescriptor
default IUnionValueDescriptor<String> getSoftErrorValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns the error codes from thegetSoftErrorCodeClass()
, if any. No error data is made available for the error codes. When the action can have soft errors with error data, override this method and useIValueDescriptorFactory.unionStringBuilder()
to add the soft errors.public IUnionValueDescriptor<String> getSoftErrorValueDescriptor(IValueDescriptorFactory f) { return f.recordBuilder() // .add("FILE_NOT_FOUND", f.recordBuilder().requiredProperty("file", f.string("")).build()) // .add("NETWORK_ERROR", f.recordBuilder().requiredProperty("url", f.string("")).build()) // .build();
Note that it is recommended that you keep the avaiable soft error codes in an enum, so you can reuse them later.In your
execute(INodeExecutionParams)
method, you can then add a soft error when necessary, which you can do like this:public INormalCompletionResult execute(INodeExecutionParams<TData> params) throws AbstractAbruptCompletionException { try { // Run business logic... } catch (final IOException e) { // Add the soft error final var errorData = new HashMap<String, Object>(); errorData.put("file", fileName); params.softError("FILE_NOT_FOUND", e, b -> b.value(errorData)) } return params.normalResult().success(result).build(); }
Instead of the factory passed in to this method, you may also use
ValueDescriptorFactory.getInstance()
if you wish to cache the descriptor in a static or instance field. *- Specified by:
getSoftErrorValueDescriptor
in interfaceIExecutionResultDescriptor
- Parameters:
factory
- Factory that may be used for creating the descriptor. You may also useValueDescriptorFactory.getInstance()
if you wish to cache the descriptor in a static or instance field.- Returns:
- The value descriptor for the data that is made available to the workflow when the execution of the node was successful, but contains one or more soft errors.
- See Also:
IExecutionResultDescriptor.getSoftErrorValueDescriptor(IValueDescriptorFactory)
-
getSuccessValueDescriptor
default IValueDescriptor<?,? extends IValueBuilder<?>> getSuccessValueDescriptor(IValueDescriptorFactory factory)
This default implementation returns a void value descriptor. This is appropriate when this plugin does not need to return any values. If you wish to return values (and make them available to other action via variables / placeholders), override this method. If you do, make sure you also modifyexecute(INodeExecutionParams)
and supply the appropriate values upon execution.Recommended best practice is to use a
IRecordValueDescriptor
, with an entry for each value that may be returned. This also allows you to add additional entries later on. For example, to indicate that your action may return a status code (default value0
) and a status message (default value<empty>
), you can use:public IValueDescriptor<?, ? extends IValueBuilder<?>> getSuccessValueDescriptor(IValueDescriptorFactory f) { return f.recordBuilder() // .requiredProperty("statusCode", f.integer(0L)) // .requiredProperty("statusMessage", f.string("")) // .build();
In your
execute(INodeExecutionParams)
method, you then need to supply a value for the status code and message, which you can do like this:public INormalCompletionResult execute(INodeExecutionParams<TData> params) throws AbstractAbruptCompletionException { // Run business logic and get status code and message final Map<String, Object> result = new HashMap<>(); result.put("statusCode", 200); result.put("statusMessage", "OK"); // Create a success result with the data return params.normalResult().success(result).build(); }
Instead of the factory passed in to this method, you may also use
ValueDescriptorFactory.getInstance()
if you wish to cache the descriptor in a static or instance field. *- Specified by:
getSuccessValueDescriptor
in interfaceIExecutionResultDescriptor
- Parameters:
factory
- Factory that may be used for creating the descriptor. Instead of the factory passed in to this method, you may also useValueDescriptorFactory.getInstance()
if you wish to cache the descriptor in a static or instance field.- Returns:
- The value descriptor for that data that is made available to the workflow when the node is executed successfully.
- See Also:
IExecutionResultDescriptor.getSuccessValueDescriptor(IValueDescriptorFactory)
-
getType
default String getType()
This default implementation simply returns thegetName()
of the plugin as the type. Make sure that the name is unique. It is recommended you hardcode the name / type, as any change will result in broken backwards compatibility. In particular we advice against usingClass.getCanonicalName()
etc., as a refactoring would then break your plugin.- Specified by:
getType
in interfaceIWorkflowElementTypeProviding
- Returns:
- The type of the workflow element that determines how the workflow element behaves. Usually there is a registered handler for each type.
-
getUnmanagedBeans
default Iterable<Class<? extends IPluginWorkflowNodeBean>> getUnmanagedBeans()
Description copied from interface:IPluginGenericCustomGUI
This must return a list of backing bean classes that control the user interface and are required by theXHTML Facelet view
. A new instance of the bean will be created automatically when the view is opened. Make sure each bean has got a no-argument constructor or instantiation will fail.Each bean should be annotated with
Named
. If this annotation is not present or no name is specified, the name defaults to the simple name of the bean class, with the first character changed to lower case.Also, each bean needs to be annotated one of the following scopes:
@RequestScoped
,@ViewScoped
,@SessionScoped
, or@ApplicationScoped
. Note that it depends on the type of plugin which scopes are actually supported (most plugins expect@ViewScoped
beans). In case you do not specify a scope, an appropriate scope will be determined automatically.Please note that the beans are fundamentally unmanaged - functionality specific to managed CDI beans may not be supported, depending on the type of plugin. Certain features of CDI managed beans may be supported partially, depending on the type of plugin, but may work slightly differently. This includes, but is not limited to:
- The exact timing at which
PostConstruct
andPreDestroy
are called may differ. - A field marked with
Inject
may not work with all values allowed by the CDI specification, and may not perform certain validation passes such as the check for circular dependencies. Also, no new bean instances will be created when those beans have not yet been created as part of the current page.
- Specified by:
getUnmanagedBeans
in interfaceIPluginGenericCustomGUI<TData extends BaseActionProps>
- Returns:
- A list of unmanaged bean classes required by the Facelet page.
- The exact timing at which
-
getVersion
default String getVersion()
Instead of the formcycle version, this default implementation returns the current version of this plugin. The version is read from theMANIFEST.MF
file in the plugin JAR file. Make sure that the manifest contains an appropriate version entry, e.g.:Implementation-Version = 3.1.4
We recommend that you use version numbers that conform to the format and semantics as laid out by SemVer (semantic version).- Specified by:
getVersion
in interfaceIElementHandler<TData extends BaseActionProps,WorkflowNode>
- Returns:
- The version of this plugin.
- See Also:
IElementHandler.getVersion()
-
-