User Code
User Defined Classes and Methods
scriptTask("Task"){
code{
userMethod()
}
}
def userMethod(){
return "UserString"
}
scriptTask("Task"){
code{
new UserClass().userMethod()
}
}
class UserClass{
def userMethod(){
return "ReturnValue"
}
}
Usage of Automation API in own defined Classes and Methods
In your own methods and classes the automation API is not automatically available differently as inside of the script task
code{} block. But it is often the case, that methods need access to the automation API.
The class ScriptApi provides static methods as entry points into the automation API. The static methods either return the API objects, or you could pass a Closure, which will activate the API inside of the Closure.
Access the Automation API like the Script code{} Block
The ScriptApi.scriptCode(Transformer) method provides access to all automation APIs the same way as inside of the normal script
code{} block. This is useful, if you want to call script code API inside of your own methods and classes.
def yourMethod(){
// Needs access to an automation API
ScriptApi.scriptCode{
// API is now available
generation.generate()
}
}
The ScriptApi.scriptCode() method can be used to call API in Java style.
def yourMethod(){
// Needs access to an automation API
ScriptApi.scriptCode().generation.generate()
}
Java note: The ScriptApi.scriptCode() returns the IScriptExecutionContext.
Access the Project API of the current active Project
The
ScriptApi.activeProject(Closure) method provides access to the project automation API of the currently active project. This is useful, if you want to call project API inside of your own methods and classes.
def yourMethod(){
// Needs access to an automation API
ScriptApi.activeProject{
// Project API is now available
transaction{
// Now model modifications are allowed
}
}
}
The ScriptApi.activeProject() method returns the current active IProject.
def yourMethod(){
// Needs access to an automation API
IProject theActiveProject = ScriptApi.activeProject()
}
User Defined Script Task Arguments
IScriptTaskUserDefinedArgument, which can be set by the user (e.g. from the commandline)
to pass user defined arguments to the script task execution. An argument can be optional or required. The arguments are type safe and checked before the task is
executed. An argument can be specified with a value and also without one. Example: "--count 25" or "-s"
Possible valueTypes are:
StringBooleanVoid: For parameter where only the existence is relevant.File: The existence of the file is not checked by default. See argument validators.Path: Same asFileIntegerLongDouble
The help text is automatically expanded with the help for user defined script task arguments.
scriptTask("TaskName"){
def procArg = newUserDefinedArgument("p", Void, "Enables the processing of ...")
code{
if(procArg.hasValue){
scriptLogger.info "The argument -p was defined"
}
}
}
scriptTask("TaskName"){
def countArg = newUserDefinedArgument("count", Integer,
"The amount of elements to create")
def nameArg = newUserDefinedArgument("name", String,
"The element name to create")
code{
// NOTE: The value can only be retrieved within the code closure
int count = countArg.value
String name = nameArg.value
scriptLogger.info "The arguments --name and --count were $name, $count"
}
}
scriptTask("TaskName"){
// User Defined Argument with the default value 25.0
def procArg = newUserDefinedArgument("p", Double, 25.0, "Help text ...")
code{
double value = procArg.value
scriptLogger.info "The argument -p was $value"
}
}
scriptTask("TaskName"){
def multiArg = newUserDefinedArgument("multiArg", String, "Help text ...")
code{
List<String> values = multiArg.values // Call values instead of value
scriptLogger.info "The argument --multiArg had values: $values"
}
}
User defined Argument Validators
newUserDefinedArgument()
call. The validator code is called when the input is checked. There are also default validators available, like:
- Constraints.IS_EXISTING_FOLDER
- Constraints.IS_EXISTING_FILE
- Constraints.IS_VALID_AUTOSAR_SHORT_NAME
import com.vector.cfg.util.contract.util.Constraints
scriptTask("TaskName"){
def contArg = newUserDefinedArgument( "p", String,
"Help text ...",
Constraints.IS_VALID_AUTOSAR_SHORT_NAME_PATH )
code{
String value = contArg.value
scriptLogger.info "The argument -p was $value"
}
}
Or you implement your own validation logic, by passing a Closure, which throws an exception, if the value is invalid.
scriptTask("TaskName"){
// User Defined Argument with the validator code as parameter
newUserDefinedArgument( "p", Integer, 20, "Help text ...",
{ value ->
if( value % 2){
throw new IllegalArgumentException("The value has to be even.")
}
} )
code{
}
}
Constraints
Constraints provides general purpose constraints for checking given parameter values throughout the automation interface. These constraints are referenced from the AutomationInterface documentation wherever they apply. The AutomationInterface takes a fail fast approach verifying provided parameter values as early as possible and throwing appropriate exceptions if values violate the corresponding constraints.
The following constraints are provided:
IS_VALID_PROJECT_NAME
Ensures that the given
String can be used as a name for a project. A valid project name starts with a letter [a-zA-Z] contains otherwise only characters matching [a-zA-Z0-9_-] and is at most 128 characters long.
IS_VALID_AUTOSAR_SHORT_NAME
Ensures that the given String conforms to the syntactical requirements for AUTOSAR short names.
IS_VALID_AUTOSAR_SHORT_NAME_PATH
Ensures that the given String conforms to the syntactical requirements for AUTOSAR short name paths.
IS_WRITABLE
Ensures that the file or folder represented by the given Path exists and can be written to.
Run Script Task with User Defined Task Arguments from CLI
The help of the run command shows, how to execute a script task with user defined arguments.
Usage: dvcfg-b automation run [-h] -b=<folder> [-p=<file>]
-t=<task>[,<task>...] [-t=<task>[,<task>...]]...
[-a=<arg>]... [-l=<location>[,<location>...]]...
[--debugger[=<port>]] [--no-save]
Description:
Run automation tasks with arguments.
* -t, --task=<task>[,<task>...] List of script tasks to execute.
E.g.: -t task1,task2
-a, --arg=<arg> Define a set of arguments specific to a single task.
E.g.: -a 'task1' -a '--name=str1 --value=1' -a 'task2' -a '-i 1,2,3'
Let’s have a look at an example script task with user defined arguments as shown below.
import static com.vector.cfg.automation.api.ScriptApi.*
scriptTask("userArgTask", DV_APPLICATION) {
def arg_enable = newUserDefinedArgument("enable", Void, "Help text ...")
def arg_count = newUserDefinedArgument("count", Integer, "Help text ...")
def arg_name = newUserDefinedArgument("name ", String, "Help text ...")
def arg_double = newUserDefinedArgument("double", Double, 25.0, "Help text ...")
def arg_multiArg = newUserDefinedArgument("multiArg", String, "Help text ...")
code {
if (arg_enable.hasValue) {
scriptLogger.info "The argument --enable was defined."
}
if (arg_count.hasValue) {
scriptLogger.info "The argument --count has the value ${arg_count.value}."
}
if (arg_name.hasValue) {
scriptLogger.info "The argument --name has the value ${arg_name.value}."
}
if (arg_double.hasValue) {
scriptLogger.info "The argument --double has the value ${arg_double.value}."
}
if (arg_multiArg.hasValue) {
List<String> values = arg_multiArg.values
scriptLogger.info "The argument --multiArg has values: ${values}."
}
}
}
To run this script task from CLI, you can use the following command.
automation run ...
-t "userArgTask"
-a "userArgTask"
-a "--enable --count=25 --name=John --double=25.0 --multiArg=1,2,3,4,5"
Stateful Script Tasks
Script tasks normally have no state or cached data, but it can be useful to cache data during an execution, or over multiple
task executions. The IScriptExecutionContext provides two methods to save and restore data for that purpose:
getExecutionData()- caches data during one task executiongetSessionData()- caches data over multiple task executions
Execution Data
Caches data during a single script task execution, which allows to save calculated values or services needed in multiple parts of the
task, without recalculating or creating it. Note: When the task is executed again the executionData will be empty.
scriptTask("TaskName"){
code{
// Cache a value for the execution
executionData.myCacheValue = 500
def val = executionData.myCacheValue // Retrieve the value anywhere
scriptLogger.info "The cached value is $val"
// Or access it from any place with ScriptApi.scriptCode like:
def sameValue = ScriptApi.scriptCode.executionData.myCacheValue
}
}
Session Data
Caches data over multiple task executions, which allows to implement a stateful task, by saving and retrieving any data calculated by the task itself.
Caution: The data is saved globally so the usage of the sessionData can lead to memory leaks or OutOfMemoryErrors. You have to take care not to
store too much memory in the sessionData. The DaVinci Configurator will also free the sessionData, when the system run low on free memory. So you
have to deal with the fact, that the sessionData was freed, when the script task getting executed again. But the data is not deallocated during a running
execution.
scriptTask("TaskName"){
// Setup - set the value the first time, this is only executed once (during initialization)
sessionData.myExecutionCount = 1
code{
// Retrieve the value
def executionCount = sessionData.myExecutionCount
scriptLogger.info "The task was executed $executionCount times"
// Update the value
sessionData.myExecutionCount = executionCount + 1
}
}
API usage
Both methods executionData and sessionData return the same API of type IScriptTaskUserData.
The IScriptTaskUserData provides methods to retrieve and store properties by a key (like a Map). The retrieval and store
methods are Object based, so any Object can be a key. The exception are Class instances (like String.class, which required that the value
is an instance of the Class).
On retrieval if a property does not exist an UnknownPropertyException is thrown. Properties can be set multiple times and will override the old value. The keys of the
properties used to retrieve and store data are compared with Object.equals(Object) for equality.
The listing below describes the usage of the API:
scriptTask("TaskName"){
code{
def val
// The sessionData and executionData have the same API
// You have multiple ways to set a value
executionData.myCacheId = "VALUE"
executionData.set("myCacheId", "VALUE")
executionData["myCacheId"] = "VALUE"
// Or with classes for a service locator pattern
executionData.set(Integer.class, 50) // Possible for any Class
executionData[Integer] = 50
// There are the same ways to retrieve the values
val = executionData.myCacheId
val = executionData.get("myCacheId")
val = executionData["myCacheId"]
// Or with classes for a service locator pattern
val = executionData.get(Integer.class)
val = executionData[Integer]
// You can also ask if the property exists
boolean exists = executionData.has("myCacheId")
}
}
ScriptAccess - Calling ScriptTasks
Sometimes it can be helpful to call other script tasks from inside your task. The scripts{} block or getScripts()
method provides API to retrieve existing IScripts and call other IScriptTasks from your running IScriptTask.
Note: If you just want to reuse code of your own scripts in an automation script project, create a normal method containing the code and call it, instead of calling the task. The method is typesafe, has code completion support and is much faster than calling a script task.
Calling script tasks
To call a task you need the name of the task and theIScriptTaskType. The IScriptTaskType determines the argument types and the
return type of the script task. Then you can use scripts.callScriptTask(String, Object...) to call the script.
You could also use callScriptTaskWithUserArgs(String, String, Object...), if you want to pass user defined arguments.
scriptTask("TaskName"){
code{
scripts.callScriptTask("OtherTask")
//The same
scripts{
callScriptTask("OtherTask")
}
}
}
scriptTask("OtherTask"){
code{
//Other task code
}
}
Calling script tasks with task arguments
If theIScriptTaskType requires task arguments, you have to pass the arguments to the callScriptTask()
methods. The return value of the method is the returned value of the called script task.
scriptTask("TaskName", DV_PROJECT){
code{
def arg1 = "First argument"
def arg2 = 5
def result = scripts.callScriptTask("OtherTask", arg1, arg2)
// Result contains the calculated value of OtherTask
}
}
scriptTask("OtherTask"){
code{arg1, arg2 ->
return arg1 + arg2
}
}