Cannot execute RPC Call: Module not found

I’m trying to build a module with an RPC Call. I couldn’t get it to work, so I tryied making a minimal example starting from a fresh project.

I followed the SDK docs for the biggest part, with two exceptions:

  • The getRPCHandler override on the GatewayHook now seems to need a string as second argument
  • I replaced the reference to ModuleMeta.MODULE_ID with "org.example.ModuleRPCImpl", which is the path to the implementing class.

I also made the method available to the scripting side as system.rpc.getGreeting, so I can test it easily. However, whenever I that method, I see the following errors:

com.inductiveautomation.ignition.client.gateway_interface.GatewayException: Module "org.example.ModuleRPCImpl" not found.
java.lang.IllegalArgumentException: Module "org.example.ModuleRPCImpl" not found.

I also treid with "org.example" as module id, but it gave a similar error "org.example" not found.

Full error stack:

Java Traceback:
Traceback (most recent call last):
  File "<input>", line 1, in <module>
	at com.sun.proxy.$Proxy61.getGreeting(Unknown Source)
	at org.example.designer.RPCCaller.getGreeting(RPCCaller.java:10)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.lang.reflect.UndeclaredThrowableException: java.lang.reflect.UndeclaredThrowableException

	at org.python.core.Py.JavaError(Py.java:552)
	at org.python.core.Py.JavaError(Py.java:543)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:520)
	at org.python.core.PyObject.__call__(PyObject.java:480)
	at org.python.core.PyObject.__call__(PyObject.java:484)
	at org.python.pycode._pyx6.f$0(<input>:1)
	at org.python.pycode._pyx6.call_function(<input>)
	at org.python.core.PyTableCode.call(PyTableCode.java:171)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1614)
	at org.python.core.Py.exec(Py.java:1658)
	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:276)
	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:131)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:605)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:593)
	at java.desktop/javax.swing.SwingWorker$1.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.desktop/javax.swing.SwingWorker.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.reflect.UndeclaredThrowableException
	at com.sun.proxy.$Proxy61.getGreeting(Unknown Source)
	at org.example.designer.RPCCaller.getGreeting(RPCCaller.java:10)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:188)
	... 19 more
Caused by: com.inductiveautomation.ignition.client.gateway_interface.GatewayException: Module "org.example.ModuleRPCImpl" not found.
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.newGatewayException(GatewayInterface.java:339)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:313)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:266)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.moduleInvokeSafe(GatewayInterface.java:878)
	at com.inductiveautomation.ignition.client.gateway_interface.ModuleRPCFactory$DynamicRPCHandler.invoke(ModuleRPCFactory.java:53)
	... 26 more
Caused by: java.lang.IllegalArgumentException: Module "org.example.ModuleRPCImpl" not found.
	at com.inductiveautomation.ignition.gateway.servlets.gateway.functions.ModuleInvoke.invoke(ModuleInvoke.java:68)
	at com.inductiveautomation.ignition.gateway.servlets.Gateway.doPost(Gateway.java:411)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at com.inductiveautomation.ignition.gateway.bootstrap.MapServlet.service(MapServlet.java:86)
	at org.eclipse.jetty.servlet.ServletHolder$NotAsyncServlet.service(ServletHolder.java:1391)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:760)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:547)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:590)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1607)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1297)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:485)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1577)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1212)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:322)
	at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.Server.handle(Server.java:500)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:547)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:270)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:388)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)
	at java.lang.Thread.run(null)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
	at com.sun.proxy.$Proxy61.getGreeting(Unknown Source)
	at org.example.designer.RPCCaller.getGreeting(RPCCaller.java:10)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.lang.reflect.UndeclaredThrowableException: java.lang.reflect.UndeclaredThrowableException

For anyone interested, here is the complete code of that example, including modl file under the build target.
TestProject2.zip (65.2 KB)

It seems like a basic thing to do, but I can’t get it right. I’m trying it on 8.0.10 at the moment.

Check this thread for changes to getRPCHandler: getRPCHandler usage in Ignition 8.0

I did alter the getRPCHandler signature, and the project builds. Is there anything else I can get from that thread?

Just knowing what that string represents…

I just found some more time to tinker with this.

This is my full example of the GatewayHook

package org.example;

import com.inductiveautomation.ignition.common.licensing.LicenseState;
import com.inductiveautomation.ignition.gateway.clientcomm.ClientReqSession;
import com.inductiveautomation.ignition.gateway.model.AbstractGatewayModuleHook;
import com.inductiveautomation.ignition.gateway.model.GatewayContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GatewayHook extends AbstractGatewayModuleHook {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void setup(GatewayContext gatewayContext) {
        logger.info("Setup GatewayHook");
    }

    @Override
    public void startup(LicenseState licenseState) {
        logger.info("Starting GatewayHook");
    }

    @Override
    public void shutdown() {

    }

    @Override
    public Object getRPCHandler(ClientReqSession session, String projectName) {
        logger.info("getRPCHandler called");
        return new ModuleRPCImpl();
    }
}

I see both the setup and the startup methods are called, however, the getRPCHandler method is never called.Not on startup and not when I call a script that should go over RPC.


The RPC implementation is just this from the tutorial:

package org.example;

public class ModuleRPCImpl implements ModuleRPC {
    public String getGreeting(String firstName){
        return "Hello, " + firstName;
    }
}

I really have no idea what I should do with that “projectName” string, certainly not for this example that should hold for all projects, and if the getRPCHandler method doesn’t even get called.

getRPCHandler won’t get called until a client or designer calls the gateway with your module ID, target function name, and appropriate list of arguments. You should have an concrete implementation of your ModuleRPC interface in your client jar that is called by all client/designer code when needed.

The session and project give you an opportunity to deliver an implementing object that is tailored to those values (passed in the inplementing class’s constructor). If you do so, consider maintaining a weak reference hashmap so a given session gets the same instance every time.

1 Like

Thank you, now I got it to work. So this was my mistake.

The explanation regarding the MODULE_ID confused me as in the example, it’s just the path of the main package (https://docs.inductiveautomation.com/display/SE/The+Module+Code).

I thought the getRPCHandler would register a class or an object during startup or during start of the designer under its classpath or package name. When needed, the client could call that method on that class.
Your comment on how the getRPCHandler is only called when the client requests the RPC object made me realise my mistake.

Thanks a lot.

Strictly speaking, it is the ID given in your module.xml. That it is your main package is a convention. v8 follows the convention closer than v7.9 for modules from IA.

2 Likes