Recently a series of enhancements to the Groovy integration has been introduced to let the system inject a base class for all the Groovy scripts. The classname is configurable in the groovy.properties file (located in in the framework/base/conf/ folder): the base class currently available provides an implementation of an OFBiz DSL (Domain Specific Language) based on Groovy specialized in the implementation of business logic (services, events and data preparation scripts).
Main goal: make available to all Groovy services, events, data preparation scripts and scriptles the same DSL, specific for OFBiz, and focused on simplifying common tasks like calling other services, performing entity operations, logging and returning messages, error handling. The end result is that all the business logic in OFBiz can now be implemented following a programming style very similar to the one provided by Minilang but leveraging all the features of a complete programming language.
The complete support for the OFBiz DSL is available since r. 1636346, committed to trunk in early November 2014.
In the following two sections we will compare examples of business logic implemented as a Minilang service and as a Java event to the equivalent version implemented with the Groovy DSL.
This is the original Minilang service:
Here is the equivalent in Groovy:
the code block:
is not really necessary (there is no equivalent in the Minilang version) but I have added it because it seems useful and also to show how you can log a warning message in the console and how you can prematurely return from a service (here we use a "failure" that is still a success, no rollback; but this nice feature is not used much in OFBiz)
- the code is really expressive and easy to read; no technical stuff that is not part of the business logic is needed (similar to Minilang); the code is also very concise (50% of the Minilang equivalent)
error handling: as in Minilang error handling related code is not necessary in the 90% of the cases; when a service call or an entity operation fail the service execution is stopped and the engine takes care of returning the "error" and rolling back the transactions; if you want to avoid this behavior for a special handling (equivalent of the Minilang's break-on-error="false" attribute) you can simply wrap the call in a try/catch block; for example:
However in most of the cases you shouldn't worry about errors returned by services and entity operations because the framework will take care of returning the proper error map for you (as it happens in Minilang)
- dispatcher and delegator objects are available with all their rich api (just use them as they are already in the context) but not necessary for the most common cases (calling sync services, fetching and manipulating simple data etc...) because for them you can use the DSL language: all the calls like runService, findOne, findList, makeValue etc... fetch the dispatcher/delegator from the context behind the lines
- runService accepts an input map and there is no need to add to it the userLogin object because the method will automatically fetch it from the context if not already in the map (same as in Minilang)
- the methods error(), failure(), success() (you can optionally pass a string to them for the message) all return a valid service output map; success/failure represent a "success" (no rollback) while error will cause a rollback; however in most of the cases you will not need to call "error" because if something goes wrong the framework will do it for you (similar to Minilang)
- with IDEs that support Groovy (I am using Idea) you will be able to debug groovy services like in Java; assisted completion features are also pretty good for Groovy
Here is the original event in Java:
Here is the equivalent in Groovy:
- the Groovy method that implements the event is identical to a Groovy service: all the event specific code is hidden by the usage of DSL
- now the success() method returns the "success" string as required by OFBiz events rather than the "success" map for services
- similarly the error() method returns the "error" string and adds the error message to the proper attribute of the request object (but this detail is hidden and the method looks exactly the same as in a service)
- you can now have a Groovy script file containing several methods, each method representing an event
- the try/catch block was not required because in case of error the "error" string would have been returned by the framework; however I have used it to return a custom error message (and show the usage of the "error" method)
Short reference of DSL operations
For now the DSL is intentionally simple because it is focused on most common tasks/behavior (for more complex and less common tasks you can use the dispatcher/delegator). This section provides a summary of the main methods; for a full reference please refer to the source file: http://svn.apache.org/repos/asf/ofbiz/ofbiz-framework/trunk/framework/service/src/main/java/org/apache/ofbiz/service/engine/GroovyBaseScript.groovy
The "run" method is implemented using named parameters and supports service calls with the following style:
The DSL valid the map passed before run the service, so you can call directly like
The "select" and "from" methods can be used in the following ways:
For more details refer to the Javadocs of EntityQuery.
and then call the methods on the GenericValue object (remove/store etc...)
logging (they all accept a GString i.e. $notation):
returning from the service or event (the methods simply return a Map for services or a string for events but you still have to use the "return" keyword to return the map back; when used by events the error method adds also the error message, if specified, to the request object):
DSL descriptor files for Eclipse and IntelliJ are included in OFBiz trunk since r1643183 in December 2014. For older versions, attached to this page you will find the DSL Descriptor files that, once added to the classpath (the framework/base/src/main/java/org/apache/ofbiz/base/ folder is probably the best place) of your OFBiz project, will add DSL support to all the Groovy scripts in OFBiz (autocompletion etc...):
- Eclipse: OfbizDslDescriptorForEclipse.dsld (seems to work in ~/.groovy/greclipse/global_dsld_support/dsld)
- IntelliJ: OfbizDslDescriptorForIntelliJ.gdsl