Encapsulate common code in shared Groovy classes

   Exchange Pre-configured Maestro services.  |   Platform Developer |  All versions   This feature is related to v5.1 and higher.

It is often the case that a suite of related Groovy services will have some element of common requirement. Rather than duplicating the required functions in each of your services, you should instead create additional Groovy classes that may be shared among the services.

There are two approaches for using common Groovy classes in your services:

  • Add them to your Fluent SDK project so that there are no external dependencies.
  • Keep them separate so they can be referenced by multiple Fluent SDK projects.

The process is very similar for these two approaches.

  1. Create the common Groovy classes as required.
    1. Ensure that your classes are in the default package (that is,they do not have a package declaration). Groovy classes in a package other than the default package are not permitted by the Fluent SDK Security Configuration.
    2. If you are adding these classes to your Fluent SDK project, add the source files to your sources root folder.
    3. If you are referring to these files externally, you need to ensure that the relevant class files are on the project build path for your IDE to utilize code complete and avoid class resolution errors.
  2. Add the path of the common Groovy source file to your service-def.json file.
    1. These files must be added to the fileIncludes attribute of the groovyScript parameter.
    2. The path must be a relative path from the service directory to the source file (for example, "../MyCommonClass.groovy").

Common code example

In this example, we'll modify the Hello World Service Example to extract the code that deals with CSV values into a common class, additional features and fail-safe checks, that can be reused by other services in the project.

Start by creating a CSV Groovy class in the sources root folder of our Fluent SDK project as follows:

// Ensure no package declaration
class CSV {
    List<String> values = (List<String>)[]

    public CSV(String csvString){
        set(csvString)
    }

    public CSV set(String csvString){
        values = (csvString ? csvString.tokenize(',') : (List<String>)[])
        return this
    }

    public String randomValue(){
        if (values.size() > 0) {
            int randomIndex = Math.floor(Math.random() * values.size()).intValue()
            return values.get(randomIndex)
        }
        return ''
    }

    public String toString(){
        return values.join(',')
    }
}

Your src folder should now look something like this.

Then, we can add this file to the fileIncludes in our service-def.json file.

{
    "name": "Welcome Greeting",
    "description": "Return a random greeting",
    "type": "Dynamic Data",
    "version": 1,
    "tmMinVersion": "5.0.0",
    "parameters": [
        {
            "name": "groovyScript",
            "filePath": "WelcomeGreeting.groovy",
            "fileIncludes": ["../CSV.groovy"],
            "bind": true,
            "required": false,
            "clearOnExport": false,
            "readOnly": true
        },
        {
            "name": "Unit Test Script",
            "filePath": "WelcomeGreetingTest.groovy",
            "fileIncludes": [],
            "bind": false,
            "required": false,
            "clearOnExport": false,
            "readOnly": true,
            "unitTest": true
        },
        {
            "name": "Help Doc",
            "type": "HTML",
            "filePath": "service-help.html",
            "bind": false,
            "required": false,
            "clearOnExport": false,
            "readOnly": true
        },
        {
            "name": "greetingsCsv",
            "description": "A comma separated list of greetings used to generate a greeting at random.",
            "type": "Text",
            "required": true,
            "readOnly": false,
            "value": "Hi,Hello,G'Day,Allo,Hola,Bonjour,Salut,Buenos dias",
            "clearOnExport": false
        }
    ]
}

Now, we are ready to adjust our service code to utilize this common class by making the following code changes.

Original code
// Select a greeting from the list at random
List<String> greetings = svcDef.paramsMap.greetingsCsv.tokenize(',')
String randomGreeting = greetings.get(Math.floor(Math.random() * greetings.size()).intValue())
New code using the CSV class
// Select a greeting from the list at random
String randomGreeting = new CSV(svcDef.paramsMap.greetingsCsv).randomValue() ?: 'Hi'

The resulting service code should now look like this.

import com.avoka.core.groovy.GroovyLogger as logger
import com.avoka.tm.vo.*
import javax.servlet.http.*
import groovy.json.JsonBuilder

class WelcomeGreeting {

    String invoke(SvcDef svcDef, Txn txn, HttpServletRequest request, User user) {

        // Read the person's name from the request
        String personsName = request.getParameter('name') ?: 'friend'

        // Select a greeting from the list at random
        String randomGreeting = new CSV(svcDef.paramsMap.greetingsCsv).randomValue() ?: 'Hi'

        // Create the result Map containing the greeting
        Map result = [:]
        result.greeting = (randomGreeting + ' ' + personsName)

        // Convert to JSON and return
        return new JsonBuilder(result).toString()
    }
}

If you deploy this service to Journey Manager and view the Groovy Script tab via the console, you'll see that the CSV class has been appended to the bottom of the script.

import com.avoka.core.groovy.GroovyLogger as logger
import com.avoka.tm.vo.*
import javax.servlet.http.*
import groovy.json.JsonBuilder

class WelcomeGreeting {

    String invoke(SvcDef svcDef, Txn txn, HttpServletRequest request, User user) {

        // Read the persons name from the request
        String personsName = request.getParameter('name') ?: 'friend'

        // Select a greeting from the list at random
        String randomGreeting = new CSV(svcDef.paramsMap.greetingsCsv).randomValue() ?: 'Hi'

        // Create the result Map containing the greeting
        Map result = [:]
        result.greeting = (randomGreeting + ' ' + personsName)

        // Convert to JSON and return
        return new JsonBuilder(result).toString()
    }
}

// GPackage Include: ../CSV.groovy
class CSV {

    List<String> values = (List<String>)[]

    public CSV(String csvString){
        set(csvString)
    }

    public CSV set(String csvString){
        values = (csvString ? csvString.tokenize(',') : (List<String>)[])
        return this
    }

    public String randomValue(){
        if (values.size() > 0) {
            int randomIndex = Math.floor(Math.random() * values.size()).intValue()
            return values.get(randomIndex)
        }
        return ''
    }

    public String toString(){
        return values.join(',')
    }
}