How to call one module method into another

I have one module, in which I have created the method.
Now I wanted to call the methods of my module into another module.

Lets pretend this is the module you wrote -

myModule

def foo():
    pass

Then in your other module

import myModule

myModule.foo()

Assuming you are using the scripting modules section.

This is the "Module Development" category for SDK modules.

For complete access to one module's classes and methods from another, you would make the first module a declared dependency of the second module (in module.xml). This will make the second module's classloader a child of the first module's classloader.

If you cannot do this (some other dependency interferes, perhaps), then you will have to use an indirect access method. If you look at the javadocs for CommonContext, you will see a getModule() method that returns a different module's gateway hook. You can use this from your second module to obtain a reference to your first module's gateway hook. That hook must expose methods you can use to obtain any other class instances you need.

2 Likes

Whoops, I didn’t see the category tag. Ignore what I said.

1 Like

@pturmel thank you for this suggestion: That hook must expose methods you can use to obtain any other class instances you need.

I have tried to implement it:

  • by creating a new interface (called IGatewayHook, that extends the standard GatewayModuleHook), where the method getProviders is declared, in order to obtain the “provider” instances from the other module.
  • by adding the implementation of IGatewayHook to the GatewayHook classes of the two modules (in order to implement the getProviders method).
  • by calling from one module the following:
    baseModuleHook = (IGatewayHook) context.getModuleManager().getModule("com.xxx.ignition.kernel.base").getHook();

The last instruction throws the ClassCastException exception:

java.lang.Exception: Exception while starting up module "com.xxx.ignition.kernel.simulation".
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$LoadedModule.startup(ModuleManagerImpl.java:2439)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.startupModule(ModuleManagerImpl.java:1226)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$2.call(ModuleManagerImpl.java:771)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.executeModuleOperation(ModuleManagerImpl.java:947)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.installModuleInternal(ModuleManagerImpl.java:737)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$InstallCommand.execute(ModuleManagerImpl.java:1903)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$Receiver.receiveCall(ModuleManagerImpl.java:1856)
	at com.inductiveautomation.ignition.gateway.redundancy.QueueableMessageReceiver.receiveCall(QueueableMessageReceiver.java:47)
	at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl.dispatchMessage(RedundancyManagerImpl.java:933)
	at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl$ExecuteTask.run(RedundancyManagerImpl.java:1008)
	at com.inductiveautomation.ignition.common.execution.impl.BasicExecutionEngine$ThrowableCatchingRunnable.run(BasicExecutionEngine.java:518)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassCastException: class com.xxx.ignition.kernel.provider.GatewayHook cannot be cast to class com.xxx.ignition.kernel.provider.IGatewayHook (com.xxx.ignition.kernel.provider.GatewayHook is in unnamed module of loader com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader @10a94db3; com.xxx.ignition.kernel.provider.IGatewayHook is in unnamed module of loader com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader @27a7482e)
	at com.xxx.ignition.kernel.provider.simulation.GatewayHook.startup(GatewayHook.java:45)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$LoadedModule.startup(ModuleManagerImpl.java:2433)
	... 16 more

8.0.17 (b2020111211)
Azul Systems, Inc. 11.0.7

where the cast is not allowed: I do not understand why. Could you help me?
Thank you very much in advance.

Best,
Andrea

Modules are loaded in their own isolated ClassLoader. If you want to be able to reference something from module “A” in your module “B” then you have to mark module “B” as depending on module “A”, which will cause “A”’s ClassLoader to be the parent ClassLoader for “B”.

An interface won’t help. You can’t retroactively apply such to the other module’s hook. I should have pointed out that you will probably have to use reflection to access anything that isn’t already declared in GatewayModuleHook.

Thank you @Kevin.Herron.
The dependency has been added, in effect the instances of the other module are accessible via debug mode.

Thank you @pturmel, I am going to work on what you suggested!

Hi @Kevin.Herron,
a better clarification: to create the module dependency, it is enough to have on module B pom file the below part?

    <dependencies>
        <dependency>
            <groupId>com.xxx.ignition</groupId>
            <artifactId>moduleA</artifactId>
            <version>x.y</version>
        </dependency>
    </dependencies>

I follow the userguide in Understanding Class Loaders - Ignition SDK Programmer’s Guide - Ignition Documentation (inductiveautomation.com), but there isn’t any reference to the pom structure and I am not sure to be on the right way!

I wouldn’t expect that to be enough. You have to end up with a <depends> entry in your module.xml file. (I still don’t use maven and its Ignition plug, so I can’t be more specific.)

Here’s what we’ve used, and is working with Maven. The key as was pointed out is the depends section.

<build>
        <plugins>
            <plugin>
                <groupId>com.inductiveautomation.ignitionsdk</groupId>
                <artifactId>ignition-maven-plugin</artifactId>
                <version>1.1.0</version>

                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>modl</goal>
                        </goals>
                    </execution>
                </executions>

                <configuration>
                    <projectScopes>
                        <projectScope>
                            <name>package-client</name>
                            <scope>C</scope>
                        </projectScope>
                        <projectScope>
                            <name>package-common</name>
                            <scope>CDG</scope>
                        </projectScope>
                        <projectScope>
                            <name>package-designer</name>
                            <scope>CD</scope>
                        </projectScope>
                        <projectScope>
                            <name>package-gateway</name>
                            <scope>G</scope>
                        </projectScope>
                    </projectScopes>

                    <moduleId>com.package</moduleId>
                    <moduleName>${project.parent.name}</moduleName>
                    <moduleDescription>${project.description}</moduleDescription>
                    <moduleVersion>${project.version}</moduleVersion>
                    <requiredIgnitionVersion>8.1.0</requiredIgnitionVersion>
                    <requiredFrameworkVersion>8</requiredFrameworkVersion>
                    <licenseFile>License.html</licenseFile>

                    <depends>
                        <depend>
                            <scope>CDG</scope>
                            <moduleId>com.otherpackage</moduleId>
                        </depend>
                    </depends>

                    <hooks>
                        <hook>
                            <scope>C</scope>
                            <hookClass>com.package.client.ClientHook</hookClass>
                        </hook>
                        <hook>
                            <scope>D</scope>
                            <hookClass>com.package.designer.DesignerHook</hookClass>
                        </hook>
                        <hook>
                            <scope>G</scope>
                            <hookClass>com.package.gateway.GatewayHook</hookClass>
                        </hook>
                    </hooks>

                </configuration>
            </plugin>
        </plugins>
    </build>

How does one get the context object to start?
(I’m new to java, maven, and intellij)

This page: Read and Write Tags - Ignition SDK Programmer's Guide - Ignition Documentation
says:
IgnitionGateway context = IgnitionGateway.get();
but the fine print at the top says “assumes that the GatewayContext object is available”

I started with the example scripting-function module from: GitHub - inductiveautomation/ignition-sdk-examples: Ignition SDK Example Projects and added that context line inside the GatewayScriptModule’s multiplyImpl function body and get the error:
Cannot resolve symbol ‘IgnitionGateway’

Using Ignition 8.0.13

Hmm, those are poor examples. The IgnitionGateway class is not part of the public API/SDK. I think you’re supposed to ignore that part and that’s why it says the assumption is you have a GatewayContext.

Your module gets the GatewayContext in the GatewayModuleHook::setup call. You can pass it around as needed.

2 Likes