My plugin: different behavior in developer and in server

Hi:

I’d like to send messages to clients when an event (i.e., a data change) occurs. Surprisingly there’s no standard method in Servoy to do that (I can’t use maintenance plugin in this context), so I’m looking for a plugin.

I found the mfServerUtils plugin, but, as I told in another post, it isn’t compatible with Servoy 5.2.

Well, what can I do? “Create your own plugin”, I told myself :wink:. I have no idea to build a plugin, so I read the Patrick Talbot’s tutorials and I started to write code.

I found why mfServerUtils plugin doesn’t work: it uses this code to send a message to a client:

IClient client = ApplicationServer.getInstance().getSQLEngine().getClient(clientID);
client.alert(alertMsg)

But getSQLEngine() doesn’t exist in Servoy 5.2 API (I don’t know why), so I had to modify this line.

Using “trial and error” method, I found that this code could work:

IClient client = ApplicationServer.getInstance().getServerStatus().getClient(clientID);
client.alert(alertMsg)

So I modified the plugin and put it in my plugins folder.

I Developer it woks fine! I created a test solution and I can send messages to client. But when I put the plugin and the solution in Server, I receive this error when I try to send a message (the method __prueba calls method mod_common_sendMsgToClients, then it calls method getClientUserName of my plugin tsappserver to send the message):

----------------------------------------------------
ERROR - Debug                      - com.servoy.j2db.dataprocessing.ClientProxy
org.mozilla.javascript.WrappedException: Wrapped java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
	java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.servoy.j2db.dataprocessing.ClientProxy (mod_common_sendMsgToClients#740)
	at org.mozilla.javascript.Context.throwAsScriptRuntimeEx(Context.java:1828)
	at org.mozilla.javascript.MemberBox.invoke(MemberBox.java:199)
	at org.mozilla.javascript.NativeJavaMethod.call(NativeJavaMethod.java:353)
	at org.mozilla.javascript.optimizer.OptRuntime.callProp0(OptRuntime.java:111)
	at org.mozilla.javascript.gen.c13._c0(mod_common_sendMsgToClients:740)
	at org.mozilla.javascript.gen.c13.call(mod_common_sendMsgToClients)
	at org.mozilla.javascript.optimizer.OptRuntime.call2(OptRuntime.java:73)
	at org.mozilla.javascript.gen.c12._c0(__prueba:48)
	at org.mozilla.javascript.gen.c12.call(__prueba)
	at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:387)
	at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3135)
	at org.mozilla.javascript.gen.c12.call(__prueba)
	at com.servoy.j2db.scripting.ScriptEngine.executeFunction(ScriptEngine.java:476)
	at com.servoy.j2db.FormController.executeFunction(FormController.java:3977)
	at com.servoy.j2db.FormController.executeFunction(FormController.java:3865)
	at com.servoy.j2db.FormController.executeFunction(FormController.java:3787)
	at com.servoy.j2db.FormController$ScriptExecuter.executeFunction(FormController.java:3642)
	at com.servoy.j2db.ui.BaseEventExecutor.fireEventCommand(BaseEventExecutor.java:272)
	at com.servoy.j2db.ui.BaseEventExecutor.fireActionCommand(BaseEventExecutor.java:217)
	at com.servoy.j2db.ui.BaseEventExecutor.fireActionCommand(BaseEventExecutor.java:212)
	at com.servoy.j2db.smart.dataui.AbstractScriptButton$2.actionPerformed(AbstractScriptButton.java:826)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
	at java.awt.Component.processMouseEvent(Component.java:6289)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
	at java.awt.Component.processEvent(Component.java:6054)
	at java.awt.Container.processEvent(Container.java:2041)
	at java.awt.Component.dispatchEventImpl(Component.java:4652)
	at java.awt.Container.dispatchEventImpl(Container.java:2099)
	at java.awt.Component.dispatchEvent(Component.java:4482)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
	at java.awt.Container.dispatchEventImpl(Container.java:2085)
	at java.awt.Window.dispatchEventImpl(Window.java:2478)
	at java.awt.Component.dispatchEvent(Component.java:4482)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:644)
	at java.awt.EventQueue.access$000(EventQueue.java:85)
	at java.awt.EventQueue$1.run(EventQueue.java:603)
	at java.awt.EventQueue$1.run(EventQueue.java:601)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
	at java.awt.EventQueue$2.run(EventQueue.java:617)
	at java.awt.EventQueue$2.run(EventQueue.java:615)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:614)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Caused by: java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
	java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.servoy.j2db.dataprocessing.ClientProxy
	at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
	at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
	at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
	at $Proxy10.getClient(Unknown Source)
	at es.thinksmart.servoy.plugins.tsappserver.JSClient.getClientUserName(JSClient.java:22)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.mozilla.javascript.MemberBox.invoke(MemberBox.java:179)
	... 55 more
Caused by: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.servoy.j2db.dataprocessing.ClientProxy
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1332)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
	at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
	at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:155)
	... 64 more
Caused by: java.io.NotSerializableException: com.servoy.j2db.dataprocessing.ClientProxy
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at sun.rmi.server.UnicastRef.marshalValue(Unknown Source)
	at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
	at sun.rmi.transport.Transport$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

Any ideas? Thanks!

Log-Out,

Does the maintenance plugin not do what you need?

plugins.maintenance.sendMessageToClient(clientId,message)

Rob

I tried it, but it doesn’ work.

The documentation says that you can’t use manteinance plugin in normal context :cry:

Exactly, it only works in pre import en post import methods

Yeap, so I can’t use it (Why Servoy did it?), then I’m looking for a plugin that works in a “normal” contexto…

Log-out,

Ah, I did not know that this plugin is only for import/export.

Use the IServerAccess.sendMessageToClient(String clientId, String message) (since 5.0) method in your server-plugin.

Rob

Ok, but I would like to send a message to a user (not to a clientID), so I have to know which clientID is a user.

So I have a client:

IClient client = ApplicationServer.getInstance().getServerStatus().getClient(clientID);

Then, I can get the username of a client:

String userName = client.getClientInfo().getUserName();

This line of code works fine in Developer, but not in Server

log-out,

Better to use the public api interfaces, all other api may change in a future version:

IClientInformation[] IServerAccess.getConnectedClients();

If you call the methods on IClientInformation in your server-side of your plugin, you should not get this error.

Rob

But, as with maintenance plugin, it doesn’t work in a “normal” context. That code returns nothing :cry:

Log-Out,

That is odd, I just tried that on a small sample, ran it from a webclient on a ServoyServer, returned by connected client.

Rob

You could also have a look at our UserManager plugin. It does what you need plus a few other things as well…

Finally my plugin works. Thanks to Rob for helping me!!!

This is important (but in the public API there’s no information), so I post it here:

rgansevles:
The thing that went wrong in server is that you cannot send the IClientInformation implementation classes over rmi to the smart client (the implementing class is not serializable).
Just move the logic to the server

Regards,

Log-out,
This plugin of yours isn’t a Servoy Forge item is it? I’m looking into creating one of these myself but did not want to reinvent the wheel if need be.

No, it isn’t. I created the plugin just to learn to create plugins in Servoy. I can send you the source, if you wish

Log-Out,
if you want to create a project on ServoyForge, just ask.
Any registered ServoyForge user can open a project there.

log-out:
No, it isn’t. I created the plugin just to learn to create plugins in Servoy. I can send you the source, if you wish

Hi Logout,

Can you share your plugin? I have a similar requirement. This time, I need to shutdown a client connected to another solution.

Thanks!

Ok, I’ll try to put into ServoyForge.

It has no documentation, and the code comments are only in spanish :shock: but I’ll try to document it! Anyway, it’s a very very easy plugin!

Or, if you wish, I can send it to you

Would anyone know which class can I get the solution name where the client is connected or it is complicated logic?

See the public api:
http://www.servoy.com/docs/public-api/6 … Name%28%29

Rob

I revived the old Robot Plugin and comitted it to Servoy Forge. I’ve made the adjustments to get it to work with 5.x, but it probably needs some testing. You can check it out at: https://www.servoyforge.net/projects/robot