Furthermore... I changed things up a bit, to use a Queue, disable
async and then call listener.pong() in a separate thread and it works
fine.
And after digging up LINGO-29, I tried using Lingo 1.1 and it works
fine with the async invoke passing the callback, and invoking the
callback in the same thread as the async invoke.
I also tried 1.2 and 1.2.1, both appears to have the same deficiency
as 1.3. So it appears that sometime after 1.1 as released this
functionality has broken.
Anyone know how to o about fixing this?
--jason
On Nov 2, 2006, at 7:48 PM, Jason Dillon wrote:
Hrm... I played around with this more... and I found that using a
topic, that if I comment the listener.pong() that everything works,
w/o exceptions.
I also read over this article:
http://jroller.com/page/sjivan?
entry=asynchronous_calls_and_callbacks_using
Which was very good, and I played with the example... which appears
to be working too.
So, maybe the problem is the async invoke which is carrying the
callback object is not getting registered properly? Or maybe its
not possible to use callbacks from async invocations?
I also noticed that in the example, it uses
"remoteInvocationFactory" instead of "metadataStratagy" on the bean
proxy:
<bean id="invocationFactory"
class="org.logicblaze.lingo.LingoRemoteInvocationFactory">
<constructor-arg>
<bean class="org.logicblaze.lingo.SimpleMetadataStrategy">
<!-- enable async one ways -->
<constructor-arg value="true"/>
</bean>
</constructor-arg>
</bean>
What is the difference?
Are callback objects not allowed to be used in the same context of
an invocation? I tried spinning off a new thread to invoke
listener.pong(), but it produced the same "destination must be
specified" problem, but with a shorter trace:
<snip>
Exception in thread "Thread-4"
java.lang.UnsupportedOperationException: A destination must be
specified.
at org.apache.activemq.ActiveMQMessageProducer.send
(ActiveMQMessageProducer.java:448)
at org.logicblaze.lingo.jms.impl.OneWayRequestor.doSend
(OneWayRequestor.java:196)
at
org.logicblaze.lingo.jms.impl.MultiplexingRequestor.doSend
(MultiplexingRequestor.java:189)
at org.logicblaze.lingo.jms.impl.OneWayRequestor.send
(OneWayRequestor.java:101)
at org.logicblaze.lingo.jms.impl.OneWayRequestor.send
(OneWayRequestor.java:97)
at
org.logicblaze.lingo.jms.impl.MultiplexingRequestor.request
(MultiplexingRequestor.java:122)
at org.logicblaze.lingo.jms.JmsClientInterceptor.invoke
(JmsClientInterceptor.java:138)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed
(ReflectiveMethodInvocation.java:185)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke
(JdkDynamicAopProxy.java:209)
at $Proxy6.pong(Unknown Source)
at org.apache.geronimo.gbuild.ping.PingResponderImpl$1.run
(PingResponderImpl.java:49)
</snip>
I'd really like to get callbacks working from async invocations, as
it makes a lot of sense when dealing with an unknown number of
remote nodes where some transient processing needs to be done. The
only other way I can think of to do the same thing would be to
create services, proxies and destinations for the responses...
which will get out of hand quite easily and may have other issues
with synchronizing up with the correct originating client that
initiated the messages.
So... I think callbacks using temporary destinations is really
ideal. But how do I tell a bunch of nodes to do something and pass
them a callback from a single invoke?
--jason
On Nov 2, 2006, at 3:57 PM, Jason Dillon wrote:
Hi folks, I am trying to figure out some of the more advanced
Lingo usage... trying to get a simple working example of
EventListener remoting, but so far I have had no luck.
I'm trying to get a super-simple ping/pong from a client to a set
of nodes listening on a topic, where the invocation is one-way,
and the server's ping responder will invoke a method on an ping
listener to send its pong.
This is what I've got:
<snip>
public interface PingListener
extends EventListener
{
void pong();
}
public interface PingResponder
{
void ping(PingListener listener);
}
public class PingResponderImpl
implements PingResponder
{
public void ping(final PingListener listener) {
log.info("Responding to PING")
listener.pong();
}
}
</snip>
My client is also simple, though in this example I've trimmed out
the bits which load the spring ctx and autowire the components:
<snip>
public class PingClient
{
public void ping() {
PingCollector collector = new PingCollector();
responder.ping(collector);
// wait for ctrl-c to end
}
public class PingCollector
implements PingListener
{
public void pong() {
log.info("Received PONG");
}
}
}
</snip>
And then the spring ctx:
<snip>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/
beans http://www.springframework.org/schema/beans/spring-
beans-2.0.xsd">
<bean id="jmsFactory"
class="org.apache.activemq.ActiveMQConnectionFactory"
scope="singleton">
<property name="brokerURL" value="vm://localhost?
broker.persistent=false"/>
</bean>
<bean id="pingResponderDestination"
class="org.apache.activemq.command.ActiveMQTopic" scope="singleton">
<constructor-arg index="0" value="gbuild.pingResponder"/>
</bean>
<bean id="pingResponder"
class="org.logicblaze.lingo.jms.JmsProxyFactoryBean">
<property name="serviceInterface"
value="org.apache.geronimo.gbuild.ping.PingResponder"/>
<property name="connectionFactory" ref="jmsFactory"/>
<property name="destination" ref="pingResponderDestination"/>
</bean>
<bean id="pingReponderImpl"
class="org.apache.geronimo.gbuild.ping.PingResponderImpl"
scope="singleton"/>
<bean id="pingReponderService"
class="org.logicblaze.lingo.jms.JmsServiceExporter"
scope="singleton">
<property name="service" ref="pingReponderImpl"/>
<property name="serviceInterface"
value="org.apache.geronimo.gbuild.ping.PingResponder"/>
<property name="connectionFactory" ref="jmsFactory"/>
<property name="destination" ref="pingResponderDestination"/>
</bean>
</beans>
</snip>
In this configuration, I see the "Responding to PING" and
"Received PONG" log messages, which is followed by some exceptions
after a delay:
<snip>
15:39:43,075 WARN [JmsClientInterceptor] Remote access error:
invocation: method 'pong', arguments []; target is null
javax.jms.JMSException:
edu.emory.mathcs.backport.java.util.concurrent.TimeoutException
at
org.logicblaze.lingo.jms.impl.MultiplexingRequestor.createJMSExceptio
n(MultiplexingRequestor.java:205)
at
org.logicblaze.lingo.jms.impl.MultiplexingRequestor.request
(MultiplexingRequestor.java:133)
at org.logicblaze.lingo.jms.JmsClientInterceptor.invoke
(JmsClientInterceptor.java:138)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(
ReflectiveMethodInvocation.java:185)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke
(JdkDynamicAopProxy.java:209)
at $Proxy6.pong(Unknown Source)
...
</snip>
And then a warning from the MultiplexingRequestor:
<snip>
15:39:43,113 WARN [MultiplexingRequestor] Response received for
unknown correlationID: 2 request: ActiveMQObjectMessage {commandId
= 9, responseRequired = true, messageId =
ID:Bliss.local-52836-1162510752209-2:6:1:1:2, originalDestination
= null, originalTransactionId = null, producerId =
ID:Bliss.local-52836-1162510752209-2:6:1:1, destination = temp-
queue://ID:Bliss.local-52836-1162510752209-2:13:1, transactionId =
null, expiration = 1162510813098, timestamp = 1162510783104,
arrival = 0, correlationId = 2, replyTo = null, persistent = true,
type = null, priority = 4, groupID = null, groupSequence = 0,
targetConsumerId = null, compressed = false, userID = null,
content = [EMAIL PROTECTED],
marshalledProperties = null, dataStructure = null,
redeliveryCounter = 0, size = 12390, properties = null,
readOnlyProperties = true, readOnlyBody = true, droppable = false}
</snip>
And at this point, the method call to responder.ping() is still
blocking.
If I change the destination to use a queue, then I get the same
timeout trace, but the call to responder.ping() unblocks due to
the JMSException being propagated.
If I enable a metadata strategy to make this async for one way
voids, with something like:
<snip>
<bean id="pingResponder"
class="org.logicblaze.lingo.jms.JmsProxyFactoryBean">
<property name="serviceInterface"
value="org.apache.geronimo.gbuild.ping.PingResponder"/>
<property name="connectionFactory" ref="jmsFactory"/>
<property name="destination" ref="pingResponderDestination"/>
<property name="metadataStrategy">
<bean
class="org.logicblaze.lingo.SimpleMetadataStrategy">
<constructor-arg value="true"/>
</bean>
</property>
</bean>
</snip>
The I see the "Responding to PING" but right after I get this
exception:
<snip>
15:46:35,401 WARN [RemoteInvocationTraceInterceptor] Processing
of JmsServiceExporter remote call resulted in fatal exception:
org.apache.geronimo.gbuild.ping.PingResponder.ping
java.lang.UnsupportedOperationException: A destination must be
specified.
at org.apache.activemq.ActiveMQMessageProducer.send
(ActiveMQMessageProducer.java:448)
at org.logicblaze.lingo.jms.impl.OneWayRequestor.doSend
(OneWayRequestor.java:196)
at
org.logicblaze.lingo.jms.impl.MultiplexingRequestor.doSend
(MultiplexingRequestor.java:189)
at org.logicblaze.lingo.jms.impl.OneWayRequestor.send
(OneWayRequestor.java:101)
at org.logicblaze.lingo.jms.impl.OneWayRequestor.send
(OneWayRequestor.java:97)
at
org.logicblaze.lingo.jms.impl.MultiplexingRequestor.request
(MultiplexingRequestor.java:122)
at org.logicblaze.lingo.jms.JmsClientInterceptor.invoke
(JmsClientInterceptor.java:138)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(
ReflectiveMethodInvocation.java:185)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke
(JdkDynamicAopProxy.java:209)
at $Proxy6.pong(Unknown Source)
...
</snip>
I am using Apple's JDK 1.5, Lingo 1.3 and Spring 2.0. Other
simple sync invocations work fine... but I really need to get
something working for more complicated invocations to and from an
arbitrary set of nodes.
Does anyone have any ideas how to get this working? I have been
digging around in the lingo svn, looking at the tests. Looks like
there is a test that uses an EventListener... and it appears to
pass, but I don't know what I am doing differently.
I've also been looking for other input on the lingo nabble
forums... but so far... no luck.
Any help is appreciated.
Thanks,
--jason