# How to get the ScriptManager inside Gateway Module Java

**URL:** <https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137>\
**Category:** Module Development\
**Created:** [February 14, 2022, 10:07pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137 "2022-02-14T22:07:35Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![kevin.setter](https://avatars.discourse-cdn.com/v4/letter/k/85e7bf/32.png) [@kevin.setter](https://forum.inductiveautomation.com/u/kevin.setter)\
**Post date:** [February 14, 2022, 10:07pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/1 "2022-02-14T22:07:35Z")

</div>

I am using one of the Perspective examples from GitHub (the Messenger) as a base for my code and the samplequickstart perspective project to learn from.

I have a reference to the GatewayContext and now I would like to get a reference to the Project ScriptManager.

I found on another thread this call

com.inductiveautomation.ignition.common.script.ScriptManager mgr = mygatewaycontext.getProjectManager().getProjectScriptManager(projectId);

My first problem is other than being of type long, I don’t know where to get the projectId from.

The documents I read from here,  
[ProjectManager (inductiveautomation.com)](http://files.inductiveautomation.com/sdk/javadoc/ignition80/8.0.0-beta/com/inductiveautomation/ignition/gateway/project/ProjectManager.html)  
show me after I get a ProjectManager as in,

ProjectManger pmgr = mygatewaycontext.getProjectManager() I should be able to get a Project from

Project p = pmgr.getProject(“samplequickstart”)  
and then long id = p.getId();

But, the call to pmgr.getProject(“samplequickstart”) returns a type Optional not a Project.

Is the dependency library in the example project not the same version as the documents I found? Or is my lack of understanding making this far more difficult that it needs to be?

Thanks in advance.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 14, 2022, 10:17pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/2 "2022-02-14T22:17:46Z")

</div>

`Optional` is a wrapping class used to avoid passing nulls around. You get the project from the Optional, if the project exists.

However, if you are trying to manipulate the jython environment that your project’s event scripts will use, you need to _ **respond** _ to the Gateway hook method to initialize a ScriptManager, which will be called separately for each enabled project in the gateway. You inject your jython definitions at that time, tailored to the project if necessary.

Getting a separate script manager instance is for your module to run its own internal jython, if any.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [February 14, 2022, 10:33pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/3 "2022-02-14T22:33:15Z")

</div>

What user action (if any) is going to invoke your script/what are you actually trying to do with the ScriptManager? How/where does your user author their code, how are you retrieving it, and where does it get fired?

---

<div class="post-metadata">

**Author:** ![kevin.setter](https://avatars.discourse-cdn.com/v4/letter/k/85e7bf/32.png) [@kevin.setter](https://forum.inductiveautomation.com/u/kevin.setter)\
**Post date:** [February 15, 2022, 2:30am UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/4 "2022-02-15T02:30:47Z")

</div>

@pturmel I see, thanks about the Optional. I should have just googled “Optional java”

I was attempting to follow this thread for a starter in my learning path here. It’s a bit old (2013)

[Executing Python from Module - 3rd Party Modules - Inductive Automation Forum](https://forum.inductiveautomation.com/t/executing-python-from-module/6073/9)

Does this line work to get a ScriptManager per project?  
com.inductiveautomation.ignition.common.script.ScriptManager mgr = ctx.getProjectManager().getProjectScriptManager(projectId)

@paul-griffith I’m trying to call pre-defined scripts from the Project Library. I am trying to call them from the handleEvent(…) method in the MobileComponentModelDelegate. The trigger (firing) is from the React component button that sends a message in the example code.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [February 15, 2022, 5:47pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/5 "2022-02-15T17:47:06Z")

</div>

I wouldn't try to hardcode a script name. That's an antipattern - what if you want to change the name of the script that's invoked; you need to install a new module to do so?  
Instead, I would look into the extension function mechanism. You can provide an extension function with your component, invoke it when necessary from your code, and allow the end user in the designer to author whatever code they feel like.

There's some discussion on a similar problem in this thread, including some of the code required to invoke an extension function in Perspective; I'm not sure if our example module provides any samples of that:

> [@Any way to write to a file on the gateway or to database from javascript?](https://forum.inductiveautomation.com/t/any-way-to-write-to-a-file-on-the-gateway-or-to-database-from-javascript/51442):
>
> I would like to write to the db and some files directly from out of my module in js. Any way to do this (without webdev module?) I usually use ajax or node.js to connect to a db. With node i can also write files… But im guessing i dont have any access to those… or idk how they are set up to the ignition server

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [February 16, 2022, 7:39am UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/6 "2022-02-16T07:39:32Z")

</div>

> [@paul-griffith](#):
>
> I’m not sure if our example module provides any samples of that:

Nope im pretty sure it doesnt,

You should check out this topic too, when i ran into some troubles on 8.1.12+  
There are some screens of code in there of both versions

> [@\[Bug\] v8.1.12 Error on invoking extension function, NoBlockingWorkAllowedException](https://forum.inductiveautomation.com/t/bug-v8-1-12-error-on-invoking-extension-function-noblockingworkallowedexception/55102/8):
>
> Phew finally got it working again! I created a runnable with a getValue function where i set BlockingWork.setBLockingWarkAllowed(true) (im doing it twice idk which one is needed but it works) Then initialize the runnable, start it in a thread. wait for it to finish running (join) and get the value from the runnable

---

<div class="post-metadata">

**Author:** ![kevin.setter](https://avatars.discourse-cdn.com/v4/letter/k/85e7bf/32.png) [@kevin.setter](https://forum.inductiveautomation.com/u/kevin.setter)\
**Post date:** [February 18, 2022, 11:50pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/7 "2022-02-18T23:50:20Z")

</div>

Ok, thanks @paul-griffith ,

I can see how to find and invoke an extension function. Can I create my own extension function for my component? I think that would fit the solution best.

How do I do this, in java code, or in the designer? Can you please point me in the direction of some documentation? Or maybe examples.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [February 19, 2022, 12:12am UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/8 "2022-02-19T00:12:22Z")

</div>

Provide `ExtensionFunctionDescriptors` in your `ComponentDescriptor` when it’s registered, and the UI will automatically have them available. Then you use the APIs mentioned in the other threads linked above to retrieve the extension function (which may or may not be present) and invoke it accordingly.

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [February 21, 2022, 7:51am UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/9 "2022-02-21T07:51:47Z")

</div>

Here some exmaples of what i did:

create a json file simalar to like for the props:

```auto
{
  "extensionFunctions": [
    {
      "name": "onRowStartEdit",
      "description": "Fired when rows in the table are being triggered to edited, if not enabled the default grids update popup will show up which will trigger an event onRowUpdated \nIf you return True the default popup will also show (example to first filter on user role)",

      "default": "\tsystem.perspective.sendMessage(messageType \u003d\"handleButtonEdit\", payload\u003d{\"data\":[x.data for x in rows]})\n\treturn False",
      "arguments":[{
          "name": "rows",
          "description": "Array of data of the selected rows each row has id (index of the selected row) and data (rows[0].data)"
        },
        {
          "name": "columns",
          "description": "The columns in order which are editable"
        }]
    }
  ]
}

```

then add it to the schema (this is probably not the most effective way of adding it but it realy doesnt matter and it works xd

```auto
public static final JsonObject EXTENSIONS_OBJECT = (new JsonParser()).parse(new InputStreamReader(GridComponents.class.getResourceAsStream("/grid.extensions.json"), StandardCharsets.UTF_8)).getAsJsonObject();
    public static final List EXTENSIONS;
    static {
      EXTENSIONS = new ArrayList();
      JsonArray jsonExt = EXTENSIONS_OBJECT.get("extensionFunctions").getAsJsonArray();
      jsonExt.forEach(eventElem -> {
        JsonObject eventDef = eventElem.getAsJsonObject();
        List<ExtensionFunctionDescriptor.ExtensionFunctionArgument> Arguments = new ArrayList<ExtensionFunctionDescriptor.ExtensionFunctionArgument>();
        JsonArray args = eventDef.get("arguments").getAsJsonArray();
        args.forEach(argsElem -> {
          JsonObject argDef = argsElem.getAsJsonObject();
          Arguments.add(new ExtensionFunctionDescriptor.ExtensionFunctionArgument(argDef.get("name").getAsString(), argDef.get("description").getAsString()));
        });
        EXTENSIONS.add(new ExtensionFunctionDescriptor(eventDef.get("name").getAsString(), eventDef.get("description").getAsString(), eventDef.get("default").getAsString(), Arguments ));
      });
    }

    public static ComponentDescriptor DESCRIPTOR = ComponentDescriptorImpl.ComponentBuilder.newBuilder()
        .setPaletteCategory(GridComponents.COMPONENT_CATEGORY)
        .setId(COMPONENT_ID)
        .setModuleId(GridComponents.MODULE_ID)
        .setSchema(SCHEMA) 
        .setName("Grid")
        .addPaletteEntry("", "Grid", "An Grid component.", null, null)
        .setDefaultMetaName("grid")
        .setEvents(EVENTS)
        .setExtensionFunctions(EXTENSIONS)
        .setResources(GridComponents.BROWSER_RESOURCES)
        .build();

```

Than add it to the descriptor  
`.setExtensionFunctions(EXTENSIONS)`

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [February 22, 2022, 3:25pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/10 "2022-02-22T15:25:38Z")

</div>

> [@victordcq](#):
>
> this is probably not the most effective way of adding it but it realy doesnt matter and it works

You should be able to create each ExtensionFunctionDescriptor from a Gson instance, something like:

```auto
            JsonArray extFnArray = json.getAsJsonArray("extensionFunctions");
            List<ExtensionFunctionDescriptor> extFns = Lists.newArrayList(extFnArray).stream()
                .map(element -> GSON.fromJson(element, ExtensionFunctionDescriptor.class))
                .collect(Collectors.toList());

```

Or you can use the `TypeToken` class to reify a list type parameter (which would otherwise be erased) and use that during deserialization of the entire JsonArray:

```auto
    public static final Type TYPE_TOKEN = new TypeToken<List<PerspectiveProjectData>>() {}.getType();

```

Or if you switch to Kotlin, the gentleman's JVM language 😉 you could use a reified function more directly:

```auto
/**
 * Deserialize [element] as [T]. Constructs a [TypeToken] automatically to capture reified type parameter.
 */
@Suppress("UnstableApiUsage")
inline fun <reified T : Any> JsonDeserializationContext.deserialize(element: JsonElement): T {
    return deserialize(element, object : TypeToken<T>() {}.type)
}

```

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [February 22, 2022, 3:49pm UTC](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/11 "2022-02-22T15:49:55Z")

</div>

Yeah… it somehow didnt work like the events, might have been the json schema itself i forgot tbh.

There was no example of the extension functions so yeah,  
Im happy that it worked so i didnt touch it anymore xD Performance wise this bit of code doesnt matter anyways, and even then its not like im doing something extremely weird (for once).

i dont really have an free moment to refactor xd
