tilln / jmeter-iso8583

ISO8583 Plugin for JMeter
MIT License
62 stars 32 forks source link

Send message to mq with “queue name, channel name, …” through jmeter-iso8583 plugin #73

Closed mehrdad2000 closed 6 months ago

mehrdad2000 commented 7 months ago

I try to send message from jmeter-iso8583 to mq, but it’s not work.

here is the my current JSR223 sampler that work correctly and send “mymessage“ to mq, now question is how can i send output of iso8583 plugin to mq server? Is it possible to add “queue manager, channel, user, pass, queue name,…) in connection manager of jmeter-iso8583?

import com.ibm.jms.JMSTextMessage; import com.ibm.mq.jms.*; import com.ibm.msg.client.wmq.WMQConstants;

import javax.jms.JMSException; import javax.jms.Session;

MQQueueConnectionFactory cf = new MQQueueConnectionFactory(); cf.setHostName("192.168.1.1"); cf.setPort(1443); // or other port cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); cf.setQueueManager("qm"); cf.setChannel("my.SVRCONN"); cf.setStringProperty(WMQConstants.USERID, "user"); cf.setStringProperty(WMQConstants.PASSWORD, "pass"); connection = (MQQueueConnection) cf.createQueueConnection(); MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); MQQueue queue = (MQQueue) session.createQueue("queue:///my.queue"); MQQueueSender sender = (MQQueueSender) session.createSender(queue); JMSTextMessage message = (JMSTextMessage) session.createTextMessage("mymessage"); connection.start(); sender.send(message);

tilln commented 7 months ago

Hi @mehrdad2000

You have to write your own Channel Class that wraps the JMS objects.

It would have to implement ISOChannel to be able to connect, send, receive etc. via JMS queue.

It should implement Configurable so you can pass in required properties via the test plan, for example:

image

Below is an example of how you would access those properties.

You would also have to convert the ISOMsg that the ISO8583 Sampler generates into an appropriate JMS message, see below for an example.

public class JMSChannel implements ISOChannel, Configurable {
    MQQueueConnectionFactory cf;
    // etc., your other JMS objects

    public void setConfiguration(Configuration cfg) throws ConfigurationException {
        // From common "Channel Settings":
        cf.setHostName(cfg.get("host"));
        cf.setPort(cfg.getInt("port"));
        // From "Advanced Configuration":
        cf.setQueueManager(cfg.get("queueManager"));
        cf.setChannel(cfg.get("channel"));
        // etc., your other config properties
    }

    public void send(ISOMsg isoMsg) throws IOException, ISOException {
        // Assuming your messages are sent as bytes rather than text:
        BytesMessage jmsMsg = session.createBytesMessage();
        jmsMsg.writeBytes(isoMsg.pack());
        sender.send(jmsMsg);
    }
   // etc., other methods
}

Most other ISOChannels extend BaseChannel for sending messages via all sorts of network/TCP connections, so you may want to have a look at how that is done.

I hope this gives you some ideas and a starting point.

mehrdad2000 commented 7 months ago

@tilln Thank you for answer, would you please consider this as feature request and add channel for “jms channel”? it would be useful feature for anyone who need send jms message.

Thanks

tilln commented 7 months ago

@mehrdad2000 I'm happy to consider pull requests that add useful features.

mehrdad2000 commented 7 months ago

@tilln should i do anything?

tilln commented 7 months ago

@mehrdad2000 how about implementing that channel class? Or do you expect me to write your code for you?

mehrdad2000 commented 7 months ago

Ok, I'm newbie in this case. if you guide me step by step I'll write it and create merge request.

github-actions[bot] commented 6 months ago

This issue is stale because it has been open for 30 days with no activity.

github-actions[bot] commented 6 months ago

This issue was closed because it has been inactive for 14 days since being marked as stale.

mehrdad2000 commented 3 months ago

@tilln instead of write class from scratch, is it possible to generate message with iso8583 plugin then pass to "jms publisher" or "java request" and send to mq?

tilln commented 3 months ago

@mehrdad2000 Theoretically, it is possible, and you could re-use some functionality of this plugin, however, you would end up writing quite a bit of code too. The challenge is that the ISO8583 Sampler builds the ISOMsg and expects to send it over the Channel. If you don't want to send but only generate the message, you would have to avoid the Sampler altogether and re-write all the message generation. So I suppose you're better off just creating that Channel class.

mehrdad2000 commented 3 months ago

@tilln ok i’ll try to write below java code use base-channel as you mentioned, after compile this code it generates class file. What should i do next? Should i put class file in lib/ext directory of jmeter? Or it should be add into the iso8583.jar file to jmeter detect it?

Here is the code:

package org.jpos.iso.channel;

import com.ibm.jms.JMSTextMessage;
import com.ibm.mq.jms.*;
import com.ibm.msg.client.wmq.WMQConstants;
import org.jpos.iso.ISOChannel;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.BaseChannel;
import org.jpos.core.Configuration;
import org.jpos.core.Configurable;
import org.jpos.core.ConfigurationException;

import javax.jms.*;

public class JMSChannel extends BaseChannel implements ISOChannel, Configurable {
    private MQQueueConnectionFactory cf;
    private MQQueueConnection connection;
    private MQQueueSession session;
    private MQQueueSender sender;

    public void setConfiguration(Configuration cfg) throws ConfigurationException {
        try {
            cf = new MQQueueConnectionFactory();
            cf.setHostName(cfg.get("host"));
            cf.setPort(cfg.getInt("port")); 
            cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
            cf.setQueueManager(cfg.get("queueManager"));
            cf.setChannel(cfg.get("channel"));
            cf.setStringProperty(WMQConstants.USERID, cfg.get("user"));
            cf.setStringProperty(WMQConstants.PASSWORD, cfg.get("pass"));

            connection = (MQQueueConnection) cf.createQueueConnection();
            session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
            MQQueue queue = (MQQueue) session.createQueue(cfg.get("qname"));
            sender = (MQQueueSender) session.createSender(queue);
            JMSTextMessage message = (JMSTextMessage) session.createTextMessage("MYMESSAGE");

            connection.start();
            sender.send(message);                                

        } catch (JMSException e) {
            throw new ConfigurationException(e);
        }
    }          
}
tilln commented 3 months ago

@mehrdad2000 You may want to look at the JMeter documentation.

mehrdad2000 commented 3 months ago

@tilln already read that page, the question is which is better? 1-create single jar file that contain this JMSChannel.class 2-add JMSChannel.class to jpos-2.1.8.jar file that exist in lib directory of Jmeter in this path "org.jpos.iso.channel.JMSChannel.class"

FYI: also try number2 got below error, when i start test:

image

2024-03-30 13:28:17,387 ERROR n.c.b.j.i.Q2: (org.jpos.q2.iso.ChannelAdaptor) error starting service
2024-03-30 13:28:17,387 ERROR n.c.b.j.i.Q2: (org.jpos.q2.iso.ChannelAdaptor) JMSChannel
org.jpos.core.ConfigurationException: JMSChannel
    at org.jpos.q2.QFactory.newInstance(QFactory.java:307) ~[jpos-2.1.8.jar:2.1.8]
    at org.jpos.q2.iso.ChannelAdaptor.newChannel(ChannelAdaptor.java:197) ~[jpos-2.1.8.jar:2.1.8]
    at org.jpos.q2.iso.ChannelAdaptor.initChannel(ChannelAdaptor.java:253) ~[jpos-2.1.8.jar:2.1.8]
    at org.jpos.q2.iso.ChannelAdaptor.startService(ChannelAdaptor.java:76) [jpos-2.1.8.jar:2.1.8]
    at org.jpos.q2.QBeanSupport.start(QBeanSupport.java:137) [jpos-2.1.8.jar:2.1.8]
    at jdk.internal.reflect.GeneratedMethodAccessor37.invoke(Unknown Source) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71) [?:?]
    at jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:260) [?:?]
    at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:112) [?:?]
    at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:46) [?:?]
    at com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(MBeanIntrospector.java:237) [?:?]
    at com.sun.jmx.mbeanserver.PerInterface.invoke(PerInterface.java:138) [?:?]
    at com.sun.jmx.mbeanserver.MBeanSupport.invoke(MBeanSupport.java:252) [?:?]
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:809) [?:?]
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) [?:?]
    at org.jpos.q2.QFactory.startQBean(QFactory.java:176) [jpos-2.1.8.jar:2.1.8]
    at nz.co.breakpoint.jmeter.iso8583.ISO8583Config.deployAndStart(ISO8583Config.java:364) [jmeter-iso8583-1.4-SNAPSHOT.jar:?]
    at nz.co.breakpoint.jmeter.iso8583.ISO8583Config.startChannelAdaptor(ISO8583Config.java:283) [jmeter-iso8583-1.4-SNAPSHOT.jar:?]
    at nz.co.breakpoint.jmeter.iso8583.ISO8583Config.testStarted(ISO8583Config.java:467) [jmeter-iso8583-1.4-SNAPSHOT.jar:?]
    at org.apache.jmeter.engine.StandardJMeterEngine.notifyTestListenersOfStart(StandardJMeterEngine.java:246) [ApacheJMeter_core.jar:5.6.2]
    at org.apache.jmeter.engine.StandardJMeterEngine.run(StandardJMeterEngine.java:424) [ApacheJMeter_core.jar:5.6.2]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
    at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
    at java.lang.Thread.run(Thread.java:829) [?:?]

Any idea? Thanks

tilln commented 3 months ago

@mehrdad2000

the question is which is better?

I cannot answer that without knowing your quality criteria. Both should work though.

org.jpos.core.ConfigurationException: JMSChannel

Instead of JMSChannel you have to use the fully qualified class name in you JMeter script, e.g. org.jpos.iso.channel.JMSChannel.

mehrdad2000 commented 3 months ago

@tilln try it too image

tilln commented 3 months ago

Your source file is missing the package declaration.

mehrdad2000 commented 3 months ago

@tilln declare package name and return exception error: package org.jpos.iso.channel.JMSChannel1;

image

FYI: filled host, port, from “Channel Settings”, And queueManager, channel from “Advanced Configuration”

tilln commented 3 months ago

@mehrdad2000 Your package name must not include the class name: package org.jpos.iso.channel;

mehrdad2000 commented 3 months ago

@tilln ok, now modified code and pass that exception, now I'll able to send "MYMESSAGE" to destination successfully.

now need to put iso8583 message that generate by sampler instead of "MYMESSAGE".

any idea? Thanks

mehrdad2000 commented 3 months ago

@tilln instead of this line that you mentioned create new message: BytesMessage jmsMsg = session.createBytesMessage(); need to get iso8583 sampler output to replace with "MYMESSAGE".

I’ll try to enable debug code but can’t find any error or log that let me inspect issue deeply. I try to send bytes, and didn’t return any error and run but mq didn’t receive message, and not show any error:

public void send(ISOMsg isoMsg) throws IOException, ISOException {
        try {
            // Create a BytesMessage
            BytesMessage jmsMsg = session.createBytesMessage();

            // Pack the ISO message and write its bytes to the JMS message
            jmsMsg.writeBytes(isoMsg.pack());

            // Send the JMS message

            sender.send(jmsMsg);
        } catch (JMSException e) {
            throw new ISOException("Error sending JMS message", e);
        }
    }

Also try to sent as text, instead of BytesMessage, same result:

public void send(ISOMsg isoMsg) throws ISOException {
    try {
        // Create a TextMessage
        TextMessage jmsMsg = session.createTextMessage();

        // Set the text content of the JMS message
        jmsMsg.setText(new String(isoMsg.pack(), "ISO-8859-1")); // Assuming ISO-8859-1 encoding

        // Send the JMS message
        sender.send(jmsMsg);
    } catch (JMSException | UnsupportedEncodingException e) {

        throw new ISOException("Error sending JMS message", e);
    }
}

image

Any Idea? Thanks