Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
We've encountered an issue exporting this macro. Please try exporting this page again later.

In Part 1 we created an add-on, which contains three SIL routinesfunctions

In Part 2 we will discuss, what should be changed in this add-on to add your own routinefunction.

1. Create your own class for your

routine

function

First of all you need to create your own class in the routine function folder. This class must extend the AbstractSILRoutine<T> the AbstractSILFunction<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:

Code Block
public class SayHello extends AbstractSILRoutine<MutableString>AbstractSILFunction<MutableString> { 
  private static final SILType[][] types = {{ TypeInst.STRING }};

  public SayHello(ClassLoader classLoader, String name) { 
    super(classLoader, name, types);
  }

  Override 
  public SILType<MutableString> getReturnType() { return TypeInst.STRING; }

  @Override 
  protected SILValue<MutableString> runRoutinerunFunction(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:

Code Block
 private static final SILType[][] types = {{ TypeInst.STRING }};

This line defines, what kind of input variables to expect for this routinefunction. We call methods in SIL like this:

Code Block
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: 

Code Block
 private static final SILType[][] types = {{ TypeInst.STRING, TypeInst.STRING }};

and you can call your method like this:

Code Block
mymethod(myparameter1, myparameter2);

If your routine function can take either one parameter or two parameters, then you should define it like this:

Code Block
private static final SILType[][] types = {{ TypeInst.STRING},

              {TypeInst.STRING, TypeInst.STRING }};

Next line:

Code Block
public class SayHello extends AbstractSILRoutine<MutableString>AbstractSILFunction<MutableString>

As you can see this class is extended from AbstractSILRoutine<MutableString>AbstractSILFunction<MutableString>, which means that this routine function will return the String type.

Next lines:

Code Block
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:

Code Block
Override 
public SILType<MutableString> getReturnType() { return TypeInst.STRING; }

These lines define a function, which informs the SIL engine what object will be returned by this routinefunction. We will return a String.

Next lines:

Code Block
@Override 
protected SILValue<MutableString> runRoutinerunFunction(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 routinefunction. This is the entry point for your routinefunction. 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:

Code Block
Issue issue = (Issue) silContext.getAllMetaInformation().get("issue");

The list parameter, is the parameter for your input variables.

Line

Code Block
SILValueFactory.string( "Hello " + param.toStringValue())

returns a value from the routinefunction. You should use the SILValueFactory class to create return values for your routinefunction. This class can create all kind of value types available in SIL. We will see more examples later.

So, this routine function actually just accept a parameter and return a result Hello + this parameter. You can implement any logic you need in this function.

Next lines:

Code Block
@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 routinesfunctions. the (name) string means that the suggestion will look like this:

Code Block
yourmethod(name)

2. 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:

Code Block
RoutineRegistryFunctionRegistry.register(new SayHello( classLoader,"SayHello")); 

It says that we add the routine function 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 function in SIL can be different.

Then also add a line like this:

Code Block
RoutineRegistryFunctionRegistry.unregister("SayHello");

Change SayHello to the name of your routinefunction. It will unload your routinefunction, if you disable your add-on.

3. More on SIL

You can see in SayHello2, we return a List as a return value.

Code Block
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 extend AbstractSILFunction with KeyableArraySILObject<MutableString> type.

In SIL you can use this routine function like this:

Code Block
string[] res = SayHello2("Alexey", "Matveev");
runnerLog(res[0]);
runnerLog(res[1]);

In SayHello3 we return a Map:

Code Block
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:

Code Block
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:

Code Block
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.

4. Pass an array as a parameter

Now we know how to pass a string parameter to a SIL routine function 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 runFunction function will look like this:

Code Block
@Override
protected SILValue<MutableString> runRoutinerunFunction(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 function in SIL like this:

Code Block
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.

Contents

Table of Contents