Thread: [Py4j-users] An issue in reflection?
Status: Beta
Brought to you by:
barthe
From: Jeremy <ken...@gm...> - 2014-05-06 23:58:43
|
So I'm trying to use Py4j to let a UI talk to a Java server. The java server uses 3 threads (entry-point, server socket, client-event dispatch). The python UI registers an event call back listener and that listener eventually gets dumped into a Vector. I had some initial trouble getting the addEventListener() working but fixed it (somehow). But now any calls to removeEventListener() don't work. My first guess was something to do with different instances of the object when Vector does the lookup, but I'm not sure. I don't understand relfection concepts well enough and the Py->Java (callback) thing seems to suggest I should be fine since the original eventlistener hasn't been garbage collected yet. If you have any insight that would be great. Error: py4j.protocol.Py4JJavaError: An error occurred while calling t.removeEventListener. : py4j.Py4JException: An exception was raised by the Python Proxy. Return Message: x at py4j.Protocol.getReturnValue(Protocol.java:417) at py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:113) at com.sun.proxy.$Proxy0.equals(Unknown Source) at java.util.Vector.indexOf(Vector.java:404) at java.util.Vector.indexOf(Vector.java:378) at java.util.Vector.removeElement(Vector.java:637) at java.util.Vector.remove(Vector.java:795) at pctelelog.EventOperatorThread.removeEventListener(EventOperatorThread.java:20) at pctelelog.ServerThread.removeEventListener(ServerThread.java:16) at pctelelog.Launcher.removeEventListener(Launcher.java:17) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) This code is a stripped down version of the development version but both are generating the same error. package pctelelog; public class Event { public String testData = "test"; } === package pctelelog; public interface EventListener { public void onEvent(Event event); } === package pctelelog; import java.util.Vector; public class EventOperatorThread extends Thread { private Vector<EventListener> m_listeners = new Vector<EventListener>(); public void run() { while(true) {} } public synchronized void addEventListener(EventListener listener) { System.out.println("ADD"); m_listeners.add(listener); } public synchronized void removeEventListener(EventListener listener) { System.out.println("REMOVE"); m_listeners.remove(listener); } } === package pctelelog; public class ServerThread extends Thread { private EventOperatorThread m_operator = new EventOperatorThread(); public void run() { m_operator.start(); while(true) {} } public synchronized void addEventListener(EventListener listener) { m_operator.addEventListener(listener); } public synchronized void removeEventListener(EventListener listener) { m_operator.removeEventListener(listener); } } === package pctelelog; import py4j.GatewayServer; public class Launcher { private ServerThread m_server = new ServerThread(); public Launcher() { m_server.start(); System.out.println("Server started."); } public void addEventListener(EventListener listener) { m_server.addEventListener(listener); } public void removeEventListener(EventListener listener) { m_server.removeEventListener(listener); } public static void main(String[] args) { GatewayServer gateway = new GatewayServer(new Launcher()); gateway.start(); } } === from py4j.java_gateway import JavaGateway, GatewayClient class EventListener(object): def onEvent(self, event): print event.testData; class Java: implements = ['pctelelog.EventListener'] class Launcher: def __init__(self): self.__gateway = JavaGateway(start_callback_server=True) listener = EventListener() self.__gateway.entry_point.addEventListener(listener) self.__gateway.entry_point.removeEventListener(listener) if __name__ == '__main__': Launcher() pass |
From: Barthelemy D. <bar...@in...> - 2014-05-07 11:54:42
|
Hi! Thanks for using Py4J! I'll try to look at this issue more deeply during the weekend, but from the stack trace, it seems the Java side is sending a method call to the Python side and the Python side is replying with an exception: Error: py4j.protocol.Py4JJavaError: An error occurred while calling t.removeEventListener. : py4j.Py4JException: An exception was raised by the Python Proxy. Return Message: x Also, from the stack trace, it appears that when deleting the listener from the Java vector, the vector calls the "equals" method on the listener. This is the first time I have to deal with this scenario and I believe the equals method is delegated to the python side. Because it is not implemented, I believe this may be the cause of failure. A workaround might be to try to implement an "equals" method in your Python listener. Do you have logging enabled on the Python side? Any stack trace visible there? Btw, you should subscribe to the mailing list, it would be easier to manage the replies :-) Bart On Tue, May 6, 2014 at 7:58 PM, Jeremy <ken...@gm...> wrote: > So I'm trying to use Py4j to let a UI talk to a Java server. The java > server uses 3 threads (entry-point, server socket, client-event > dispatch). The python UI registers an event call back listener and that > listener eventually gets dumped into a Vector. I had some initial > trouble getting the addEventListener() working but fixed it (somehow). > But now any calls to removeEventListener() don't work. > > My first guess was something to do with different instances of the > object when Vector does the lookup, but I'm not sure. I don't understand > relfection concepts well enough and the Py->Java (callback) thing seems > to suggest I should be fine since the original eventlistener hasn't been > garbage collected yet. If you have any insight that would be great. > > Error: > py4j.protocol.Py4JJavaError: An error occurred while calling > t.removeEventListener. > : py4j.Py4JException: An exception was raised by the Python Proxy. > Return Message: x > at py4j.Protocol.getReturnValue(Protocol.java:417) > at > py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:113) > at com.sun.proxy.$Proxy0.equals(Unknown Source) > at java.util.Vector.indexOf(Vector.java:404) > at java.util.Vector.indexOf(Vector.java:378) > at java.util.Vector.removeElement(Vector.java:637) > at java.util.Vector.remove(Vector.java:795) > at > pctelelog.EventOperatorThread.removeEventListener(EventOperatorThread.java:20) > at pctelelog.ServerThread.removeEventListener(ServerThread.java:16) > at pctelelog.Launcher.removeEventListener(Launcher.java:17) > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > at > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > > This code is a stripped down version of the development version but both > are generating the same error. > > package pctelelog; > > public class Event { > public String testData = "test"; > } > > === > > package pctelelog; > > public interface EventListener { > public void onEvent(Event event); > } > > === > > package pctelelog; > > import java.util.Vector; > > public class EventOperatorThread extends Thread { > > private Vector<EventListener> m_listeners = new > Vector<EventListener>(); > > public void run() { > while(true) {} > } > > public synchronized void addEventListener(EventListener listener) { > System.out.println("ADD"); > m_listeners.add(listener); > } > > public synchronized void removeEventListener(EventListener listener) { > System.out.println("REMOVE"); > m_listeners.remove(listener); > } > } > > === > > package pctelelog; > > public class ServerThread extends Thread { > > private EventOperatorThread m_operator = new EventOperatorThread(); > > public void run() { > m_operator.start(); > while(true) {} > } > > public synchronized void addEventListener(EventListener listener) { > m_operator.addEventListener(listener); > } > public synchronized void removeEventListener(EventListener listener) { > m_operator.removeEventListener(listener); > } > > } > > === > > package pctelelog; > > import py4j.GatewayServer; > > public class Launcher { > private ServerThread m_server = new ServerThread(); > > public Launcher() { > m_server.start(); > System.out.println("Server started."); > } > > public void addEventListener(EventListener listener) { > m_server.addEventListener(listener); > } > public void removeEventListener(EventListener listener) { > m_server.removeEventListener(listener); > } > > public static void main(String[] args) { > GatewayServer gateway = new GatewayServer(new Launcher()); > gateway.start(); > } > } > > === > > from py4j.java_gateway import JavaGateway, GatewayClient > > class EventListener(object): > > def onEvent(self, event): > print event.testData; > > class Java: > implements = ['pctelelog.EventListener'] > > class Launcher: > > def __init__(self): > self.__gateway = JavaGateway(start_callback_server=True) > listener = EventListener() > self.__gateway.entry_point.addEventListener(listener) > self.__gateway.entry_point.removeEventListener(listener) > > if __name__ == '__main__': > Launcher() > pass > > > ------------------------------------------------------------------------------ > Is your legacy SCM system holding you back? Join Perforce May 7 to find out: > • 3 signs your SCM is hindering your productivity > • Requirements for releasing software faster > • Expert tips and advice for migrating your SCM now > http://p.sf.net/sfu/perforce > _______________________________________________ > Py4j-users mailing list > Py4...@li... > https://lists.sourceforge.net/lists/listinfo/py4j-users |
From: Jeremy <ken...@gm...> - 2014-05-16 23:35:37
|
Sorry for the delayed reply. Been busy, finally got time to work on my project. I looked at the Vector.java code and can see that it calls the Object class method, equals(). So taking your suggestion, I added an equals(Object) method to the interface (not necessary likely) and tried to implement something in the implementing class in Python. Something like: class equals(self, obj): if self == obj: return True return False But still got the same error. Tried adding in Python's global equal, and that didn't work either. And even tried creating a UUID for each EventListener, but that didn't work either. It just can't seem to find the equals method. My final EventListener ended up looking like this. class EventListener(object): id = uuid.uuid4() def onEvent(self, event): pass def equals(self, obj): return __eq__(obj) def __eq__(self, obj): if obj == None: return False if obj.id == self.id: return True else: return False class Java: implements = ['pctelelog.EventListener'] pass My solution that seems to be working now has been to remove passing around an interface and instead rename the interface EventCallback and wrap it inside a new class (EventListener) and pass an object of that class around. It works fine but I have a strange issue now, maybe I'm doing it wrong. Here's my new EventListener.java public class EventListener implements EventCallback { private EventCallback m_callback = null; public EventListener() { } public EventListener(EventCallback callback) { assert callback != null; m_callback = callback; } public void setCallback(EventCallback callback) { m_callback = callback; } public static EventListener createEventListener(EventCallback callback) { return new EventListener(callback); } @Override public void onEvent(AbstractEvent event) { m_callback.onEvent(event); } } Here's the Python I use to get an instance of the class and then add it to the listener pool: (This method sits inside a PyQt Widget class.) def initCallback(self, func): callback = EventCallback() callback.onEvent = self.onEvent self.eventListener = self.__gateway.jvm.pctelelog.EventListener(callback) self.__gateway.entry_point.addEventListener(self.eventListener) When I try to do it like that I get an error (Logger + Error): Callback Server Starting Socket listening on ('127.0.0.1', 25334) Command to send: r u pctelelog rj e Answer received: yp Command to send: r u pctelelog.EventListener rj e Answer received: ycpctelelog.EventListener Traceback (most recent call last): File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", line 27, in <module> Launcher() File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", line 23, in __init__ mainWindow = MainWindow(self.__gateway) File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", line 25, in __init__ self.initCallback(self.onEvent) File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", line 49, in initCallback self.eventListener = self.__gateway.jvm.pctelelog.EventListener(callback) File "/usr/local/lib/python2.7/site-packages/py4j/java_gateway.py", line 662, in __call__ args_command = ''.join([get_command_part(arg) for arg in args]) File "/usr/local/lib/python2.7/site-packages/py4j/protocol.py", line 261, in get_command_part command_part = PYTHON_PROXY_TYPE + python_proxy_pool.put(parameter) AttributeError: 'NoneType' object has no attribute 'put' === Now, if I change it around and instantiate with the void constructor and set the callback with the setter. It works fine. def initCallback(self, func): callback = EventCallback() callback.onEvent = self.onEvent self.eventListener = self.__gateway.jvm.pctelelog.EventListener() self.eventListener.setCallback(callback) self.__gateway.entry_point.addEventListener(self.eventListener) I'd rather do without the setter if there was a way to manage it. Any idea what's going on? Thanks! On 5/7/14, 7:54 AM, Barthelemy Dagenais wrote: > Hi! > > Thanks for using Py4J! I'll try to look at this issue more deeply > during the weekend, but from the stack trace, it seems the Java side > is sending a method call to the Python side and the Python side is > replying with an exception: > > Error: > py4j.protocol.Py4JJavaError: An error occurred while calling > t.removeEventListener. > : py4j.Py4JException: An exception was raised by the Python Proxy. > Return Message: x > > Also, from the stack trace, it appears that when deleting the listener > from the Java vector, the vector calls the "equals" method on the > listener. This is the first time I have to deal with this scenario and > I believe the equals method is delegated to the python side. Because > it is not implemented, I believe this may be the cause of failure. A > workaround might be to try to implement an "equals" method in your > Python listener. > > Do you have logging enabled on the Python side? Any stack trace visible there? > > Btw, you should subscribe to the mailing list, it would be easier to > manage the replies :-) > > Bart > > On Tue, May 6, 2014 at 7:58 PM, Jeremy <ken...@gm...> wrote: >> So I'm trying to use Py4j to let a UI talk to a Java server. The java >> server uses 3 threads (entry-point, server socket, client-event >> dispatch). The python UI registers an event call back listener and that >> listener eventually gets dumped into a Vector. I had some initial >> trouble getting the addEventListener() working but fixed it (somehow). >> But now any calls to removeEventListener() don't work. >> >> My first guess was something to do with different instances of the >> object when Vector does the lookup, but I'm not sure. I don't understand >> relfection concepts well enough and the Py->Java (callback) thing seems >> to suggest I should be fine since the original eventlistener hasn't been >> garbage collected yet. If you have any insight that would be great. >> >> Error: >> py4j.protocol.Py4JJavaError: An error occurred while calling >> t.removeEventListener. >> : py4j.Py4JException: An exception was raised by the Python Proxy. >> Return Message: x >> at py4j.Protocol.getReturnValue(Protocol.java:417) >> at >> py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:113) >> at com.sun.proxy.$Proxy0.equals(Unknown Source) >> at java.util.Vector.indexOf(Vector.java:404) >> at java.util.Vector.indexOf(Vector.java:378) >> at java.util.Vector.removeElement(Vector.java:637) >> at java.util.Vector.remove(Vector.java:795) >> at >> pctelelog.EventOperatorThread.removeEventListener(EventOperatorThread.java:20) >> at pctelelog.ServerThread.removeEventListener(ServerThread.java:16) >> at pctelelog.Launcher.removeEventListener(Launcher.java:17) >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >> at >> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) >> >> This code is a stripped down version of the development version but both >> are generating the same error. >> >> package pctelelog; >> >> public class Event { >> public String testData = "test"; >> } >> >> === >> >> package pctelelog; >> >> public interface EventListener { >> public void onEvent(Event event); >> } >> >> === >> >> package pctelelog; >> >> import java.util.Vector; >> >> public class EventOperatorThread extends Thread { >> >> private Vector<EventListener> m_listeners = new >> Vector<EventListener>(); >> >> public void run() { >> while(true) {} >> } >> >> public synchronized void addEventListener(EventListener listener) { >> System.out.println("ADD"); >> m_listeners.add(listener); >> } >> >> public synchronized void removeEventListener(EventListener listener) { >> System.out.println("REMOVE"); >> m_listeners.remove(listener); >> } >> } >> >> === >> >> package pctelelog; >> >> public class ServerThread extends Thread { >> >> private EventOperatorThread m_operator = new EventOperatorThread(); >> >> public void run() { >> m_operator.start(); >> while(true) {} >> } >> >> public synchronized void addEventListener(EventListener listener) { >> m_operator.addEventListener(listener); >> } >> public synchronized void removeEventListener(EventListener listener) { >> m_operator.removeEventListener(listener); >> } >> >> } >> >> === >> >> package pctelelog; >> >> import py4j.GatewayServer; >> >> public class Launcher { >> private ServerThread m_server = new ServerThread(); >> >> public Launcher() { >> m_server.start(); >> System.out.println("Server started."); >> } >> >> public void addEventListener(EventListener listener) { >> m_server.addEventListener(listener); >> } >> public void removeEventListener(EventListener listener) { >> m_server.removeEventListener(listener); >> } >> >> public static void main(String[] args) { >> GatewayServer gateway = new GatewayServer(new Launcher()); >> gateway.start(); >> } >> } >> >> === >> >> from py4j.java_gateway import JavaGateway, GatewayClient >> >> class EventListener(object): >> >> def onEvent(self, event): >> print event.testData; >> >> class Java: >> implements = ['pctelelog.EventListener'] >> >> class Launcher: >> >> def __init__(self): >> self.__gateway = JavaGateway(start_callback_server=True) >> listener = EventListener() >> self.__gateway.entry_point.addEventListener(listener) >> self.__gateway.entry_point.removeEventListener(listener) >> >> if __name__ == '__main__': >> Launcher() >> pass >> >> >> ------------------------------------------------------------------------------ >> Is your legacy SCM system holding you back? Join Perforce May 7 to find out: >> • 3 signs your SCM is hindering your productivity >> • Requirements for releasing software faster >> • Expert tips and advice for migrating your SCM now >> http://p.sf.net/sfu/perforce >> _______________________________________________ >> Py4j-users mailing list >> Py4...@li... >> https://lists.sourceforge.net/lists/listinfo/py4j-users |
From: Barthelemy D. <bar...@in...> - 2014-05-17 21:18:04
|
Hi, regarding the equals method, I believe you were in the right direction: def equals(self, obj): # obj will be a JavaObject type, so obj is never equal to self return obj is not None and obj.toString() == self.toString() def toString(self): return "Something Unique" In one of your examples, you call __eq__(obj), but it should be self.__eq__(obj) A good practice when you are not sure what is going on is to always wrap your code in: try: # unsafe code except Exception: from traceback import print_exc print_exc() Sometimes, exceptions are swallowed or shadowed by other exceptions and this is a trick that saved me a lot of time in the past ;-) Finally, I'm not sure why you need the setter (vs the constructor with the parameter). I'll need to investigate and I'll try to get back to you this week. Thanks, Bart On Fri, May 16, 2014 at 7:35 PM, Jeremy <ken...@gm...> wrote: > Sorry for the delayed reply. Been busy, finally got time to work on my > project. > > I looked at the Vector.java code and can see that it calls the Object > class method, equals(). > So taking your suggestion, I added an equals(Object) method to the > interface (not necessary likely) and tried to implement something in the > implementing class in Python. Something like: > > class equals(self, obj): > if self == obj: > return True > return False > > But still got the same error. Tried adding in Python's global equal, and > that didn't work either. And even tried creating a UUID for each > EventListener, but that didn't work either. It just can't seem to find > the equals method. My final EventListener ended up looking like this. > > class EventListener(object): > id = uuid.uuid4() > > def onEvent(self, event): > pass > > def equals(self, obj): > return __eq__(obj) > > def __eq__(self, obj): > if obj == None: > return False > > if obj.id == self.id: > return True > else: > return False > > class Java: > implements = ['pctelelog.EventListener'] > > pass > > > My solution that seems to be working now has been to remove passing > around an interface and instead rename the interface EventCallback and > wrap it inside a new class (EventListener) and pass an object of that > class around. It works fine but I have a strange issue now, maybe I'm > doing it wrong. > > Here's my new EventListener.java > public class EventListener implements EventCallback { > > private EventCallback m_callback = null; > > public EventListener() { > } > > public EventListener(EventCallback callback) { > assert callback != null; > > m_callback = callback; > } > > public void setCallback(EventCallback callback) { > m_callback = callback; > } > > public static EventListener createEventListener(EventCallback > callback) { > return new EventListener(callback); > } > > @Override > public void onEvent(AbstractEvent event) { > m_callback.onEvent(event); > } > } > > Here's the Python I use to get an instance of the class and then add it > to the listener pool: > (This method sits inside a PyQt Widget class.) > > def initCallback(self, func): > callback = EventCallback() > callback.onEvent = self.onEvent > self.eventListener = > self.__gateway.jvm.pctelelog.EventListener(callback) > self.__gateway.entry_point.addEventListener(self.eventListener) > > > When I try to do it like that I get an error (Logger + Error): > > Callback Server Starting > Socket listening on ('127.0.0.1', 25334) > Command to send: r > u > pctelelog > rj > e > > Answer received: yp > Command to send: r > u > pctelelog.EventListener > rj > e > > Answer received: ycpctelelog.EventListener > Traceback (most recent call last): > File > "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", > line 27, in <module> > Launcher() > File > "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", > line 23, in __init__ > mainWindow = MainWindow(self.__gateway) > File > "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", > line 25, in __init__ > self.initCallback(self.onEvent) > File > "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", > line 49, in initCallback > self.eventListener = > self.__gateway.jvm.pctelelog.EventListener(callback) > File "/usr/local/lib/python2.7/site-packages/py4j/java_gateway.py", > line 662, in __call__ > args_command = ''.join([get_command_part(arg) for arg in args]) > File "/usr/local/lib/python2.7/site-packages/py4j/protocol.py", line > 261, in get_command_part > command_part = PYTHON_PROXY_TYPE + python_proxy_pool.put(parameter) > AttributeError: 'NoneType' object has no attribute 'put' > > === > Now, if I change it around and instantiate with the void constructor and > set the callback with the setter. It works fine. > > def initCallback(self, func): > callback = EventCallback() > callback.onEvent = self.onEvent > self.eventListener = self.__gateway.jvm.pctelelog.EventListener() > self.eventListener.setCallback(callback) > self.__gateway.entry_point.addEventListener(self.eventListener) > > I'd rather do without the setter if there was a way to manage it. Any > idea what's going on? > > > Thanks! > > On 5/7/14, 7:54 AM, Barthelemy Dagenais wrote: >> Hi! >> >> Thanks for using Py4J! I'll try to look at this issue more deeply >> during the weekend, but from the stack trace, it seems the Java side >> is sending a method call to the Python side and the Python side is >> replying with an exception: >> >> Error: >> py4j.protocol.Py4JJavaError: An error occurred while calling >> t.removeEventListener. >> : py4j.Py4JException: An exception was raised by the Python Proxy. >> Return Message: x >> >> Also, from the stack trace, it appears that when deleting the listener >> from the Java vector, the vector calls the "equals" method on the >> listener. This is the first time I have to deal with this scenario and >> I believe the equals method is delegated to the python side. Because >> it is not implemented, I believe this may be the cause of failure. A >> workaround might be to try to implement an "equals" method in your >> Python listener. >> >> Do you have logging enabled on the Python side? Any stack trace visible there? >> >> Btw, you should subscribe to the mailing list, it would be easier to >> manage the replies :-) >> >> Bart >> >> On Tue, May 6, 2014 at 7:58 PM, Jeremy <ken...@gm...> wrote: >>> So I'm trying to use Py4j to let a UI talk to a Java server. The java >>> server uses 3 threads (entry-point, server socket, client-event >>> dispatch). The python UI registers an event call back listener and that >>> listener eventually gets dumped into a Vector. I had some initial >>> trouble getting the addEventListener() working but fixed it (somehow). >>> But now any calls to removeEventListener() don't work. >>> >>> My first guess was something to do with different instances of the >>> object when Vector does the lookup, but I'm not sure. I don't understand >>> relfection concepts well enough and the Py->Java (callback) thing seems >>> to suggest I should be fine since the original eventlistener hasn't been >>> garbage collected yet. If you have any insight that would be great. >>> >>> Error: >>> py4j.protocol.Py4JJavaError: An error occurred while calling >>> t.removeEventListener. >>> : py4j.Py4JException: An exception was raised by the Python Proxy. >>> Return Message: x >>> at py4j.Protocol.getReturnValue(Protocol.java:417) >>> at >>> py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:113) >>> at com.sun.proxy.$Proxy0.equals(Unknown Source) >>> at java.util.Vector.indexOf(Vector.java:404) >>> at java.util.Vector.indexOf(Vector.java:378) >>> at java.util.Vector.removeElement(Vector.java:637) >>> at java.util.Vector.remove(Vector.java:795) >>> at >>> pctelelog.EventOperatorThread.removeEventListener(EventOperatorThread.java:20) >>> at pctelelog.ServerThread.removeEventListener(ServerThread.java:16) >>> at pctelelog.Launcher.removeEventListener(Launcher.java:17) >>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >>> at >>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) >>> >>> This code is a stripped down version of the development version but both >>> are generating the same error. >>> >>> package pctelelog; >>> >>> public class Event { >>> public String testData = "test"; >>> } >>> >>> === >>> >>> package pctelelog; >>> >>> public interface EventListener { >>> public void onEvent(Event event); >>> } >>> >>> === >>> >>> package pctelelog; >>> >>> import java.util.Vector; >>> >>> public class EventOperatorThread extends Thread { >>> >>> private Vector<EventListener> m_listeners = new >>> Vector<EventListener>(); >>> >>> public void run() { >>> while(true) {} >>> } >>> >>> public synchronized void addEventListener(EventListener listener) { >>> System.out.println("ADD"); >>> m_listeners.add(listener); >>> } >>> >>> public synchronized void removeEventListener(EventListener listener) { >>> System.out.println("REMOVE"); >>> m_listeners.remove(listener); >>> } >>> } >>> >>> === >>> >>> package pctelelog; >>> >>> public class ServerThread extends Thread { >>> >>> private EventOperatorThread m_operator = new EventOperatorThread(); >>> >>> public void run() { >>> m_operator.start(); >>> while(true) {} >>> } >>> >>> public synchronized void addEventListener(EventListener listener) { >>> m_operator.addEventListener(listener); >>> } >>> public synchronized void removeEventListener(EventListener listener) { >>> m_operator.removeEventListener(listener); >>> } >>> >>> } >>> >>> === >>> >>> package pctelelog; >>> >>> import py4j.GatewayServer; >>> >>> public class Launcher { >>> private ServerThread m_server = new ServerThread(); >>> >>> public Launcher() { >>> m_server.start(); >>> System.out.println("Server started."); >>> } >>> >>> public void addEventListener(EventListener listener) { >>> m_server.addEventListener(listener); >>> } >>> public void removeEventListener(EventListener listener) { >>> m_server.removeEventListener(listener); >>> } >>> >>> public static void main(String[] args) { >>> GatewayServer gateway = new GatewayServer(new Launcher()); >>> gateway.start(); >>> } >>> } >>> >>> === >>> >>> from py4j.java_gateway import JavaGateway, GatewayClient >>> >>> class EventListener(object): >>> >>> def onEvent(self, event): >>> print event.testData; >>> >>> class Java: >>> implements = ['pctelelog.EventListener'] >>> >>> class Launcher: >>> >>> def __init__(self): >>> self.__gateway = JavaGateway(start_callback_server=True) >>> listener = EventListener() >>> self.__gateway.entry_point.addEventListener(listener) >>> self.__gateway.entry_point.removeEventListener(listener) >>> >>> if __name__ == '__main__': >>> Launcher() >>> pass >>> >>> >>> ------------------------------------------------------------------------------ >>> Is your legacy SCM system holding you back? Join Perforce May 7 to find out: >>> • 3 signs your SCM is hindering your productivity >>> • Requirements for releasing software faster >>> • Expert tips and advice for migrating your SCM now >>> http://p.sf.net/sfu/perforce >>> _______________________________________________ >>> Py4j-users mailing list >>> Py4...@li... >>> https://lists.sourceforge.net/lists/listinfo/py4j-users > > > ------------------------------------------------------------------------------ > "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE > Instantly run your Selenium tests across 300+ browser/OS combos. > Get unparalleled scalability from the best Selenium testing platform available > Simple to use. Nothing to install. Get started now for free." > http://p.sf.net/sfu/SauceLabs > _______________________________________________ > Py4j-users mailing list > Py4...@li... > https://lists.sourceforge.net/lists/listinfo/py4j-users |
From: Jeremy <ken...@gm...> - 2014-05-18 03:01:18
|
Hah, turns out it was the missing 'self.' changed it to self.__eq__(obj) and it works! (Getting my Java and Python mixed up.) Its great that I can just pass around the interface now. There's one last thing that has been confusing me and that is launching the server using the java_gateway.launch_gateway(). I've been trying to start the app using that instead of manually calling the popen() myself. My directory layout looks like this: root | | -Launcher.py | -MainWindow.py | -Other stuff .py | lib \ | -common-codec.jar | -jackson-core.jar | -py4j-0.8.1.jar | -pctelelog-gateway-server.jar | -Other dependencies for gateway server Looking at the documentation for launch_gateway() I decided to try using this in my Launcher. self.__gateway = JavaGateway.launch_gateway(jarpath="./lib/pctelelog-gateway-server.jar", classpath="pctelelog.TeleLogPy4jLauncher", die_on_exit=True) TeleLogPy4jLauncher.java (inside the pctelelog-gateway-server.jar) package pctelelog; /*Imports*/ public class TeleLogPy4jLauncher implements GatewayServerListener { private static Logger logger = LogManager.getLogger(TeleLogPy4jLauncher.class); private static TeleLogServer m_telelogServer = new TeleLogServer(); public TeleLogPy4jLauncher() { logger.info("Logging started."); m_telelogServer.start(); } public void addEventListener(EventListener listener) { logger.info("Listener added."); m_telelogServer.addEventListener(listener); } public void removeEventListener(EventListener listener) { logger.info("Listener removed."); m_telelogServer.removeEventListener(listener); } public static void main(String[] args) { TeleLogPy4jLauncher launcher = new TeleLogPy4jLauncher(); GatewayServer gateway = new GatewayServer(launcher); gateway.addListener(launcher); gateway.start(); } /* GatewayListener implementations */ } When I run Launcher.py I get a StringIndexOutofBoundsException when the addEventListener is called in my MainWindow initCallback(). If I launch the JAR manually everything works fine. So I feel like there must be something I'm misunderstanding about the way to use launch_gateway. Maybe it won't work with my server inside a jar? Thanks for the help and patience so far! Jeremy On 5/17/14, 5:17 PM, Barthelemy Dagenais wrote: > Hi, > > regarding the equals method, I believe you were in the right direction: > > def equals(self, obj): > # obj will be a JavaObject type, so obj is never equal to self > return obj is not None and obj.toString() == self.toString() > > def toString(self): > return "Something Unique" > > In one of your examples, you call __eq__(obj), but it should be self.__eq__(obj) > > A good practice when you are not sure what is going on is to always > wrap your code in: > > try: > # unsafe code > except Exception: > from traceback import print_exc > print_exc() > > Sometimes, exceptions are swallowed or shadowed by other exceptions > and this is a trick that saved me a lot of time in the past ;-) > > Finally, I'm not sure why you need the setter (vs the constructor with > the parameter). I'll need to investigate and I'll try to get back to > you this week. > > Thanks, > Bart > > > On Fri, May 16, 2014 at 7:35 PM, Jeremy <ken...@gm...> wrote: >> Sorry for the delayed reply. Been busy, finally got time to work on my >> project. >> >> I looked at the Vector.java code and can see that it calls the Object >> class method, equals(). >> So taking your suggestion, I added an equals(Object) method to the >> interface (not necessary likely) and tried to implement something in the >> implementing class in Python. Something like: >> >> class equals(self, obj): >> if self == obj: >> return True >> return False >> >> But still got the same error. Tried adding in Python's global equal, and >> that didn't work either. And even tried creating a UUID for each >> EventListener, but that didn't work either. It just can't seem to find >> the equals method. My final EventListener ended up looking like this. >> >> class EventListener(object): >> id = uuid.uuid4() >> >> def onEvent(self, event): >> pass >> >> def equals(self, obj): >> return __eq__(obj) >> >> def __eq__(self, obj): >> if obj == None: >> return False >> >> if obj.id == self.id: >> return True >> else: >> return False >> >> class Java: >> implements = ['pctelelog.EventListener'] >> >> pass >> >> >> My solution that seems to be working now has been to remove passing >> around an interface and instead rename the interface EventCallback and >> wrap it inside a new class (EventListener) and pass an object of that >> class around. It works fine but I have a strange issue now, maybe I'm >> doing it wrong. >> >> Here's my new EventListener.java >> public class EventListener implements EventCallback { >> >> private EventCallback m_callback = null; >> >> public EventListener() { >> } >> >> public EventListener(EventCallback callback) { >> assert callback != null; >> >> m_callback = callback; >> } >> >> public void setCallback(EventCallback callback) { >> m_callback = callback; >> } >> >> public static EventListener createEventListener(EventCallback >> callback) { >> return new EventListener(callback); >> } >> >> @Override >> public void onEvent(AbstractEvent event) { >> m_callback.onEvent(event); >> } >> } >> >> Here's the Python I use to get an instance of the class and then add it >> to the listener pool: >> (This method sits inside a PyQt Widget class.) >> >> def initCallback(self, func): >> callback = EventCallback() >> callback.onEvent = self.onEvent >> self.eventListener = >> self.__gateway.jvm.pctelelog.EventListener(callback) >> self.__gateway.entry_point.addEventListener(self.eventListener) >> >> >> When I try to do it like that I get an error (Logger + Error): >> >> Callback Server Starting >> Socket listening on ('127.0.0.1', 25334) >> Command to send: r >> u >> pctelelog >> rj >> e >> >> Answer received: yp >> Command to send: r >> u >> pctelelog.EventListener >> rj >> e >> >> Answer received: ycpctelelog.EventListener >> Traceback (most recent call last): >> File >> "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", >> line 27, in <module> >> Launcher() >> File >> "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", >> line 23, in __init__ >> mainWindow = MainWindow(self.__gateway) >> File >> "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", >> line 25, in __init__ >> self.initCallback(self.onEvent) >> File >> "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", >> line 49, in initCallback >> self.eventListener = >> self.__gateway.jvm.pctelelog.EventListener(callback) >> File "/usr/local/lib/python2.7/site-packages/py4j/java_gateway.py", >> line 662, in __call__ >> args_command = ''.join([get_command_part(arg) for arg in args]) >> File "/usr/local/lib/python2.7/site-packages/py4j/protocol.py", line >> 261, in get_command_part >> command_part = PYTHON_PROXY_TYPE + python_proxy_pool.put(parameter) >> AttributeError: 'NoneType' object has no attribute 'put' >> >> === >> Now, if I change it around and instantiate with the void constructor and >> set the callback with the setter. It works fine. >> >> def initCallback(self, func): >> callback = EventCallback() >> callback.onEvent = self.onEvent >> self.eventListener = self.__gateway.jvm.pctelelog.EventListener() >> self.eventListener.setCallback(callback) >> self.__gateway.entry_point.addEventListener(self.eventListener) >> >> I'd rather do without the setter if there was a way to manage it. Any >> idea what's going on? >> >> >> Thanks! >> >> On 5/7/14, 7:54 AM, Barthelemy Dagenais wrote: >>> Hi! >>> >>> Thanks for using Py4J! I'll try to look at this issue more deeply >>> during the weekend, but from the stack trace, it seems the Java side >>> is sending a method call to the Python side and the Python side is >>> replying with an exception: >>> >>> Error: >>> py4j.protocol.Py4JJavaError: An error occurred while calling >>> t.removeEventListener. >>> : py4j.Py4JException: An exception was raised by the Python Proxy. >>> Return Message: x >>> >>> Also, from the stack trace, it appears that when deleting the listener >>> from the Java vector, the vector calls the "equals" method on the >>> listener. This is the first time I have to deal with this scenario and >>> I believe the equals method is delegated to the python side. Because >>> it is not implemented, I believe this may be the cause of failure. A >>> workaround might be to try to implement an "equals" method in your >>> Python listener. >>> >>> Do you have logging enabled on the Python side? Any stack trace visible there? >>> >>> Btw, you should subscribe to the mailing list, it would be easier to >>> manage the replies :-) >>> >>> Bart >>> >>> On Tue, May 6, 2014 at 7:58 PM, Jeremy <ken...@gm...> wrote: >>>> So I'm trying to use Py4j to let a UI talk to a Java server. The java >>>> server uses 3 threads (entry-point, server socket, client-event >>>> dispatch). The python UI registers an event call back listener and that >>>> listener eventually gets dumped into a Vector. I had some initial >>>> trouble getting the addEventListener() working but fixed it (somehow). >>>> But now any calls to removeEventListener() don't work. >>>> >>>> My first guess was something to do with different instances of the >>>> object when Vector does the lookup, but I'm not sure. I don't understand >>>> relfection concepts well enough and the Py->Java (callback) thing seems >>>> to suggest I should be fine since the original eventlistener hasn't been >>>> garbage collected yet. If you have any insight that would be great. >>>> >>>> Error: >>>> py4j.protocol.Py4JJavaError: An error occurred while calling >>>> t.removeEventListener. >>>> : py4j.Py4JException: An exception was raised by the Python Proxy. >>>> Return Message: x >>>> at py4j.Protocol.getReturnValue(Protocol.java:417) >>>> at >>>> py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:113) >>>> at com.sun.proxy.$Proxy0.equals(Unknown Source) >>>> at java.util.Vector.indexOf(Vector.java:404) >>>> at java.util.Vector.indexOf(Vector.java:378) >>>> at java.util.Vector.removeElement(Vector.java:637) >>>> at java.util.Vector.remove(Vector.java:795) >>>> at >>>> pctelelog.EventOperatorThread.removeEventListener(EventOperatorThread.java:20) >>>> at pctelelog.ServerThread.removeEventListener(ServerThread.java:16) >>>> at pctelelog.Launcher.removeEventListener(Launcher.java:17) >>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >>>> at >>>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) >>>> >>>> This code is a stripped down version of the development version but both >>>> are generating the same error. >>>> >>>> package pctelelog; >>>> >>>> public class Event { >>>> public String testData = "test"; >>>> } >>>> >>>> === >>>> >>>> package pctelelog; >>>> >>>> public interface EventListener { >>>> public void onEvent(Event event); >>>> } >>>> >>>> === >>>> >>>> package pctelelog; >>>> >>>> import java.util.Vector; >>>> >>>> public class EventOperatorThread extends Thread { >>>> >>>> private Vector<EventListener> m_listeners = new >>>> Vector<EventListener>(); >>>> >>>> public void run() { >>>> while(true) {} >>>> } >>>> >>>> public synchronized void addEventListener(EventListener listener) { >>>> System.out.println("ADD"); >>>> m_listeners.add(listener); >>>> } >>>> >>>> public synchronized void removeEventListener(EventListener listener) { >>>> System.out.println("REMOVE"); >>>> m_listeners.remove(listener); >>>> } >>>> } >>>> >>>> === >>>> >>>> package pctelelog; >>>> >>>> public class ServerThread extends Thread { >>>> >>>> private EventOperatorThread m_operator = new EventOperatorThread(); >>>> >>>> public void run() { >>>> m_operator.start(); >>>> while(true) {} >>>> } >>>> >>>> public synchronized void addEventListener(EventListener listener) { >>>> m_operator.addEventListener(listener); >>>> } >>>> public synchronized void removeEventListener(EventListener listener) { >>>> m_operator.removeEventListener(listener); >>>> } >>>> >>>> } >>>> >>>> === >>>> >>>> package pctelelog; >>>> >>>> import py4j.GatewayServer; >>>> >>>> public class Launcher { >>>> private ServerThread m_server = new ServerThread(); >>>> >>>> public Launcher() { >>>> m_server.start(); >>>> System.out.println("Server started."); >>>> } >>>> >>>> public void addEventListener(EventListener listener) { >>>> m_server.addEventListener(listener); >>>> } >>>> public void removeEventListener(EventListener listener) { >>>> m_server.removeEventListener(listener); >>>> } >>>> >>>> public static void main(String[] args) { >>>> GatewayServer gateway = new GatewayServer(new Launcher()); >>>> gateway.start(); >>>> } >>>> } >>>> >>>> === >>>> >>>> from py4j.java_gateway import JavaGateway, GatewayClient >>>> >>>> class EventListener(object): >>>> >>>> def onEvent(self, event): >>>> print event.testData; >>>> >>>> class Java: >>>> implements = ['pctelelog.EventListener'] >>>> >>>> class Launcher: >>>> >>>> def __init__(self): >>>> self.__gateway = JavaGateway(start_callback_server=True) >>>> listener = EventListener() >>>> self.__gateway.entry_point.addEventListener(listener) >>>> self.__gateway.entry_point.removeEventListener(listener) >>>> >>>> if __name__ == '__main__': >>>> Launcher() >>>> pass >>>> >>>> >>>> ------------------------------------------------------------------------------ >>>> Is your legacy SCM system holding you back? Join Perforce May 7 to find out: >>>> • 3 signs your SCM is hindering your productivity >>>> • Requirements for releasing software faster >>>> • Expert tips and advice for migrating your SCM now >>>> http://p.sf.net/sfu/perforce >>>> _______________________________________________ >>>> Py4j-users mailing list >>>> Py4...@li... >>>> https://lists.sourceforge.net/lists/listinfo/py4j-users >> >> ------------------------------------------------------------------------------ >> "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE >> Instantly run your Selenium tests across 300+ browser/OS combos. >> Get unparalleled scalability from the best Selenium testing platform available >> Simple to use. Nothing to install. Get started now for free." >> http://p.sf.net/sfu/SauceLabs >> _______________________________________________ >> Py4j-users mailing list >> Py4...@li... >> https://lists.sourceforge.net/lists/listinfo/py4j-users > ------------------------------------------------------------------------------ > "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE > Instantly run your Selenium tests across 300+ browser/OS combos. > Get unparalleled scalability from the best Selenium testing platform available > Simple to use. Nothing to install. Get started now for free." > http://p.sf.net/sfu/SauceLabs > _______________________________________________ > Py4j-users mailing list > Py4...@li... > https://lists.sourceforge.net/lists/listinfo/py4j-users |