Ah interesting... it's ActiveMQ code that is throwing the exception... As per the JMS contract, the Qpid message producer is setting the JMSDestination on the message it is sending (in this case a foreign message, namely an ActiveMQ message). The ActiveMQ message class doesn't seem to like having a destination set on it which isn't one that it can resolve (even though it doesn't need to). The code in question appears to be here in the activeMQ codebase:
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.activemq/activemq-core/5.6.0/org/apache/activemq/command/DefaultUnresolvedDestinationTransformer.java It looks like ActiveMQ is requiring Queue and Topic implementations to implement the methods isQueue() and/or isTopic()... but these are not part of the API defined for JMS Queues and topics AFAIK (see http://docs.oracle.com/javaee/6/api/javax/jms/Queue.html for example). So I think that ActiveMQ is in error / violation of the JMS spec here (though Robbie who has been reading the JMS spec carefully lately may be able to give better advice). If ActiveMQ is absolutely determined to turn the destination object into an ActiveMQ one, I'm not entirely sure why the ActiveMQ code doesn't fall back to an instanceof test to determine whether the the passed in Destination is a Queue (or if not a Topic)... -- Rob On 19 February 2014 20:01, Mark Barker <[email protected]> wrote: > Hi Rob, > > Here is the stack trace. The line (72) in Listener.java (app code) that is > failing is just: > > messageProducer2.send(msg); > > where messageProducer2 is a MessageProducer from the Qpid > connection/session, > and msg is just a "Message" which was received from Q1 just prior, via the > Openwire transport (from its own connection/session). > > javax.jms.JMSException: Unresolvable destination: > org.apache.qpid.amqp_1_0.jms.impl.QueueImpl.isQueue(): > org.apache.qpid.amqp_1_0.jms.impl.QueueImpl@706254aa > at > org.apache.activemq.command.DefaultUnresolvedDestinationTransformer.transform(DefaultUnresolvedDestinationTransformer.java:48) > at > org.apache.activemq.command.ActiveMQDestination.transform(ActiveMQDestination.java:132) > at > org.apache.activemq.command.ActiveMQMessage.setJMSDestination(ActiveMQMessage.java:243) > at > org.apache.qpid.amqp_1_0.jms.impl.MessageProducerImpl.send(MessageProducerImpl.java:309) > at > org.apache.qpid.amqp_1_0.jms.impl.MessageProducerImpl.send(MessageProducerImpl.java:215) > at Listener.main(Listener.java:72) > > Is this enough to tell you what's happening? > > If not, please let me know what else I can provide to understand this > issue! > I can include code. It's only for testing purposes anyway. > > Thanks, > Mark. > > Sent from my iPhone > > > On Feb 19, 2014, at 1:51, Rob Godfrey <[email protected]> wrote: > > > > Hi Mark, > > > >> On 19 February 2014 05:23, Mark Barker <[email protected]> wrote: > >> > >> Thanks again to Rob and Robbie for their answers thus far! > >> > >> So I managed to slap (i.e. Frankenstein) together two pieces of > >> example/client code in order to attempt to facilitate a bridge of sorts > >> between two disparate queues. > >> > >> For this test, I'm using an ActiveMQ broker with two client > processes/JVMs > >> (client1 and client2). > >> The ActiveMQ broker is configured with 2 active protocols (transport > >> connectors) - Openwire (standard) on port 61616, and AMQP (1.0) on port > >> 5673 (only because I was experimenting previously with the Qpid broker > on > >> the more conventional port 5672) on the same box. > >> > >> client1 is a process based purely on an ActiveMQ Java/JMS openwire > client > >> (Publisher.java) example and its only purpose is to publish a > TextMessage > >> into Q1 via the openwire (tcp://) connection URL. > >> > >> client2 contains client code (and is linked/run with .jar libraries) for > >> both ActiveMQ AND Qpid JMS (AMQP 1.0). Its intent is to read messages > from > >> Q1 (via ActiveMQ) and re-deliver them into Q2 (via AMQP). This > situation is > >> a little contrived to start with, as eventually Q2 may well be on a > >> physically separate broker on a physically separate machine. > >> > >> So far, so good. I did some basic testing and proved my single client2 > >> process can successfully (independently) interact with both queues (via > >> both protocols). > >> > >> My issue is now this: > >> If I receive a "TextMessage" in client2 using "consumer2" (a > >> MessageConsumer for the ActiveMQ connection/session), this message > >> object/entity ("msg") is not just something I can use (unaltered) to > "send" > >> via client2's "producer2" (a MessageProducer for the AMQP > >> connection/session). Indeed, if I just try and "producer2.send(msg)", I > get > >> a Java exception at runtime. Something like: > >> "javax.jms.JMSException: Unresolvable destination: > >> org.apache.qpid.amqp_1_0.jms.impl.QueueImpl.isQueue(): > >> org.apache.qpid.amqp_1_0.jms.impl.QueueImpl@e127d8ab" on the "send" > call. > >> > >> I can only assume that this is because TextMessage has 2 separate > >> implementations context-dependant on the protocol/client interface with > >> which we are dealing. > >> Some digging (printing out the .getClass() results) shows that the msg > >> received is something like an > org.apache.activemq.command.ActiveMQTextMessage, > >> and the message needed to be sent is actually an > >> org.apache.qpid.amqp_1_0.jms.impl.TestMessageImpl. > >> > >> If this is the case, what is the best way to solve this problem. > >> If msg has a number of header and application-defined property > attributes > >> (never minding the body), how exactly is client2 supposed to > copy/preserve > >> them all across into a TextMessage object implementation suitable for > >> delivery to Q2. Will client2 need to know the exact structure of the > >> messages in order to deconstruct and reconstruct to satisfy the protocol > >> bridging?? > > > > So, in general a JMS library should be able to send a valid JMS message > > created or received from a different JMS provider... these are known as > > "foreign" messages in JMS terms. The exception is that Destinations > (such > > as those found in the JMSReplyTo field) are provider specific. However > if > > you don't have a ReplyTo set in the incoming message then I don't believe > > there should be any other issues as long as the messages are conformant > > with the JMS specification (note that many providers may "extend" the JMS > > specification to allow for non standard behaviours such as allowing map > > messages to contain nested maps or lists... such messages cannot be > > guaranteed to be resent without issue). > > > > Having said all of the above, I'm not sure that this is actually your > > issue... the error you are seeing sounds more like it is to do with > trying > > to send to a queue which doesn't exist, however I can't find the error > text > > you pasted in the Qpid codebase anywhere... Would it be possible to > paste > > in the complete stack trace (or at least all the bits that are within the > > qpid code if you want to remove any confidential parts from your own > > program)? > > > > Thanks, > > Rob > > > > > >> As ever, any help with this would be hugely appreciated... > >> Thanks in advance, > >> Mark. > >> > >> > >> -----Original Message----- From: Rob Godfrey > >> Sent: Monday, February 17, 2014 5:54 PM > >> > >> To: [email protected] > >> Subject: Re: New User JMS API Questions > >> > >> On 18 February 2014 01:11, Mark Barker wrote: > >> > >> Robbie, > >>> thanks again for your answers. > >>> > >>> As for your first suggestion: > >>> > >>> "connecting an ActiveMQ JMS client to the ActiveMQ > >>> broker and a Qpid JMS client to the Qpid broker within the same JVM" > >>> > >>> Is this going to be possible in practice? I'm something of a novice at > >>> Java too. Will there be some kind of conflict if trying to use both the > >>> ActiveMQ JMS client and the Qpid JMS client APIs in the same process? > How > >>> would/could this be done (example build command)? Thus far I have been > >>> building simple example code from the command line and referencing the > >>> relevant .jar dependency in the classpath params for both javac (build) > >>> and > >>> java (runtime). > >>> > >>> > >>> There shouldn't be an issue as long as there are no conflicts between > the > >> dependencies of the ActiveMQ client and the Qpid client. The Qpid > clients > >> aim to have as few dependencies as possible, so there really shouldn't > be > >> an issue. > >> > >> > >> Finally, > >>> today I've been looking at getting the simple Hello.java example > running > >>> on the ActiveMQ broker. > >>> Obviously, this means I have to use a JMS AMQP 1.0 client, so I've been > >>> using the Qpid JMS 1.0 client. > >>> I've encountered some issues which seem to relate to the Connection URL > >>> syntax from the JNDI (hello.properties) file. > >>> > >>> For instance, > >>> in a previous Qpid client talking AMQP 0-10 with a Qpid broker, I used: > >>> amqp://username:password@clientid > /test?brokerlist='tcp://localhost:5672' > >>> however I've read and seen in practice that this won't work with the > 1.0 > >>> client. > >>> Instead I have to use something like: > >>> amqp://username:password@localhost:5672 > >>> > >>> Can somebody please point me to the relevant documentation that > explains > >>> this difference in syntax. For all my digging on the Qpid website, I > can > >>> only find examples of the first/former (0-10 style), with no > disclaimers > >>> or > >>> caveats regarding the 1.0 client. > >>> > >>> > >>> No - there isn't a lot (or indeed really any) documentation around the > >> AMQP > >> 1.0 client. As you've noted the syntax is a little different from the > 0-10 > >> style... but you've pretty much got all of the syntax already. > >> > >> There are currently a number of options (set in the normal URI way: > >> amqp://username:password@host:port?option1=value1&option2=value2...) to > >> fine tune some AMQP settings. If you are interested you can look in the > >> code which parses them here: > >> > >> https://svn.apache.org/viewvc/qpid/trunk/qpid/java/amqp-1-0- > >> client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/ > >> ConnectionFactoryImpl.java?revision=1557982&view=markup&pathrev=1568703 > >> > >> Between lines 295 and 381 you will see the available options defined > along > >> with a brief description of their purpose. > >> > >> > >> In addition, I've found I can use "queue://" or "topic://" prefixes in > the > >>> JNDI properties to specify the object type when using the generic > >>> interface > >>> (i.e. general instead of p2p/pub-sub). Is that syntax a feature of the > >>> AMQP > >>> protocol, or something specific to the Qpid client or ActiveMQ broker? > I > >>> can't find much mention of it anywhere. > >>> > >>> > >>> That's something specific to the ActiveMQ broker. > >> > >> > >> Thanks again for giving these questions your attention!! > >>> > >>> > >>> > >>> -- Rob > >> > >> > >> > >>> -----Original Message----- From: Robbie Gemmell > >>> Sent: Saturday, February 15, 2014 2:57 PM > >>> > >>> To: [email protected] > >>> Subject: Re: New User JMS API Questions > >>> > >>> On 14 February 2014 04:55, Mark Barker wrote: > >>> > >>> If anyone has a tried this, or can confirm: > >>> > >>>> will it be possible to have a JMS client using an ActiveMQ broker on > one > >>>> machine (or maybe a producer/consumer pair), ultimately sending a > message > >>>> which then routes to a Qpid broker and associated local JMS consumer > on a > >>>> second machine (preserving all standard and application-specific JMS > >>>> message headers/properties). Has this been done and are there further > >>>> tricks, considerations and caveats here? > >>>> Maybe the ActiveMQ JMS consumer process on the first machine makes the > >>>> routing decision and then places the message via a producer instance > for > >>>> the Qpid broker on the 2nd machine? > >>> It sounds like you are talking about bridging two brokers, which you > >>> presumably do either by connecting an ActiveMQ JMS client to the > ActiveMQ > >>> broker and a Qpid JMS client to the Qpid broker within the same JVM, > or by > >>> using the Qpid AMQP 1.0 JMS client to connect to both brokers. > >> >
