0

I am new to Websphere MQ (IBM z/OS) technologies. We had a requirement to implement a standalone application that uses JMS technology to connect to an MQ server (on IBM z/OS. This is maintained by a different organization for which we have only limited access) and put a message on the queue.

Here are pieces of my code below.

private void sendMessage(String queue, String msg) {
        JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
        JmsConnectionFactory cf = ff.createConnectionFactory();

        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, queueManagerName);
        cf.setStringProperty(WMQConstants.USERID, user);
        cf.setStringProperty(WMQConstants.PASSWORD, password);

    Connection connection = null;
    Session session = null;
    Destination destination = null;
    MessageProducer producer = null;


        connection = cf.createConnection(user, password);
        session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        destination = session.createQueue(queue);
        //((MQDestination)destination).setCCSID(37);
        producer = session.createProducer(destination);

        TextMessage message = session.createTextMessage();
        message.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 37);
        //message.setIntProperty(WMQConstants.JMS_IBM_ENCODING, 785);

        message.setText(msg);
        // Start the connection
        connection.start();

        // And, send the message
        producer.send(message);
}

I was successfully able to connect to the MQ server on the other end and put the messages on the remote server in ASCII format. I was able to consume the message that I have put on the queue from an AIX server.

But since the MQ is running on z/OS and the consumer is also an Mainframe application the message I put appears to be a garbage/unreadable format. After some research I figured out that messages needs to be converted to EBCDIC to be put on z/OS MQ. I expected that this will be taken care of by the IBM MQ libraries.

Please help on how can I put the messages in EBCDIC format.

4 Answers4

3

You are doing this wrong:

message.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 37);

You need to declare the character set that you are putting on the queue. Since that looks like Java, I'm assuming it is a UTF-16 string. Declare it as 1208, not 37.

On the other end, if they want it in EBCDIC, they will do a GET-With-Convert, declaring that they want to receive it in IBM 37/1140 and MQ will invoke Unicode Conversion Services for z/OS and make it happen.

Joe Zitzelberger
  • 4,238
  • 2
  • 28
  • 42
  • Thanks Joe. The person on the other end who is consuming the message is expecting that the message will be in EBCDIC format. I am not sure how I an put the message in the queue in EBCDIC. When they see in the queue the message is appearing in this format. 622756 RFH u MQSTR _ ( ¦_ ¬ –  Mar 30 '15 at 17:07
  • If they will not do the get with convert, you will have to preconvert the string before you put it on the queue, then you can declare it to MQ as code page IBM 37/1140. You can use the encoder class (java.text.Encoding IIRC) to convert to other character sets. But MQ has no PUT-With-Convert, only a GET. – Joe Zitzelberger Mar 31 '15 at 04:31
  • Although, as a skanky hack, you could put to a local queue, then get the same message with convert into 37/1140, then send the resulting message. – Joe Zitzelberger Mar 31 '15 at 04:32
  • Thanks a lot Joe. I appreciate your help. I am doing an manual conversion of data and putting it in the queue since we don't have a local MQ setup on our side. –  Mar 31 '15 at 13:02
1

More importantly, if your receiver is not a Java client, you need to disable the JMS header as follows:

destination = session.createQueue("queue:///" + queue + "?targetClient=1")

or by invoking the Native MQ implementation :

((MQDestination)destination).setMessageBodyStyle(WMQConstants.WMQ_MESSAGE_BODY_MQ)

See:

https://www-01.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.dev.doc/q032120_.htm

https://www-01.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.dev.doc/q032140_.htm?lang=en

http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.0.1/com.ibm.mq.csqzaw.doc/jm10910_.htm

Stavr00
  • 3,219
  • 1
  • 16
  • 28
0

To store your message in a non-standard-encoding you will have to use BytesMessage instead of TextMessage. This might work (untested!):

byte[] messageBytes = msg.getBytes("IBM037");
BytesMessage message = session.createBytesMessage();
message.writeBytes(messageBytes);

But it would be preferable to have the given message-encoding respected at the consuming side - that's why you put it there.

piet.t
  • 11,718
  • 21
  • 43
  • 52
0

If possible, use MQ's MQGMO convert option to convert into the local machine's character set. But if you want (or can't) use that mechanism, you can also implement your own character set translation to have full control. For example:

  //---------------------------------------------------
  //Character Translation Table for: IBM500
  private static char[] EBCDIC2ASCII_IBM500 = new char[] {

    0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15, 
    16, 17, 18, 19, 157, 10, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31, 
    128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7, 
    144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26, 
    32, 160, 226, 228, 224, 225, 227, 229, 231, 241, 91, 46, 60, 40, 43, 33, 
    38, 233, 234, 235, 232, 237, 238, 239, 236, 223, 93, 36, 42, 41, 59, 94, 
    45, 47, 194, 196, 192, 193, 195, 197, 199, 209, 166, 44, 37, 95, 62, 63, 
    248, 201, 202, 203, 200, 205, 206, 207, 204, 96, 58, 35, 64, 39, 61, 34, 
    216, 97, 98, 99, 100, 101, 102, 103, 104, 105, 171, 187, 240, 253, 254, 177, 
    176, 106, 107, 108, 109, 110, 111, 112, 113, 114, 170, 186, 230, 184, 198, 164, 
    181, 126, 115, 116, 117, 118, 119, 120, 121, 122, 161, 191, 208, 221, 222, 174, 
    162, 163, 165, 183, 169, 167, 182, 188, 189, 190, 172, 124, 175, 168, 180, 215, 
    123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 173, 244, 246, 242, 243, 245, 
    125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 185, 251, 252, 249, 250, 255, 
    92, 247, 83, 84, 85, 86, 87, 88, 89, 90, 178, 212, 214, 210, 211, 213, 
    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 179, 219, 220, 217, 218, 159
  };

  private static char[] ASCII2EBCDIC_IBM500 = new char[] {
      0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, 
      16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, 
      64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97, 
      240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111, 
      124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214, 
      215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109, 
      121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150, 
      151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 187, 208, 161, 7, 
      32, 33, 34, 35, 36, 0, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, 
      48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 255, 
      65, 170, 176, 177, 159, 178, 106, 181, 189, 180, 154, 138, 186, 202, 175, 188, 
      144, 143, 234, 250, 190, 160, 182, 179, 157, 218, 155, 139, 183, 184, 185, 171, 
      100, 101, 98, 102, 99, 103, 158, 104, 116, 113, 114, 115, 120, 117, 118, 119, 
      172, 105, 237, 238, 235, 239, 236, 191, 128, 253, 254, 251, 252, 173, 174, 89, 
      68, 69, 66, 70, 67, 71, 156, 72, 84, 81, 82, 83, 88, 85, 86, 87, 
      140, 73, 205, 206, 203, 207, 204, 225, 112, 221, 222, 219, 220, 141, 142, 223
      };

  public static void main(String[] args)
  {
    String ebcdic = "" + (char)0xC1 + (char)0xC2 + (char)0xC3;
    System.err.println("ebcdic: " + ebcdic);

    String ascii = "";
    for( char c: ebcdic.toCharArray() ) {

      ascii += EBCDIC2ASCII_IBM500[c];
    }
    System.err.println("ascii:  " + ascii);

    ebcdic="";
    for( char c: ascii.toCharArray() ) {

      ebcdic += ASCII2EBCDIC_IBM500[c];
    }
    System.err.println("ebcdic: " + ebcdic);
  }

And here's the code to create these tables:

public static void createTranslationTable(Charset charset)
 {
   System.out.println();
   System.out.println("// ---------------------------------------------------" );
   System.out.println("// Character Translation Tables for: " + charset.name() );

   byte[] b = new byte[256];
   for( int i=0;i<256;i++ ) b[i] = (byte)i;

   String s = "";
   try {
     s = new String(b,charset.name());
   }
   catch (UnsupportedEncodingException e) {
     e.printStackTrace();
   }

   int[] inverse = new int[256];

   System.out.println("unsigned char EBCDIC2ASCII_" + charset.name() + "[256] = {");
   for( int i=0;i<256;i++ ) {

     int c = s.charAt(i); // %256;
     if( c>255 ) c=i;
     inverse[c] = i;

     System.out.print( c + (i<255?", ":"") );
     if( i%16==15 ) System.out.println();
   }
   System.out.println("};");

   System.out.println("unsigned char ASCII2EBCDIC_" + charset.name() + "[256] = {");

   for( int i=0;i<256;i++ ) {

     int c = inverse[i]; // %256;
     System.out.print( c + (i<255?", ":"") );
     if( i%16==15 ) System.out.println();
   }

   System.out.println("};");
 }

And you could use it like this:

 createTranslationTable( Charset.forName("CP037") );
Axel Podehl
  • 4,034
  • 29
  • 41
  • I think this is not answering the question. The OP wanted to know how to put a EBCDIC message to a queue from JMS, not how to get it as ASCII. I think the method you mention could be used to translate to EBCDIC before put but the CCSID would need to set to match. Also note based on comments to another answer the RHF2 header turned out to be the problem and seems to match the accepted answer. – JoshMc Jan 21 '20 at 13:56
  • well, I think he could translate the JAva String from ascii to EBCDIC with the second loop: ebcdic += ASCII2EBCDIC_IBM500[c]; and then set and send that String in the TextMessage – Axel Podehl Jan 21 '20 at 15:51