push messages to active mq via proxy using http transport - java

Hi I am trying to push messages to active mq via http transport.
The active mq is behind the proxy server which need authentication before pushing the message to external active mq.
is there a way I can set the proxy details to active mq connection.
I read some article where mentioned we can use HttpClientTrasport.
But i am not sure how to set the HttpClientTrasport to ActiveMQConnection object.
Thanks in advance.

if i understand you want to set the proxy config for org.apache.activemq.ActiveMQConnection ?
this can be set on org.apache.activemq.ActiveMQConnectionFactory.ActiveMQConnectionFactory(String brokerURL) level by passing the url with proxy config like this :
brokerURL = "http://localhost:8080?proxyHost=proxy&proxyPort=8080&proxyUser=user&proxyPassword=pwd"
if you have specials characters on user or pwd you need to change like this :
brokerURL = "http://localhost:8080?"+ URLEncoder.encode("proxyHost=proxy&proxyPort=8080&proxyUser=user&proxyPassword=pwd", "UTF-8");
hope this help

add transportConnection configuration in activemq;
nano ~/apache-activemq-5.11.1/conf/activemq.xml
<transportConnector name="http" uri="http://0.0.0.0:8888?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
use broker_url
private static final String DEFAULT_BROKER_URL = "http://localhost:8888";
add dependency in project
<dependency><groupId>org.apache.activemq</groupId><artifactId>activemq-http</artifactId><version>5.11.1</version></dependency>

Related

What is the purpose of setting QueueManager property for IBM MQ?

Following this example of sending messages to queue let's look at the part of setting connection factory properties
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, HOST);
cf.setIntProperty(WMQConstants.WMQ_PORT, PORT);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, CHANNEL);
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QMGR);
cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "JmsPutGet (JMS)");
cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
cf.setStringProperty(WMQConstants.USERID, APP_USER);
cf.setStringProperty(WMQConstants.PASSWORD, APP_PASSWORD);
When the line cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QMGR); is removed then nothing changes: the client still can successfully send and receive messages.
What is the purpose of setting WMQConstants.WMQ_QUEUE_MANAGER property here?
IBM MQ server is a container based on this Dockefile:
FROM ibmcom/mq:9.2.2.0-r1
ENV LICENSE=accept
ENV MQ_DEV=true
ENV MQ_APP_PASSWORD=app-password
ENV MQ_ADMIN_PASSWORD=admin-pwd
ENV MQ_QMGR_NAME=KUPOL_DEV_QM
Additionally:
In the same example we see the line
destination = context.createQueue("queue:///" + QUEUE_NAME)
and it does not break the app if the prefix "queue:///" is removed, leaving the line as
destination = context.createQueue(QUEUE_NAME).
And I see similar things in multiple examples for IBM MQ across the web.
What is going on with this code? Is it blind copy-pasting or is there an intention?
If you leave queue manager unset or specify a value that is prefixed with a * you can connect to any queue manager name listening on the host and port you specify.
If you specify a queue manager name that is not prefixed with a * then it must match the name of the queue manager listening on the host and port.
You can also use a CCDT to hold the the connection details, in this case (in addition to the above points) the queue manager name you specify is used to look up the connection details in the CCDT. If it is prefixed with a * it will look up the name without the * in the CCDT.
In addition to specifying queue names with the queue:/// prefix, you can also specify topics with the prefix topic:///, my guess is createQueue defaults to assume you are specifying a queue name.
Your sample code appears to be JMS. IBM MQ supports a couple of addressing models for queues.
All three of these mean the same thing:
context.createQueue("MY.QUEUE");
context.createQueue("queue://MY.QUEUE");
context.createQueue("queue:///MY.QUEUE");
However, with the triple-slash you can also fully-qualify REMOTE queues
context.createQueue("queue://QMGRB/MY.OTHER.QUEUE");
This tells IBM MQ to send the message to the QMgr and have it deliver the message to the Remote Queue 'MY.OTHER.QUEUE' on 'QMGRB'.
Note: IBM MQ also supports destination options, so you can modify persistence, priority, character encoding, targetClient, etc. This is useful so you can externalize the configuration and change the message pattern without having to change the code!
ref: https://www.ibm.com/docs/en/ibm-mq/9.0?topic=applications-creating-destinations-in-jms-application

Connecting to IBM MQ using CCDT file in JMS

I am trying to connect to IBM MQ using JMS and client channel definition table (CCDT). I was able to connect successfully to the QueueManager when i specify the MQ properties individually.
But when i try to use CCDT file i get the below exception.
As client channel definition table (CCDT) is used to determine the channel definitions used by client applications to connect to the queue manager i didnt set QueueManager Name.
ERROR> com.ssc.ach.mq.JMSMQReceiver[main]: errorMQJMS2005: failed to create MQQueueManager for ''
javax.jms.JMSException: MQJMS2005: failed to create MQQueueManager for ''
at com.ibm.mq.jms.services.ConfigEnvironment.newException(ConfigEnvironment.java:586)
at com.ibm.mq.jms.MQConnection.createQM(MQConnection.java:2110)
at com.ibm.mq.jms.MQConnection.createQMNonXA(MQConnection.java:1532)
at com.ibm.mq.jms.MQQueueConnection.<init>(MQQueueConnection.java:150)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:174)
at com.ibm.mq.jms.MQQueueConnectionFactory.createConnection(MQQueueConnectionFactory.java:1066)
Iam using the .setCCDTURL(ccdt); method to set the CCDT URL.
private MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setCCDTURL(ccdt);
queueConnection = mqQueueConnectionFactory.createConnection(username, pwd);
When i try to connect using below configuration instead of the CCDT file it connects to the MQ.
mqQueueConnectionFactory.setHostName(host);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(qManager);
mqQueueConnectionFactory.setTransportType(1);
Do i need to set setQueueManager as well along with the CCDT file , as the exception says failed to create MQQueueManager for ''
The CCDT is not meant to be read in a text editor, it is a binary formatted file. One of the parameters in the CCDT for each CLNTCONN channel is QMNAME. Knowing what QMNAME is set to and how many CLNTCONN channels you have defined in the CCDT and what you want to accomplish will help figure out what value if any should be specified for with setQueueManager.
If there is only one CLNTCONN channel then you could specify the following and it will connect using the single channel no matter what the QMNAME property is set to:
setQueueManager("*");
If there is more than one CLNTCONN channel in the file each with a different QMNAME specified, assuming the name matches the actual queue manager name listening on the host and port associated with the channel you would pass the queue manager name:
setQueueManager("QMGRNAME");
If there is more than one CLNTCONN channels in the file each with the same QMNAME specified where this name is not meant to reflect a actual queue manager name listening on the host and port associated with each channel, this is known as a queue manager group, this would be intended where you want the client to connect to any number of different hosts and ports and you do not need to know which queue manager you are connecting to, in this case you would pass the queue manager group name prefixed with a *:
setQueueManager("*QMGRGROUPNAME");
Another variation of the above is if there is more than one CLNTCONN channels in the file each with an all blank (spaces) or NULL QMNAME specified, this is known as a queue manager group, this would be intended where you want the client to connect to any number of different hosts and ports and you do not need to know which queue manager you are connecting to, in this case you would pass the queue manager name as either a single space or nothing at all ``:
setQueueManager(" ");
//or
setQueueManager("");
The last use case above would likely work if you did not use setQueueManager at all.
If you want to view the contents of the CCDT, you can use the runmqsc command that comes as part of the MQ v8 and higher client or server install.
For Unix ksh/bash shells use the following:
export MQCHLLIB=PATH/OF/CCDT
export MQCHLTAB=NAME_OF_CCDT
runmqsc -n
For Windows use the following:
set MQCHLLIB=PATH/OF/CCDT
set MQCHLTAB=NAME_OF_CCDT
runmqsc -n
Once the runmqsc program has started and displayed Starting local MQSC for 'NAME_OF_CCDT'. you can run the following command to see the channel details:
DIS CHL(*)
Below is a more specific command to narrow the number of fields returned:
DIS CHL(*) QMNAME CONNAME
I haven't look at it in a while but I thought the correct format is:
MQQueueConnectionFactory qcf = new MQQueueConnectionFactory();
qcf.setQueueManager(qManager);
qcf.setCCDTURL(ccdt);
conn = qcf.createConnection(username, pwd);

Restlet framework: how to bind to localhost only?

I need to build a (standalone Java) restlet-based service that only listens on localhost, i.e. no requests from network are allowed.
I was trying to do the obvious:
Server srv = new Server(Protocol.HTTPS, "localhost", httpsPort);
component.getServers().add(srv);
But the service still listens on 0.0.0.0. :-(
I went into the code and found that HttpsServerHelper ignores the hostname when creating the service:
this.server = HttpsServer.create(new InetSocketAddress(getHelped().getPort()), 0);
Similar code exists in plain HTTP's HttpServerHelper, where it is even more clear.
My question then is this:
How can I configure Restlet component/service to only listen on localhost?
I don't know which server you use under the hood within your standalone Restlet application. You should use a server connector other than the default one and I recommend you to use the Jetty one.
To do that, simply put the jar of the extension org.restlet.ext.jetty in your classpath.
In this case, using the following code should correspond to your needs:
component.getServers().add(Protocol.HTTP, "localhost", 8182);
Here is the corresponding trace at application startup:
2015-09-03 09:47:22.180:INFO::jetty-7.1.6.v20100715
2015-09-03 09:47:22.211:INFO::Started SelectChannelConnector#localhost:8182
In addition, here is the link in the Restlet documentation regarding Restlet connectors: http://restlet.com/technical-resources/restlet-framework/guide/2.3/core/base/connectors.
Hope it helps you,
Thierry
The easier way to achieve that is to use virtual hosts.
Virtual hosts are the first routing barrier when handling a request, especially it helps routing on a domain.
Here is a sample code that illustrates this:
Component c = new Component();
c.getServers().add(Protocol.HTTP, 8182);
VirtualHost host = new VirtualHost();
host.setHostDomain("localhost");
c.getHosts().add(host);
host.attach(new Restlet() {
#Override
public void handle(Request request, Response response) {
response.setEntity("hello, world", MediaType.TEXT_PLAIN);
}
});
c.start();
Usually, applications are attached on the default host of a component. This default host does nothing, except routing requests based on the context path of the attached application:
c.getDefaultHost().attach("/contextPath1", new Test1Application());
c.getDefaultHost().attach("/contextPath2", new Test2Application());
When you would like to filter calls based on other data than the request's path, virtual host may be the solution.
Here is a diagram that may help you:
http://restlet.com/technical-resources/restlet-framework/tutorials/2.3#part05

Netty 5, how to bind some specify info in channel

ClientA and Client B connect to the NettyServer.
when the connection builds, there is a channel between Client and NettyServer, I want when channel active, I can add Client side info in the channel, so that I can store like Map(ClientInfo,Channel). The on the server side, I can use Map.get(ClientInfo) to get the specific channel, then I can use channel.writeAndFlush() to send message to the specific client.
how to implement it? Use attachment? But, in neety5 API ChannelHandler, the attachment example is not the way I want to use. I wander if I can add attachment at Client side, and I can get it at the Server side?
You can use the AttributeKey or AttributeMap to store your client info, and store them into channel or channelContext, if necessary you can use them using get or set method.

How do you connect to a Multi-Instance Queue Manager using MQQueueConnectionFactory

We have an application which needs to communicate with a Multi-Instance QueueManager. Both (instances) are running on the default port and have unique addresses.
serverA.internal.company.address
serverB.internal.company.address
We use the following code to establish the ConnectionFactory:
MQQueueConnectionFactory connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setTransportType(1);
connectionFactory.setPort(1414);
connectionFactory.setChannel("CLIENTCONNECTION");
connectionFactory.setQueueManager("queue.manager.name.here");
connectionFactory.setHostName("serverA.internal.company.address");
How can we specify both addresses so that failover is achieved without writing our own retry logic?
using the following:
connectionFactory.setConnectionNameList("serverA.internal.company.address(1414),"
+ "serverB.internal.company.address(1414)")
instead of
connectionFactory.setHostName("serverA.internal.company.address");
connectionFactory.setPort(1414);
did the trick for us.
You are on exactly the correct track - but please do review this technote for information.
http://www-01.ibm.com/support/docview.wss?uid=swg21508357

Categories