Ignition 8.1.17 - after upgrading from 8.1.16, pages message sent doesn't trigger perspective message handler?

Hi @PGriffith,

I've upgraded an application from Ignition 8.1.16 to Ignition 8.1.17

I have a module that send message to perspective pages.
All works fine in 8.1.16, but after upgrading in 8.1.17, the message are not sent or received in the event bus.

Does anything change in the way to send page's message ?

The code used by the module to send message:

    public void sendCallbackMessage(String strSessionId,String pageId,String sessionName,Dataset data) {
        try {
            UUID sessionId = UUID.fromString(strSessionId);
            perspectiveContext.getSessionMonitor().findSession(sessionId).ifPresent(session -> {

                Optional<PageModel> pageModel = session.findPage(pageId);
                if (pageModel.isPresent()){

                    PyDictionary payloadMap = new PyDictionary();
                    QualifiedValue value = new BasicQualifiedValue(data);
                    payloadMap.put("data", value);

                    UserScopeMessageEvent message = new UserScopeMessageEvent(sessionName, payloadMap);

                    logger.debug("sendCallbackMessage() send to sessionName={} - sessionId={} - pageId={} - data={}",
                            sessionName,
                            sessionId.toString(),
                            pageId,
                            value);

                    session.queue().submit(() -> pageModel.get().getPageEventBus().post(message));

                } else {
                    logger.error("sendCallbackMessage() - sessionId={} - pageId={} not found !",
                            sessionId.toString(),
                            pageId);
                }
            });
        } catch (Exception e) {
            logger.error("sendCallbackMessage() - Exception : {}",e);
        }
    }

According to gateway and browser logs, session id and page id are OK,
nevertheless the message handler that is no more triggered since upgrading in 8.1.17:

Perspective page message handler:

Instead of subscribing to the page eventbus, subscribe to the page’s event manager (you’ll have to bump your SDK version). There was a catastrophic performance cliff in Guava’s eventbus, so we had to migrate away. The API is roughly the same, but the internals are different.

Thanks a lot @PGriffith !

I suppose that it’s the same for session message, I have to use event Manager instead of event bus:

before 8.1.17:

	perspectiveContext.getSessionMonitor().findSession(sessionId).ifPresent(session -> {
			PyDictionary payloadMap = new PyDictionary();
			payloadMap.put("sessionId", sessionId.toString());
			payloadMap.put("id", id);
			payloadMap.put("qv", qv);
			UserScopeMessageEvent message = new UserScopeMessageEvent(messageHandler, payloadMap);
			logger.debug("SessionEventBus().post : sessionId={}, id={}, qv={}",sessionId.toString(),id,qv);
			session.queue().submit(() -> session.getEventBus().post(message));
	});

from 8.1.17:

session.queue().submit(() -> session.getEventManager().post(message));
1 Like

Yeah, pretty much everything in Perspective was refactored to have the two side by side. I think we’re planning to remove the eventbus stuff in Perspective in 8.2.X, but I’m not positive on that.

1 Like

is that required to depend on the Perspective module !?

If you plan to use Perspective APIs in your code, you must do two things:

  1. At compile time of your module, provide the appropriate Perspective SDK dependencies via your build system of choice.
  2. Declare a dependency on the Perspective module in your module.xml, so that Ignition knows to load your code (on the Gateway, at least) within an appropriate classloader.

If you want to handle Perspective being optional, things get somewhat more complicated and can require reflection to handle cleanly.

1 Like

Sorry for bothering you,
there is an Archetype for Perspective Module To import an empty Template To write My code there.
Thanks in Advanced

No, there are no Maven archetypes for a Perspective component. We use Gradle internally, and no one (to my knowledge) has yet figured out how to build a Perspective component with Maven.

There are two public examples of a Perspective component built using Gradle:

1 Like

Thanks PGriffith :heart:

Hi,

In relation to the above, I have got this mechanism working with Message Handlers on views (root). But I can't seem to get this to work with the Perspective Session Events mechanism. Am I supposed to be doing something different?

It's not clear at all to me what issue you're having or how it relates to the above. Are you also developing a module? What have you done/what are you currently doing/what's going wrong?

Sorry, should have added some context.

I am trying to send a message from a Module running on the gateway to a connected client.

So I have my module configured as it is laid out in this thread. Although, when I send the message using:

session.queue().submit(() -> session.getEventManager().post(message));

I can only register that message on the client, if I put my message handler on one of the pages in my project (I used the root for this test).

What I actually want to do, is have the message handler in the Perspective Session Events. I tested it with the Session Events and it seems that I cannot handle the message being sent from my module.

I do not get the message printed to the log from this message handler.

But I do from this message handler.

So I assume I need to send the messages in a different context, if it is possible at all?

Ah, yeah. The former are messages sent via (typically) system.util.sendMessage, on an overall platform-level bus. The latter are messages sent via system.perspective.sendMessage, on a Perspective-specific bus. To use the overall system bus, you want the MessageDispatchManager you get from GatewayContext. You build up a Properties instance with the static string constant keys in MessageDispatchManager.

So this is what I have tried at the moment.

PyDictionary payload = new PyDictionary();
payload.put("param", number);

Properties filterParams = new Properties();
filterParams.setProperty(MessageDispatchManager.KEY_SCOPE, MessageDispatchManager.SCOPE_CLIENT_ONLY);

dispatchManager.dispatch("ProjectName", "test", payload, filterParams);

The ProjectName is the actual name of my project. Looking through the KEYs in MessageDispatchManager I can't see any other I need (I could be wrong)

The message is still not handled by the client.

I think this is vision client, for perspective its probabbly SCOPE_SESSION

you should probably not hardcode a project name in a module

2 Likes

Ah! That worked. Thank you.

Yes, the ProjectName will come from the configuration eventually. It is easier to ignore that for now.

One last question, is there a way that I can display a Popup from the Perspective Session Events handler.

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 2, in handleMessage at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.popupAction(PerspectiveScriptingFunctions.java:758) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.openPopup(PerspectiveScriptingFunctions.java:240) 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.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.

at org.python.core.Py.JavaError(Py.java:547)

at org.python.core.Py.JavaError(Py.java:538)

at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)

at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:552)

at org.python.core.PyObject.__call__(PyObject.java:477)

at org.python.core.PyObject.__call__(PyObject.java:481)

at org.python.pycode._pyx351.handleMessage$1(:2)

at org.python.pycode._pyx351.call_function()

at org.python.core.PyTableCode.call(PyTableCode.java:173)

at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

at org.python.core.PyFunction.function___call__(PyFunction.java:474)

at org.python.core.PyFunction.__call__(PyFunction.java:469)

at org.python.core.PyFunction.__call__(PyFunction.java:464)

at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:846)

at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:828)

at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runFunction(ProjectScriptLifecycle.java:832)

at com.inductiveautomation.ignition.common.script.ScriptManager$ScriptFunctionImpl.invoke(ScriptManager.java:1009)

at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$AutoRecompilingScriptFunction.invoke(ProjectScriptLifecycle.java:897)

at com.inductiveautomation.perspective.gateway.script.ScriptFunctionHelper.invoke(ScriptFunctionHelper.java:147)

at com.inductiveautomation.perspective.gateway.script.ScriptRunner.run(ScriptRunner.java:23)

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.ThreadPoolExecutor.runWorker(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at com.inductiveautomation.perspective.gateway.threading.BlockingWork$BlockingWorkRunnable.run(BlockingWork.java:58)

at java.base/java.lang.Thread.run(Unknown Source)

Caused by: org.python.core.PyException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.

... 26 common frames omitted

Caused by: java.lang.IllegalArgumentException: No perspective page attached to this thread.

at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64)

at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120)

at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47)

at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.popupAction(PerspectiveScriptingFunctions.java:758)

at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.openPopup(PerspectiveScriptingFunctions.java:240)

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:190)

Because I get this error, so I am assuming I can't use system.perspective.openPopup without calling from within a Perspective View?

you can put you will need to fill in a pageId, as the session has many pages

1 Like

Ok great, I will take a look at that. Thank you.

2 Likes

Great! That got it working. Many thanks.

1 Like