ActiveMQ Classic Resource Adapter Connection Factories - jms

In ActiveMQ classic ra.xml we have several definitions of Connection Factories.
There are the following, mentioned as Outbound(meaning used only for sending messages?), documented here:
<outbound-resourceadapter>
<connection-definition>
<managedconnectionfactory-class>org.apache.activemq.ra.ActiveMQManagedConnectionFactory</managedconnectionfactory-class>
<connectionfactory-interface>javax.jms.ConnectionFactory</connectionfactory-interface>
<connectionfactory-impl-class>org.apache.activemq.ra.ActiveMQConnectionFactory</connectionfactory-impl-class>
<connection-interface>javax.jms.Connection</connection-interface>
<connection-impl-class>org.apache.activemq.ra.ManagedConnectionProxy</connection-impl-class>
</connection-definition>
<connection-definition>
<managedconnectionfactory-class>org.apache.activemq.ra.ActiveMQManagedConnectionFactory</managedconnectionfactory-class>
<connectionfactory-interface>javax.jms.QueueConnectionFactory</connectionfactory-interface>
<connectionfactory-impl-class>org.apache.activemq.ra.ActiveMQConnectionFactory</connectionfactory-impl-class>
<connection-interface>javax.jms.QueueConnection</connection-interface>
<connection-impl-class>org.apache.activemq.ra.ManagedConnectionProxy</connection-impl-class>
</connection-definition>
<connection-definition>
<managedconnectionfactory-class>org.apache.activemq.ra.ActiveMQManagedConnectionFactory</managedconnectionfactory-class>
<connectionfactory-interface>javax.jms.TopicConnectionFactory</connectionfactory-interface>
<connectionfactory-impl-class>org.apache.activemq.ra.ActiveMQConnectionFactory</connectionfactory-impl-class>
<connection-interface>javax.jms.TopicConnection</connection-interface>
<connection-impl-class>org.apache.activemq.ra.ManagedConnectionProxy</connection-impl-class>
</connection-definition>
Additionally, I see a number of connection factories declared as admin objects:
<adminobject>
<adminobject-interface>javax.jms.ConnectionFactory</adminobject-interface>
<adminobject-class>org.apache.activemq.ActiveMQConnectionFactory</adminobject-class>
<config-property>
<config-property-name>brokerUrl</config-property-name>
<config-property-type>java.lang.String</config-property-type>
</config-property>
</adminobject>
<adminobject>
<adminobject-interface>javax.jms.ConnectionFactory</adminobject-interface>
<adminobject-class>org.apache.activemq.pool.XaPooledConnectionFactory</adminobject-class>
<config-property>
<config-property-name>brokerUrl</config-property-name>
<config-property-type>java.lang.String</config-property-type>
</config-property>
<config-property>
<config-property-name>tmFromJndi</config-property-name>
<config-property-type>java.lang.Boolean</config-property-type>
</config-property>
</adminobject>
<adminobject>
<adminobject-interface>javax.jms.XAConnectionFactory</adminobject-interface>
<adminobject-class>org.apache.activemq.ActiveMQXAConnectionFactory</adminobject-class>
<config-property>
<config-property-name>brokerURL</config-property-name>
<config-property-type>java.lang.String</config-property-type>
</config-property>
</adminobject>
My question is what is the use of all these implementations?
Which one should be used from a consumer such as Message Driven Bean(MDB)?

Related

How Do I Connect Stomp Client to An ActiveMQ Artemis Destination Created Using JMS(Spring Boot)?

CONTEXT
I am trying to learn about SpringJMS and MOMS and I am using ActiveMQ Artemis for this. I created a Queue Destination address using the jakarta.jms.* API, and managed to send some message to the queue like this:
public void createUserDestination(String userId) throws JMSException {
queueDestination = setupConnection().createQueue("user" + userId);
producer = session.createProducer(queueDestination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
producer.send(session.createTextMessage("Testing queue availability"));
connection.close();
log.info("successfully created group... going back to controller");
}
So for example, if I pass an ID of user12345abc, I get a Queue Address user12345abc, of the routing type ANYCAST with one queue underneath(with that same address) with my message placed there.
PROBLEM
Now, I wanted to write a simple web front-end with STOMP that can connect to this queue. But I have been having a ton of problems connecting to that queue address because each time I try to connect by providing the destination address, it creates a new address in the MOM and connects to that instead.
My STOMP code looks like this(the first argument is the destination address, you can ignore the rest of the code):
stompClient.subscribe("jms.queue.user12345abc", (message) => {
receivedMessages.value.push(message.body);
});
In this case, completely brand new queue is created with the address jms.queue.user12345abc which is not what I want at all.
I configured my Spring Backend to use an external MOM broker like this(I know this is important):
public void configureMessageBroker(MessageBrokerRegistry registry) {
// these two end points are prefixes for where the messages are pushed to
registry.enableStompBrokerRelay("jms.topic", "jms.queue")
.setRelayHost("127.0.0.1")
.setRelayPort(61613)
.setSystemLogin(brokerUsername)
.setSystemPasscode(brokerPassword)
.setClientLogin(brokerUsername)
.setClientPasscode(brokerPassword);
// this prefixes the end points where clients send messages
registry.setApplicationDestinationPrefixes("/app", "jms.topic", "jms.queue");
// this prefixes the end points where the user's subscribe to
registry.setUserDestinationPrefix("/user");
}
But it's still not working as I expect it to. Am I getting some concept wrong here? How do I use STOMP to connect to that queue I created earlier with JMS?
It's not clear why you are using the jms.queue and jms.topic prefixes. Those are similar but not quite the same as the jms.queue. and jms.topic. prefixes which were used way back in ActiveMQ Artemis 1.x (whose last release was in early 2018 almost 5 years ago now).
In any case, I recommend you use the more widely adopted /queue/ and /topic/, e.g.:
public void configureMessageBroker(MessageBrokerRegistry registry) {
// these two end points are prefixes for where the messages are pushed to
registry.enableStompBrokerRelay("/topic/", "/queue/")
.setRelayHost("127.0.0.1")
.setRelayPort(61613)
.setSystemLogin(brokerUsername)
.setSystemPasscode(brokerPassword)
.setClientLogin(brokerUsername)
.setClientPasscode(brokerPassword);
// this prefixes the end points where clients send messages
registry.setApplicationDestinationPrefixes("/app", "/topic/", "/queue/");
// this prefixes the end points where the user's subscribe to
registry.setUserDestinationPrefix("/user");
}
The in broker.xml you'd need to add the corresponding anycastPrefix and multicastPrefix values on the STOMP acceptor, e.g.:
<acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;anycastPrefix=/queue/;multicastPrefix=/topic/</acceptor>
To be clear, your JMS code will stay the same, but your STOMP consumer would be something like:
stompClient.subscribe("/queue/user12345abc", (message) => {
receivedMessages.value.push(message.body);
});

Spring integration- Route one channel to specific channel with message transformer

am new to Spring Integration
my objective is passing message to one channel to another (chain process)
Channel1 ---> chennal2 --> chennal3 ---> chennal4.
(Msg1)       (Msg2)                (Msg3)                    (Msg4)
     \                         \                       /                          /
       \                        \                   /                          /          
                            errorChennal (Msg5)
1.       Msg1(EmployeeObject), Msg2 (DetailsObjet), Msg3(VerificationObject), Msg4(FinalObject), Msg5(ErrorObject)
Each channel payloads will have different Class Objects.
   All the channel need to be communicated to "errorChennal" in case of Exception, validation error, etc.
Tried:
1. when I tried with #transformer am not able to communicate to "erroeChannel".
when I tried with #Router(header-value-router) Message transform not happing. Msg1 object is to all object
Question:
  How do i route one channel to specific channel with message transformer?
FOUND ANSWER
Configuration:
<int:channel id="channel1"/>
<int:channel id="channel2"/>
<int:channel id="channel3"/>
<int:channel id="channel4"/>
<int:service-activator input-channel="channel1" ref="firstChannel" method="doProcess1" />
<int:service-activator input-channel="channel2" ref="secondChannel" method="doProcess2" />
<int:service-activator input-channel="channel3" ref="thirdChannel" method="doProcess3" />
<int:service-activator input-channel="channel4" ref="forthChannel" method="doProcess4" />
<int:service-activator input-channel="errorChannel" ref="errorHandlerChannel" method="doErrorProcess" />
Java Code:
public FirstChannel {
private Map<String, MessageChannel> msgChannels;
boolean isError = false;
#Autowired
public ScheduleParser(Map<String, MessageChannel> msgChannels) {
super();
this.msgChannels = msgChannels;
}
public void doprocess1(Message<?> message){
File file = (File) message.getPayload();
//business code
if(!isError)
//transforming the messae
msgChannels.get("channel2").send(new GenericMessage(EmployeeVO , headersMap));
else
msgChannels.get("errorChannel").send(new GenericMessage(ObjectVO , headersMap));
}
}
Same way Other channels Code will be
Channels aren't connected to each other they are connected to endpoints.
Transformers don't route, routers route.
You need something like
channel1->payload-type-router
type1Channel->...
type2Channel->...
...
possibly with a different transformer for each payload type downstream.
It's generally better to show the configuration you have tried rather than some abstraction like you have shown.
The error flow configuration depends on what starts your flow (gateway, poller, etc) - i.e. what is upstream of channel1.
EDIT
Your configuration is completely wrong. For example, you currently have two subscribers on channel1 - a header value router and service activator.
Messages arriving on channel1 will alternately go to one or the other - messages going to the service activator will never go to the router.
Without knowing the complete picture, I am guessing you need something like...
channel1->serviceActivator1->channel1toRouter->router(channel2 or failed)
channel2->serviceActivator2->channel2toRouter->router(channel2 or failed)
...

Getting exception while Consuming https Webservice in mule

I'm trying to call a https web service using cxf generated client proxies within Mule. Almost 99% of the time, I get
Caused by: org.apache.commons.httpclient.ProtocolException: Unbuffered entity enclosing request can not be repeated.
at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:487)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)*
The app has http inbound end point. The Mule Java transformer tries to call a webservice using https using cxf generated client proxies. I'm running into above said exception.
I've provided screenshot the mule flow [http://i.stack.imgur.com/7X9Wg.jpg]. Much appreciated!!
Mule config xml
<cxf:jaxws-service serviceClass="test.service.https.TestService" doc:name="SOAP" configuration-ref="CXF_Configuration" enableMuleSoapHeaders="false"/>
<custom-transformer class="test.service.https.CallLicenseService" doc:name="Calls HTTPS WS using CXF generated client proxies" encoding="UTF-8" mimeType="text/plain"/>
<logger message="Success" level="INFO" doc:name="Logger"/>
<set-payload value="#['HELLO SUCCESS']" doc:name="Set Payload"/> </flow>
Transformer
URL wsdlURL = null;
String serviceUrl = "TARGET_HTTPS_WSDL"; //This would be the target https URL
try {
wsdlURL = new URL(serviceUrl);
} catch (MalformedURLException e) {
Logger.getLogger(getClass()).info("", e);
}
AuditLogServiceService ss = new AuditLogServiceService(wsdlURL);
AuditLoggingService port = ss.getAuditLoggingServicePort();
((BindingProvider) port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
serviceUrl.substring(0, serviceUrl.length() - 5));
AuditLogServiceRequest request = new AuditLogServiceRequest();
request.setClientId("4");
request.setUserId("101");
request.setEventSubType("1");
request.setEventType("1");
AuditLogMessage msg = new AuditLogMessage();
msg.setMessage("Hello Test");
request.getLogMessages().add(msg);
AuditLogServiceResponse response = port.logEvent(request);
System.out.println(response.getMessage());
return response.getMessage();
First of all if you need to consume a webservice You need to put <cxf:jaxws-client serviceClass instead of cxf:jaxws-client ...next step is you need to use an http outbound endpoint to post to the external webservice ... pls refer the following link :- http://www.mulesoft.org/documentation/display/current/Consuming+Web+Services+with+CXF
One more thing .. you need to use java component instead of <custom-transformer class ..you need to set the payload just before the component ... I mean you need to set the payload before posting it to external webservice

warning message in console while calling DB2 function on zOS using jdbcTemplate

My java app deployed in jboss AS 7, queries a MS SQL server database using spring data. I also need to call a DB2 function on zOS for which I use Spring JdbcTemplate. The SQL is:
public String getUniqueId()
{
String sql = "SELECT " + schemaName + ".SGB_LON_ID_NEXT() FROM SYSIBM.SYSDUMMY1" ;
return (jdbcTemplate.queryForLong(sql));
}
Unit tests in Eclipse work fine.
When I deploy in the jboss server, the first call works.
However, the second transaction onwards, the call itself works, but a few warnings appear in the server.log for each call.
I wonder if it could be the fact that the JDBC call is NOT a part of the JPA transaction. (note that the jdbc call is a simple - the DB2 function just returns the next serial number for a field )
Here are the warning messages from the error stack:
21:50:33,955 WARN [org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory] (http-/127.0.0.1:8080-14)
Destroying connection that is not valid, due to the following exception: com.ibm.db2.jcc.t4.b#1167bd5: com.ibm.db2.jcc.am.SqlSyntaxErrorException:
DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=<END-OF-STATEMENT>;MICROSECONDS MICROSECOND SECONDS SECOND MINUTES MIN, DRIVER=3.63.123
21:50:34,096 WARN [org.jboss.jca.core.connectionmanager.listener.TxConnectionListener] (http-/127.0.0.1:8080-14)
IJ000305: Connection error occured:org.jboss.jca.core.connectionmanager.listener.TxConnectionListener#f79f0f[state=NORMAL managed connection=org.jboss.jca.adapters.jdbc.local.LocalManagedConnection#136e43e connection handles=0 lastUse=1359255001136 trackByTx=false
pool=org.jboss.jca.core.connectionmanager.pool.strategy.PoolByCri#c2c2de pool internal context=SemaphoreArrayListManagedConnectionPool#8793c7[pool=DB2_zOS_DS]
xaResource=LocalXAResourceImpl#f70194[connectionListener=f79f0f connectionManager=112dadb warned=false currentXid=null] txSync=null]:
com.ibm.db2.jcc.am.SqlSyntaxErrorException:
DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=<END-OF-STATEMENT>;MICROSECONDS MICROSECOND SECONDS SECOND MINUTES MIN, DRIVER=3.63.123
21:50:34,196 WARN [org.jboss.jca.core.connectionmanager.pool.strategy.PoolByCri] (http-/127.0.0.1:8080-14)
IJ000612: Destroying connection that could not be successfully matched: org.jboss.jca.core.connectionmanager.listener.TxConnectionListener#f79f0f[state=DESTROYED managed connection=
org.jboss.jca.adapters.jdbc.local.LocalManagedConnection#136e43e connection handles=0 lastUse=1359255001136 trackByTx=false
pool=org.jboss.jca.core.connectionmanager.pool.strategy.PoolByCri#c2c2de pool internal context=SemaphoreArrayListManagedConnectionPool#8793c7[pool=DB2_zOS_DS]
xaResource=LocalXAResourceImpl#f70194[connectionListener=f79f0f connectionManager=112dadb warned=false currentXid=null] txSync=null]
Any suggestions on how to fix?
I am not clear on how to add the JDBC call to the current transaction (JPA). Or should it be a separate transaction. As stated earlier the jdbc call is a db2 function that returns the next value for a sequence number.
The problem turned out to be in my datasource setup in JBOSS_HOME/standalone/configuration/standalone.xml.
In the validation section, I had this which was incorrect.
<validation>
<check-valid-connection-sql>select 1</check-valid-connection-sql>
<validation>
The above was incorrect and DB2 was giving a validation error.
I changed that to the following instead:
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.db2.DB2ValidConnectionChecker"/>
<stale-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.db2.DB2StaleConnectionChecker"/>
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.db2.DB2ExceptionSorter"/>
</validation>
Here is the complete datasource set up in case anybody else finds it useful.
<datasource jndi-name="java:jboss/datasources/DB2_zOS_DS" pool-name="DB2_zOS_DS" enabled="true" use-java-context="true">
<connection-url>jdbc:db2://MyHostName:MyPortNo/MyDBQA1:currentSchema=MySchemaQA1;</connection-url>
<driver>db2zOS</driver>
<transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
<pool>
<min-pool-size>9</min-pool-size>
<max-pool-size>50</max-pool-size>
<prefill>true</prefill>
<allow-multiple-users/>
</pool>
<security>
<user-name>MY-APP-ID</user-name>
<password>My-APP-ID-PASSWORD</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.db2.DB2ValidConnectionChecker"/>
<stale-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.db2.DB2StaleConnectionChecker"/>
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.db2.DB2ExceptionSorter"/>
</validation>
<timeout>
<set-tx-query-timeout>true</set-tx-query-timeout>
<blocking-timeout-millis>500</blocking-timeout-millis>
<idle-timeout-minutes>15</idle-timeout-minutes>
</timeout>
<statement>
<track-statements>false</track-statements>
<prepared-statement-cache-size>32</prepared-statement-cache-size>
<share-prepared-statements>true</share-prepared-statements>
</statement>
</datasource>
<drivers>
<driver name="db2zOS" module="com.ibm.db2">
<driver-class>com.ibm.db2.jcc.DB2Driver</driver-class>
</driver>
</drivers>

Multiple consumers per StreamingAmf connection?

I have an Adobe Air 2.0 application that is also utilizing Spring BlazeDS integration. Inside this application I have a couple of data grids. The design was for each grid's model to register a Consumer to listen for changes pushed from BlazeDS. The first grid instantiated works correctly, however each subsequent grid causes the following warning in BlazeDS
[WARN] [Endpoint.StreamingAMF] Endpoint with id 'streaming-amf' received a duplicate streaming connection request from, FlexClient with id ''
I was under the impression you could have multiple consumers inside a Flex/Air application. Am I mistaken or have I just missed something in my configuration?
Server side channel definition
<channel-definition id="streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
<properties>
<add-no-cache-headers>false</add-no-cache-headers>
<max-streaming-clients>15</max-streaming-clients>
<user-agent-settings>
<user-agent match-on="AdobeAIR" kickstart-bytes="2048" max-streaming-connections-per-session="2" />
<user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="3" />
<user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="3" />
</user-agent-settings>
</properties>
</channel-definition>
Code for Channelset
<s:ChannelSet id="pricingCS">
<s:channels>
<s:StreamingAMFChannel id="streaming-amf"
url="http://localhost:8080/blazeds/messagebroker/streamingamf"
connectTimeout="5"/>
</s:channels>
</s:ChannelSet>
Code for Consumer
consumer = new Consumer();
consumer.id = "pricingConsumer";
consumer.destination = "pricingUpdates";
consumer.subtopic = pId;
consumer.channelSet = channelSet;
consumer.addEventListener(MessageEvent.MESSAGE, priceUpdate);
consumer.addEventListener(MessageFaultEvent.FAULT, priceUpdateFail);
consumer.subscribe();

Resources