This section contains a quick overview of conventions and rules that are outlined and discussed in more detail in the remaining sections of this document. Use this checklist whenever developing / reworking pipelets.
The following things, you should do:
Things you should not do:
To ensure synchronization between pipelet descriptor and implementation (i.e. Java source code), the use of tools is required. Manual pipelet descriptor changes should be avoided at all costs. The recommended tool for pipelet modeling and editing is Intershop Studio.
It is recommended to use a consistent naming scheme for pipelets that indicates the purpose of a pipelet based on its name.
The naming conventions outlined below are by no means complete but apply to about 80% of all cases.
The pipelets used most frequently are those managing the life cycle of persistent objects. The following naming scheme is recommended for the following pipelets:
Create<Object>
Update<Object>
Delete<Object>
Get<Object>ByUUID
PersistentObject
). Get<Object>By<Attr>
Get<Object>By<Object>
Get<Object>By<Attr>
pipelet. The only difference is that here another, usually associated, object is used for the lookup.Get<Object>sBy<Attr>
Get<Object>
s By<Object>
Get<Object>sBy<Attr>
pipelet. The only difference is that here, another, usually associated, object is used for the lookup.Beside standard life cycle and lookup pipelets, pipelets are required that do some actual processing on the business objects of the pipeline dictionary. The naming scheme for these pipelets depends on the type of processing done by the pipelet.
Below are some examples and recommendations that might be used as guidance:
Calculate<Object>
Process<Object>
Pipelet groups do not have a real function when it comes to pipelet or pipeline processing. They are purely declarative and are used by the Visual Pipeline Manager for an alternative grouping of the whole pipelet set. The feature is designed to help developers locate all pipelets that do something with certain business objects without looking at their name.
The VPM pipelet grouping only works successfully when all pipelets are categorized within a small but meaningful set of pipelet groups. Too many groups are less helpful than too few groups.
Common
, Misc
or Util
.Note that pipelet group names should start with a capital letter and consist of a single word only.
Pipelet parameter names and types are an essential part of the pipelet API because they basically make up the pipelet signature. Whenever a pipelet name does not allow developers to infer the pipelet's meaning at first glance, the pipelet parameters will. Choosing an appropriate set of pipelet parameters is essential for pipelet reuse.
Pipelet parameter names need to make sense for the pipelet that uses the parameter. When choosing a name, do not focus on the pipeline the pipelet might be used in. Due to the dictionary aliasing feature of Intershop 7, there is no need to synchronize the pipelet parameter names of all pipelets that are used in a single pipeline. This gives more freedom to the developer for choosing semantically meaningful names. Below are some general parameter naming conventions that are mandatory:
usergroup, userGroup
and BASKET
are invalid.DomainID
.As a general rule, pipelet parameter sets should be designed in a way that good interoperability between the different pipelet groups, e.g., life-cycle, lookup, processing, is ensured. There is, for example, no point in having ID attributes in processing pipelets. Instead, processing pipelets should read business object instances from the pipeline dictionary that have to be provided by the lookup pipelets. The benefit is that you do not need to replicate the code required for retrieving the instances of business objects throughout all pipelets.
Although pipelet parameter naming is done with a pipelet focus only, there are parameters that are shared by pipelets and pipelines. To ease development, you should access and store standard objects with standard parameter names.
The following parameter names should be used for standard platform objects:
Domain
User
UserGroup
Permission
When accessing platform parameters, it is always a good idea to take a look at the naming conventions used in the platform. Although the conventions are not as strict as suggested here, they might still provide some guidance.
Like parameter names, parameter types are part of the pipelet's API. Hence, correct and consistent usage of parameter types is important. The following rules apply:
Integer, Double, String, Money, Quantity, BigDecimal
, ...).int, double, string
).In case a pipelet consumes numeric data (e.g. numeric type codes, dates, money values, ...) it must use the appropriate Java object types. A pipelet must not read numeric information as string and convert them internally into the corresponding object type (e.g. by using Integer.valueOf()
). There are two very important reasons for this rule:
Integer.valueOf()
fails as soon as the application supports multiple locales. In such a scenario, users will provide numeric input based on their locale setting (e.g. "20.50" for English and "20,50" for German). Pipelets that use the standard methods conversion will fail with a NumberFormatException
.If numeric data is posted as string content from a template (e.g. an HTTP POST of an update form) it needs to be converted using one of the following formatter utility pipelets before it can be used:
VerifyBoolean
VerifyInteger
VerifyDouble
VerifyDate
VerifyMoney
VerifyQuantity
UpdateCustomAttribute | <IN> Object : ExtensibleObject | <IN> Locale : LocaleInformation | <IN> AttributeName : String | <IN> AttributeType : String | <IN> AttributeValue : String
In this example, the attribute value needs to support string, integer
and double
. The (wrong) pipelet implementation reads those values as string and internally converts them by evaluating a numeric type code (that is also provided as a string).
This is very bad practice, due to the dangerous internal conversion of strings (see the discussion on localization issues above) and the limited reusability of the pipelet. A better API version of this example pipelet would look like this:
UpdateCustomAttribute | <IN> Object : ExtensibleObject | <IN> Locale : LocaleInformation | <IN> AttributeName : String | <IN> AttributeValue : Object
Note that the pipelet does not read a numeric type code any more. Instead, the pipelet reads the attribute value as an object. The implementation will use the instanceof
operation to check for supported types (i.e. String, Integer, Double
) and call the appropriate ExtensibleObject
method. In an HTTP/HTML environment where the values are always posted as strings
, an additional decision node should be used to evaluate the submitted type code in order to decide which conversion utility pipelet should be used. The following simplified pipeline view summarizes this approach.
Note that the type checks in this sample pipeline are just examples. In real pipelines, the type codes are likely read from somewhere else (i.e. from a webform or a form record).
Pipelets are supposed to be reusable across pipelines and even different projects. It is therefore important to design pipelets to be more generic than it might be required in the context of a certain use case. One important feature of generic pipelets is the support for statically configured configuration parameters that are used as fallbacks in case a declared I/O parameter is not available in the pipeline dictionary.
This issue is best discussed with an example. Consider a pipelet that can be used to remove a specified custom attribute for a provided ExtensibleObject
instance.
RemoveCustomAttribute | <IN> Object : ExtensibleObject | <IN> Locale : LocaleInformation |
For the original use case, the pipelet received the name of the attribute to be removed from the pipeline dictionary (i.e., the user selected the attribute to be removed explicitly). However, it is also perfectly possible that the pipeline designer needs to remove a custom attribute independently of the user interaction. Therefore, the attribute name should alternatively be configurable in the pipelet configuration.
RemoveCustomAttribute | <CONFIG> DefaultAttributeName : String | <IN> Object : ExtensibleObject | <IN> Locale : LocaleInformation | <IN> AttributeName : String
The pipelet implementation would select the attribute name to be used such that the pipeline dictionary value always takes precedence:
public void init() throws PipelineInitializationException { cfg_defaultAttributeName = (String)getConfiguration(). ... get("DefaultAttributeName"); ... } public int execute(PipelineDictionary dict) throws PipeletExecutionException { // lookup AttributeName in pipeline dictionary String attributeName = (String)dict.get(IO_ATTRIBUTENAME_NAME); //{{ execute String attrName = attributeName != null ? attributeName : cfg_defaultAttributeName; if(attrName == null) { throw new PipeletExecutionException( ... "Mandatory input parameter 'AttributeName' not available."); } ...
This is a pattern that can be applied to many pipelets. All pipelet input parameters for which a static configuration at the pipeline level does make sense should complement the dictionary input parameters with appropriate 'Default' configuration parameters.
The following specific rules apply:
Pipelets must not make any assumptions about the environment they are used in. To be reusable across different projects, a pipelet must not make any assumptions about the UI that triggers the pipelet's execution. To be reusable in job- or web service-driven implementations, a pipelet must not even assume that there is an HTTP request triggering the pipelet.
It is therefore forbidden for pipelets to directly access HTTP form data stored in the pipeline dictionary. The following pipeline dictionary API calls should not be used:
Iterator createFormKeyIterator() Iterator createFormPrefixedKeyIterator() String getFormValue(String) String getFormValues(String) void removeFormValues(String) void setFormValue(String,String) void setFormValues(String,String)
When implementing pipelines for an HTTP/HTML based application, the following form handling utility pipelets should be used to access the form data and provide it in a controlled way for all other pipelets.
GetFormSelection GetFormRecord CreateWebForm GetWebForm UpdateWebForm ValidateWebForm UpdateClipboard GetClipboard
A consistent handling of errors across different pipelets is another important aspect of our pipelet API. The following basic rules apply:
PipeletExecutionException
in case a required input parameter is not available in the pipeline dictionary.PipelineInitializationException
in case a required configuration parameter is not available.RemoteException, RuntimeExceptions
and Throwable
in their execution body.CreateException, FinderException, RemoveException
and any other custom business exceptions (in case these exceptions are declared at the manager level) by using the error exit (if the pipelet declares one).To decide whether a certain pipelet should declare an error exit at all, refer to the discussion in the pipelet naming scheme section ( #Pipelet Naming).
Even though pipelets often need to indicate detailed error information by storing certain error codes in the pipeline dictionary, this style guide does not provide a naming scheme for error codes, since this is an issue that needs to be addressed and better supported by the platform. In the meantime, error codes should be avoided (if possible) within pipelets. Instead use utility pipelets like SetDictionaryValue
that should be connected to the error exit of pipelets to record a custom error code. Note that this only works for pipelets that can experience only one error situation. If it is required to return an error code from the pipelet, you should declare an output parameter ErrorCode
and return a human-readable error name.