You can find Part 1 of this article here.
In Part 1 we created an add-on, which contains three SIL routines.
In Part 2 we will discuss, what should be changed in this add-on to add your own routine.
Create your own class for your routine
First of all you need to create your own class in the routine folder. This class must extend the AbstractSILRoutine<T> class.
Let's look at the available files in this folder (these files are provided as an example. If you develop you own add-on, you can remove these files).
SayHello.java:
public class SayHello extends AbstractSILRoutine<MutableString> {
private static final SILType[][] types = {{ TypeInst.STRING }};
public SayHello(ClassLoader classLoader, String name) {
super(classLoader, name, types);
}
@SFGOverride
public SILType<MutableString> getReturnType() { return TypeInst.STRING; }
@Override
protected SILValue<MutableString> runRoutine(SILContext silContext, List<SILValue<?>> list) {
SILValue param = list.get(0);
return SILValueFactory.string( "Hello " + param.toStringValue());
}
@Override
public String getParams() { return "(name)"; }
Let's have a look at the first line:
private static final SILType[][] types = {{ TypeInst.STRING }};
This line defines, what kind of input variables to expect for this routine. We call methods in SIL like this:
mymethod(myparameter);
By types = {{ TypeInst.STRING }}; we say that myparameter is a string. If you want to pass two parameters to mymethod then the line will be like this:
private static final SILType[][] types = {{ TypeInst.STRING, TypeInst.STRING }};
and you can call your method like this:
mymethod(myparameter1, myparameter2);
If your routine can take either one parameter or two parameters, then you should define it like this:
private static final SILType[][] types = {{ TypeInst.STRING},
{TypeInst.STRING, TypeInst.STRING }};
Next line:
public class SayHello extends AbstractSILRoutine<MutableString>
As you can see this class is extended from AbstractSILRoutine<MutableString>, which means that this routine will return the String type.
Next lines:
public SayHello(ClassLoader classLoader, String name) {
super(classLoader, name, types);
}
These lines define a constructor. You do not need to change anything there.
Next lines:
@SFGOverride
public SILType<MutableString> getReturnType() { return TypeInst.STRING; }
These lines define a function, which informs the SIL engine what object will be returned by this routine. We will return a String.
Next lines:
@Override
protected SILValue<MutableString> runRoutine(SILContext silContext, List<SILValue<?>> list) {
SILValue param = list.get(0);
return SILValueFactory.string( "Hello " + param.toStringValue());
}
These lines provide the logic, which will be executed by your routine. This is the entry point for your routine. This function accepts two parameters.
silContext (you can find here system variables like the issue, for which the script is executed, sil variables).
For example, if you need to take the issue for which the script is executed, you can use a code like this:
Issue issue = (Issue) silContext.getAllMetaInformation().get("issue");
The list parameter, is the parameter for your input variables.
Line
SILValueFactory.string( "Hello " + param.toStringValue())
returns a value from the routine. You should use the SILValueFactory class to create return values for your routine. This class can create all kind of value types available in SIL. We will see more examples later.
So, this routine actually just accept a parameter and return a result Hello + this parameter. You can implement any logic you need in this function.
Next lines:
@Override
public String getParams() { return "(name)"; }
These lines define how your function will look in the SIL Manager. When you start typing in the SIL manager, you see suggestions for available routines. the (name) string means that the suggestion will look like this:
yourmethod(name)
Add your class to SIL engine
We created a class, but how to tell the SIL engine how to use it? It is done in the ESLauncher.java file. You can see there lines like this one:
RoutineRegistry.register(new SayHello( classLoader,"SayHello"));
It says that we add the routine from the SayHello class and it will be called SayHello.
What you need is to copy the line and change first SayHello to your class and the next SayHello to your name. The name of the class and the name of the routine in SIL can be different.
Then also add a line like this:
RoutineRegistry.unregister("SayHello");
Change SayHello to the name of your routine. It will unload your routine, if you disable your add-on.
More on SIL
You can see in SayHello2, we return a List as a return value.
SILValue param1 = list.get(0);
SILValue param2 = list.get(1);
List<String> res = new ArrayList<>();
res.add("Hello " + param1.toStringValue());
res.add("Hello " + param2.toStringValue());
return SILValueFactory.stringArray(res);
where res is a List<String>.
To make it work you also need to change the return type to TypeInst.STRING_ARR and extend AbstractSILRoutine with KeyableArraySILObject<MutableString> type.
In SIL you can use this routine like this:
string[] res = SayHello2("Alexey", "Matveev");
runnerLog(res[0]);
runnerLog(res[1]);
In SayHello3 we return a Map:
SILValue param1 = list.get(0);
SILValue param2 = list.get(1);
Map<String, String> res = new HashMap<>();
res.put("param1","Hello " + param1.toStringValue());
res.put("param2","Hello " + param2.toStringValue());
return SILValueFactory.stringArray(res);
You can use SayHello3 in SIL like this:
res = SayHello3("Alexey", "Matveev");
runnerLog(res["param1"]);
runnerLog(res["param2"]);
We call the SIL array not by index, but by key. But if you notice, these functions have the same code to return a value:
return SILValueFactory.stringArray(res);
It is because in SIL the KeyableArraySILObject contains a List and a Map to provide keys for the List, that is why the code is the same.
Pass an array as a parameter
Now we know how to pass a string parameter to a SIL routine and return a string, a List or a Map.
Now let's have a look on how to pass an array as a parameter.
The runRoutine function will look like this:
@Override
protected SILValue<MutableString> runRoutine(SILContext silContext, List<SILValue<?>> list) {
GenericArraySILObject rowsToUpdate = (GenericArraySILObject) list.get(0).getObject();
Map<String, int[]> keys = rowsToUpdate.getKeysMapping()
......
}
First you convert the parameter to the GenericArraySILObject class and then convert it to Java's Map.
You could use this routine in SIL like this:
string[] arr;
arr["key1"] = "value1";
arr["key2"] = "value2";
yourmethod(arr);
That is all I wanted to talk about in this article. I hope that now you have a good intro in developing your own add-on for the SIL engine.
Alexey Matveev
software developer
MagicButtonLabs
Philippines
1,574 accepted answers
2 comments