When I try to send the JMS message to the external queue
It is failing with below error
error occured while sending the message :JMSWMQ2008: Failed to open MQ queue 'TESTQUEUE'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2082' ('MQRC_UNKNOWN_ALIAS_BASE_Q').
Jms Template declaration
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="cachedJmsQueueConnectionFactory" />
<property name="pubSubDomain" value="false" />
<property name="receiveTimeout" value="2000" />
</bean>
<bean id="testQueue" class="com.ibm.mq.jms.MQQueue">
<property name="baseQueueManagerName" value="${test.qmgrName}" />
<property name="baseQueueName" value="${test.queue}" />
</bean>
this.jmsTemplate.convertAndSend(getDestinationBean("testQueue"),
message.getJson());
but if I use dynamic destination resolver with jmsTemplate, I could send the message
this.jmsTemplate.convertAndSend("TESTQUEUE",
message.getJson());
In this situation when one program works and one does not the difference is that the two programs have resolved to different queue names. To figure out what's wrong requires understanding of how the names are resolved. There are two possibilities for which 2082: MQRC_UNKNOWN_ALIAS_BASE_Q results:
The alias queue's TARGQ attribute points to a non-existent queue.
The alias queue refers to a non-local clustered queue.
In the first case an alias queue is defined over a local queue but the definition is defective in some way. Often it is because the local queue name is misspelled. The result is that TARGQ has nothing local to which it can resolve. This is easy enough to diagnose by simple inspection or by using amqsput or any other sample which puts a message onto the queue.
The only way this can work in one instance and not the other as described is that one app resolves to the alias queue and one does not. For instance, one of the two apps specifies a non-local QMgr name and the message is put directly to a transmission queue whereas the other one hits a dead-end by resolving to the broken alias.
The second case is when the alias resolves to a non-local clustered queue but the calling program has specified the local QMgr name as part of the destination. The key to understanding this case is that, unlike a QRemote which can re-map the QMgr name, a QAlias does not change the QMgr name specified by the calling app. Since the QMgr name should not be provided to resove a clustered queue, supplying a non-blank string here breaks resolution.
Here's why...When opening a clustered queue an app specifies no QMgr name and MQ decides which instance to send to. The name resolution mechanism looks locally first and if it finds a clustered queue it uses the CLWLUSEQ attribute to decide whether to prefer the local instance over clustered instances. But if what it finds is an alias over a clustered queue it re-drives resolution using the TARGQ name. If the local QMgr name has been specified as part of a fully-qualified destination address and there is no local queue instance that matches TARGQ, there is no way to resolve it at that point and resolution fails. To successfully use an alias over a clustered queue therefore requires the calling program to not specify a QMgr name.
So both programs are resolving to different queue names. That you believe they are resolving to the same name when the behavior indicates they cannot possibly be needs to be dealt with to diagnose this further.
The best thing to do is to use a known-good piece of code for which resolution is unambiguous. The amqsput sample is good but what you really need to test this is a program that allows you to specify both the QMgr name to connect to and the QMgr name for the destination address, such as the Q program from SupportPac MA01. Recreate the error by variously specifying the local QMgr name in the destination or leaving it blank and you will be able to discern the case in which it fails and then modify the code accordingly.
As mentioned by Rob if it is a clustered queue then don't specify the queue manager.
<bean id="testInQueue" class="com.ibm.mq.jms.MQQueue">
<property name="baseQueueName" value="${test.queue}" />
</bean>
This config worked for me.
Related
How to customize start/stop of aws s3 inbound-channel-adapter . I want to set auto-startup="false" initially and start manually when server starts.Looking for a solution which is similar like we have the below solution for file inbound channel adaptor.
inboundFileAdapterChannel.send(new GenericMessage("#'s3FilesChannelId.adapter'.start()"));
Config:
If i try the same approach for s3 inbound adapter channel . I am getting the below error
APPLICATION FAILED TO START
Description:
A component required a bean named 's3FilesChannelId.adapter' that could not be found.
Action:
Consider defining a bean named 's3FilesChannelId.adapter' in your configuration.
Let's assume we have a channel adapter like this:
<int-aws:s3-inbound-channel-adapter id="s3Inbound"
channel="s3Channel"
session-factory="s3SessionFactory"
auto-create-local-directory="true"
auto-startup="false"
delete-remote-files="true"
preserve-timestamp="true"
filename-pattern="*.txt"
local-directory="."
remote-file-separator="\"
local-filename-generator-expression="#this.toUpperCase() + '.a' + #fooString"
comparator="comparator"
temporary-file-suffix=".foo"
local-filter="acceptAllFilter"
remote-directory-expression="'foo/bar'">
<int:poller fixed-rate="1000"/>
</int-aws:s3-inbound-channel-adapter>
Pay attention to the auto-startup="false" and to the id="s3Inbound".
So, it isn't going to be started automatically after application context initialization.
However using that s3Inbound id we can do that manually whenever it is convenient for us.
Your story about inboundFileAdapterChannel is not clear though, but you still can inject a Lifecycle for the mentioned channel adapter and perform its start():
#Autowired
#Qualifier("s3Inbound")
private Lifecycle s3Inbound;
...
this.s3Inbound.start();
The piece of code about inboundFileAdapterChannel seems like a reference to the Control Bus approach, but that's already slightly different story: https://docs.spring.io/spring-integration/docs/current/reference/html/system-management-chapter.html#control-bus
I'm trying to understand what config properties do I really need to make an MDB deployed on JBoss 5 process messages from a queue set up on a remote JMS provider. I'm planning to configure the activation spec using the ejb-jar.xml, and I wan't to configure only what I really need, not more. My understanding is that the allowed config for the spec is configured in the ra.xml in use. If I look for the ra.xml from jms-ra.rar I can see the below inbound-resourceadapter element
<inbound-resourceadapter>
<messageadapter>
<messagelistener>
<messagelistener-type>javax.jms.MessageListener</messagelistener-type>
<activationspec>
<activationspec-class>org.jboss.resource.adapter.jms.inflow.JmsActivationSpec</activationspec-class>
<required-config-property>
<config-property-name>destination</config-property-name>
</required-config-property>
</activationspec>
</messagelistener>
</messageadapter>
</inbound-resourceadapter>
only the destination property is mandatory. In my case this destination is remote, therefore I did configure a JMSProviderLoader with the necessary JNDI properties and also a connection factory that references this JMSProviderLoader, both in a new [myprovidername]-ds.xml file I added to deploy.
I cannot understand how if I only add a destination will the MDB know it is from that specific remote JMS provider, I do see that the outbound-resourceadapter element from ra.xml specifies the below:
<config-property>
<description>The jndi name of the provider of connection factories</description>
<config-property-name>JmsProviderAdapterJNDI</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>java:DefaultJMSProvider</config-property-value>
</config-property>
But judging from the word outgoing, this would not apply to inbound flows.
In summary, to enable an MDB to listen, do I only need destination? If so, how does it know what JMS provider this is from given that I could have multiple providers with same destination name?
Thanks
The magic comes with the Activation Spec that is configured in the inbound-resourceadapter:
<activationspec-class>org.jboss.resource.adapter.jms.inflow.JmsActivationSpec</activationspec-class>
Looking into the source shows, that java:/DefaultJMSProvider is hard set as default for the providerAdapterJNDI, so this one is used automagically, same as explicitly configured for the outbound part.
So you only need a destination as mandatory property because all else has a viable default in JmsActivationSpec.
As long as you name your own JMSProviderLoader to be the "Default" one in your *-ds.xml, everything works fine:
<attribute name="ProviderName">DefaultJMSProvider</attribute>
Otherwise you would have to set the according attribute explicitly in your activation spec for the MDB.
I'm working on abstracting out any sort of messaging framework for some code I'm working on. Basically, I'm using a combination of Spring AOP and Spring Integration to generate messages without the Java code knowing anything about RabbitMQ, JMS, or even Spring Integration. That said, what I'm using to generate the messages is contained in its own .jar, and it re-used by several other areas of the application. I currently have the messaging system set up such that the channels on which messages are sent are specified by the code that calls the system (i.e., channels are generated automatically based on the external method invocation) by specifying the channel name in the message header and using a header-value router to create the channels if they don't exist. My issue comes in on the endpoint of these channels - the intention of the current structure is to allow Spring to change to any messaging structure as requirements specify or change. I know how to take a static channel and use outbound channel converters/gateways to send it to a pre-specified RabbitMQ/JMS queue and process from there; what I'm struggling with is how to tell Spring that I need every channel created by the router to have a RabbitMQ (or whatever other messaging system gets implemented) outbound channel adapter that's dynamically generated based on the channel name since we don't know channel names beforehand.
Is this possible? And if not, would you mind providing input as to what could perhaps be a better way?
Thanks ahead of time!
Here's a basic template of what my config file looks like - I have an initial channel ("messageChannel") which gets sent to a publish-subscribe-channel and queuing channel depending on one of the message headers and is routed from there.
<!--Header value based channel configurations-->
<int:channel id="messageChannel" />
<int:channel id="queue" />
<int:publish-subscribe-channel id="topic" />
<!--Header-based router to route to queue or topic channels-->
<int:header-value-router input-channel="messageChannel"
header-name="#{ T(some.class.with.StringConstants).CHANNEL_TYPE}" />
<!--Re-routes messages according to their destination and messaging type-->
<int:header-value-router input-channel="queue"
header-name="#{ T(some.class.with.StringConstants).MESSAGE_DESTINATION}" />
<int:header-value-router input-channel="topic"
header-name="#{ T(some.class.with.StringConstants).MESSAGE_DESTINATION}" />
<!--AOP configuration - picks up on any invocation of some.class.which.generates.Messages.generateMessage()
from a Spring-managed context.-->
<aop:config>
<aop:pointcut id="eventPointcut"
expression="execution(* some.class.which.generates.Messages.generateMessage(..))" />
<aop:advisor advice-ref="interceptor" pointcut-ref="eventPointcut"/>
</aop:config>
<int:publishing-interceptor id="interceptor" default-channel="messageChannel">
<int:method pattern="generateMessage" payload="#return" channel="messageChannel" />
</int:publishing-interceptor>
See the dynamic-ftp sample; it uses a dynamic router that creates new outbound endpoints/channels on demand.
We have swing GUI clients that are connecting to a server process.
The clients 'call' services on the server using jms:queue 'from' endpoints defined in Camel routes, and using ActiveMQ as the underlying JMS broker.
However, the client also offers a Camel jms:topic endpoint for the server to broadcast messages back to the client.
Unfortunately, it looks like the topic connection is getting lost somehow, and although the client can still 'call' the services on the server, the server cannot send any messages to the client's topic endpoint.
The client-side spring definition of the Camel endpoint is as follows:
<camel:route>
<camel:from uri="jms:topic:inUseQueue"/>
<camel:to uri="bean:inUseInterfaceImpl"/>
</camel:route>
And the server-side producer is defined as follows:
<bean id="inUseManagerImpl" class="org.apache.camel.spring.remoting.CamelProxyFactoryBean">
<property name="serviceUrl" value="jms:topic:inUseQueue"/>
<property name="serviceInterface" value="uniworks.core.inuse.InUseInterface"/>
</bean>
Does anyone know of a way that we can somehow detect the loss of this topic connection on the client side?
An easy workaround shall be to override isSingleton() method of CamelProxyFactoryBean. Return false and let spring create the producer bean on every invocation instead of caching it. Or you can also define the scope of CamelProxyFactoryBean to be prototype.
Also you can try with the ActiveMQ camel component that supports connection pooling.
I realize this is a 8 month old question, but hey what the hell.
would it make sense to make the server broadcast "isalive" message once a minute, this way if the client doesn't get any of the "isalive" messages it can presume it has been disconnected.
My setup is Spring 3 JMS, MVC + Websphere MQ + Websphere 7
<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="com.SomeListener" />
<!-- and this is the message listener container -->
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="xxxCF" />
<property name="destination" ref="someQueue" />
<property name="messageListener" ref="messageListener" />
</bean>
When I start up the server, the listener seems to start correctly since it receives the messages that are on the queue as I put them.
However, once I run any simple controller/action that doesn't even have anything to do with JMS it gives me the message below over and over...
DefaultMessag W org.springframework.jms.listener.DefaultMessageListenerContainer handleListenerSetupFailure Setup of JMS message listener invoker failed for destination 'queue:///ABCDEF.EFF.OUT?persistence=-1' - trying to recover. Cause: MQJMS2008: failed to open MQ queue ''.; nested exception is com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2042'.
DefaultMessag I org.springframework.jms.listener.DefaultMessageListenerContainer refreshConnectionUntilSuccessful Successfully refreshed JMS Connection
ConnectionEve W J2CA0206W: A connection error occurred. To help determine the problem, enable the Diagnose Connection Usage option on the Connection Factory or Data Source.
ConnectionEve A J2CA0056I: The Connection Manager received a fatal connection error from the Resource Adapter for resource JMS$XXXQCF$JMSManagedConnection#2. The exception is: javax.jms.JMSException: MQJMS2008: failed to open MQ queue ''.
ConnectionEve W J2CA0206W: A connection error occurred. To help determine the problem, enable the Diagnose Connection Usage option on the Connection Factory or Data Source.
ConnectionEve A J2CA0056I: The Connection Manager received a fatal connection error from the Resource Adapter for resource jms/XXXQCF. The exception is: javax.jms.JMSException: MQJMS2008: failed to open MQ queue ''.
The original listener seems to be still running correctly...but I think the controller is somehow triggering off another connection?
Does anyone know what I should check for or what might cause this issue?
thanks
The 2042 means "Object in use". Since there is no concept of exclusive use of queues for message producers, then one of your consumers is locking the queue.
This behavior is controlled by the queue definition's DEFSOPT attribute. This is at the queue manager itself and not in the managed object definitions or your factory options. From the command line while signed on as mqm (or the platform equivalent if the QMgr is on Windows, iSeries, z/OS, etc.) you would need to start runmqsc and issue the following commands to verify and then fix the problem. In my example, the QMgr is PLUTO and the example queue is SYSTEM.DEFAULT.LOCAL.QUEUE.
/home/mqm: runmqsc PLUTO
5724-H72 (C) Copyright IBM Corp. 1994, 2009. ALL RIGHTS RESERVED.
Starting MQSC for queue manager PLUTO.
dis q(system.default.local.queue) defsopt
1 : dis q(system.default.local.queue) defsopt
AMQ8409: Display Queue details.
QUEUE(SYSTEM.DEFAULT.LOCAL.QUEUE) TYPE(QLOCAL)
DEFSOPT(EXCL)
alter ql(system.default.local.queue) defsopt(shared)
2 : alter ql(system.default.local.queue) defsopt(shared)
AMQ8008: WebSphere MQ queue changed.
dis q(system.default.local.queue) defsopt
3 : dis q(system.default.local.queue) defsopt
AMQ8409: Display Queue details.
QUEUE(SYSTEM.DEFAULT.LOCAL.QUEUE) TYPE(QLOCAL)
DEFSOPT(SHARED)
If you display the queue and find that it is already set for DEFSOPT(SHARED) then something must be specifying exclusive use of the queue through the API. That typically means a C or base Java program since these non-JMS APIs have access to low-level WMQ functionality. Those can be a little trickier to diagnose and I usually use a trace or the SupportPac MA0W exit to display the API calls and options used. If this is the case, I'd want to know more about what is meant by "simple controller/action" as noted in the original post.
Finally, if the queue that you are accessing is a remote queue then it will resolve to a transmit queue. The channel will always set a transmit queue to GET(INHIBITED) and acquire an exclusive lock on it. This is consistent with WMQ functionality in that an application can only GET messages from a local queue.