Skip to content

Commit 88a16ea

Browse files
authored
Merge pull request #24 from ibm-messaging/rich-workshop-updates
added .bat and .sh helper scripts and new interactive Java JMS sample
2 parents caa0c4a + daeecf7 commit 88a16ea

File tree

3 files changed

+684
-0
lines changed

3 files changed

+684
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
/*
2+
* (c) Copyright IBM Corporation 2018 - 2025
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.ibm.mq.samples.jms;
18+
19+
import java.io.Console;
20+
import javax.jms.Destination;
21+
import javax.jms.JMSConsumer;
22+
import javax.jms.JMSContext;
23+
import javax.jms.JMSException;
24+
import javax.jms.JMSProducer;
25+
import javax.jms.TextMessage;
26+
27+
import com.ibm.msg.client.jms.JmsConnectionFactory;
28+
import com.ibm.msg.client.jms.JmsFactoryFactory;
29+
import com.ibm.msg.client.wmq.WMQConstants;
30+
31+
/**
32+
* A minimal and simple application for Intereactive Point-to-point messaging.
33+
*
34+
* Application makes use of fixed literals, any customisations will require
35+
* re-compilation of this source file. Application assumes that the named queue
36+
* is empty prior to a run.
37+
*
38+
* Notes:
39+
*
40+
* API type: JMS API (v2.0, simplified domain)
41+
*
42+
* Messaging domain: Point-to-point
43+
*
44+
* Provider type: IBM MQ
45+
*
46+
* Connection mode: Client connection
47+
*
48+
* JNDI in use: No
49+
*
50+
*/
51+
public class JmsPutGetInteractive {
52+
53+
// Java console colour settings to make Put and Get easier to follow
54+
private static final String BACKGROUND_BLACK = "\u001B[40m";
55+
private static final String BACKGROUND_WHITE = "\u001B[47m";
56+
private static final String TEXT_BLACK = "\u001B[30m";
57+
private static final String TEXT_WHITE = "\u001B[37m";
58+
private static final String DEFAULT_TEXT = "\u001B[0m";
59+
60+
// Constants for very simple console logging method
61+
private static final int MSG = 0;
62+
private static final int INFO = 1;
63+
private static final int WARNING = 2;
64+
private static final int ERROR = 3;
65+
66+
// Boolean flags to coordinate JMS Put and Get operstions
67+
private static Boolean doGet = true;
68+
private static Boolean doPut = true;
69+
// Set doTls true for TLS, TLS is off (false) by default
70+
private static Boolean doTls = false;
71+
72+
// System exit status value (assume unset value to be 1)
73+
private static int status = 1;
74+
75+
/*
76+
* Set your JMS Connection Factory Variables HERE
77+
*/
78+
// Create variables for the connection to MQ
79+
private static String HOST = "_YOUR_HOSTNAME_";
80+
private static int PORT = 1414;
81+
private static String CHANNEL = "DEV.APP.SVRCONN";
82+
private static String QMGR = "QM1";
83+
private static String APP_USER = "app";
84+
private static String APP_PASSWORD = "_APP_PASSWORD_";
85+
private static String QUEUE_NAME = "DEV.QUEUE.1";
86+
/*
87+
* Note: you should not need to edit below this line for the workshop
88+
*/
89+
90+
91+
/**
92+
* Main method
93+
*
94+
* @param args
95+
*/
96+
public static void main(String[] args) {
97+
98+
parseArgs(args);
99+
100+
// JMS object variables
101+
JMSContext context = null;
102+
Destination destination = null;
103+
JMSProducer producer = null;
104+
JMSConsumer consumer = null;
105+
106+
try {
107+
// Create a connection factory
108+
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
109+
JmsConnectionFactory cf = ff.createConnectionFactory();
110+
111+
// Set the properties
112+
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, HOST);
113+
cf.setIntProperty(WMQConstants.WMQ_PORT, PORT);
114+
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, CHANNEL);
115+
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
116+
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QMGR);
117+
cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "JmsPutGet (JMS)");
118+
cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
119+
cf.setStringProperty(WMQConstants.USERID, APP_USER);
120+
cf.setStringProperty(WMQConstants.PASSWORD, APP_PASSWORD);
121+
if (doTls) {
122+
cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER");
123+
}
124+
125+
// Create JMS objects
126+
context = cf.createContext();
127+
destination = context.createQueue("queue:///" + QUEUE_NAME);
128+
129+
if (doPut) {
130+
long uniqueNumber = System.currentTimeMillis() % 1000;
131+
TextMessage message = context.createTextMessage("Your lucky number today is " + uniqueNumber);
132+
133+
producer = context.createProducer();
134+
producer.send(destination, message);
135+
logOutput(INFO, "Sent message:\n" + message);
136+
if (doGet) {
137+
Console c = System.console();
138+
logOutput(MSG, BACKGROUND_WHITE + TEXT_BLACK + "Ready to receive a message?" + DEFAULT_TEXT);
139+
logOutput(MSG, BACKGROUND_BLACK + TEXT_WHITE + "Press the Enter key to continue ..."
140+
+ DEFAULT_TEXT);
141+
c.readLine();
142+
}
143+
}
144+
145+
if (doGet) {
146+
int waitTime = 15000; // in ms or 15 seconds
147+
consumer = context.createConsumer(destination); // autoclosable
148+
String receivedMessage = null;
149+
if (!doPut) { // if this is a get only operation then display message
150+
TextMessage message = (TextMessage) consumer.receive(waitTime);
151+
if (message != null) {
152+
logOutput(INFO, "Received message:\n" + message);
153+
receivedMessage = message.getText();
154+
}
155+
} else {
156+
receivedMessage = consumer.receiveBody(String.class, waitTime);
157+
}
158+
if (receivedMessage != null) {
159+
logOutput(INFO, "\nReceived message payload:\n" + receivedMessage);
160+
} else {
161+
logOutput(INFO, "No Message Received Within " + waitTime + "ms");
162+
}
163+
}
164+
165+
context.close();
166+
recordSuccess();
167+
} catch (JMSException jmsex) {
168+
recordFailure(jmsex);
169+
}
170+
171+
System.exit(status);
172+
173+
} // end main()
174+
175+
/**
176+
* Record this run as successful.
177+
*/
178+
private static void recordSuccess() {
179+
logOutput(MSG, "SUCCESS");
180+
status = 0;
181+
return;
182+
}
183+
184+
/**
185+
* Record this run as failure.
186+
*
187+
* @param ex
188+
*/
189+
private static void recordFailure(Exception ex) {
190+
if (ex != null) {
191+
if (ex instanceof JMSException) {
192+
processJMSException((JMSException) ex);
193+
} else {
194+
System.out.println(ex);
195+
}
196+
}
197+
System.out.println("FAILURE");
198+
status = -1;
199+
return;
200+
}
201+
202+
/**
203+
* Process a JMSException and any associated inner exceptions.
204+
*
205+
* @param jmsex
206+
*/
207+
private static void processJMSException(JMSException jmsex) {
208+
System.out.println(jmsex);
209+
Throwable innerException = jmsex.getLinkedException();
210+
if (innerException != null) {
211+
System.out.println("Inner exception(s):");
212+
}
213+
while (innerException != null) {
214+
System.out.println(innerException);
215+
innerException = innerException.getCause();
216+
}
217+
return;
218+
}
219+
220+
/**
221+
* Log output to console in a consistent way.
222+
*
223+
* @param level the log level to output
224+
* @param message the message to log
225+
*/
226+
private static void logOutput(int level, String message) {
227+
String eyeCatcher = "#### ";
228+
String tag = "";
229+
switch (level) {
230+
case 0:
231+
tag = " ";
232+
break;
233+
case 1:
234+
tag = eyeCatcher + "INFO: ";
235+
break;
236+
case 2:
237+
tag = eyeCatcher + "WARNING: ";
238+
break;
239+
case 3:
240+
tag = eyeCatcher + "ERROR: ";
241+
break;
242+
default:
243+
tag = "";
244+
}
245+
//Print output to console
246+
System.out.println(tag + message);
247+
}
248+
249+
/**
250+
* Helper method to parse the args[] from the command line.
251+
*
252+
* @param args the list of argument passed to the main method
253+
*
254+
*/
255+
private static void parseArgs(String args[]) {
256+
System.out.println(""); // Presentation padding on console
257+
// Sanity check main() arguments and warn user
258+
if (args.length > 0) {
259+
logOutput(WARNING,
260+
"You have provided arguments to the Java main() function. JVM arguments (such as -Djavax.net.ssl.trustStore) must be passed before the main class or .jar you wish to run.\n\n");
261+
262+
// Parse command line arguments, assuming name value pairs
263+
String option = null;
264+
String value = null;
265+
for (int i = 0; i < args.length; i += 2) { // iterate 2: name,value
266+
option = args[i].toLowerCase(); // force lower case
267+
268+
// Check the option and cast the value as needed
269+
switch (option) {
270+
case "-host": // hostname
271+
HOST = getValue(option, args, i);
272+
logOutput(INFO, "Host [" + HOST + "]");
273+
break;
274+
case "-p": // port number
275+
try {
276+
PORT = Integer.parseInt(getValue(option, args, i));
277+
} catch (NumberFormatException nfe) {
278+
status = -1;
279+
logOutput(ERROR, "Unabale to parse value \"" + value + "\" specified for option \""
280+
+ option + "\"");
281+
System.exit(status);
282+
}
283+
logOutput(INFO, "Port [" + PORT + "]");
284+
break;
285+
case "-c": // channel name
286+
CHANNEL = getValue(option, args, i);
287+
logOutput(INFO, "Channel [" + CHANNEL + "]");
288+
break;
289+
case "-qm":
290+
QMGR = getValue(option, args, i);
291+
logOutput(INFO, "Queue Manager [" + QMGR + "]");
292+
break;
293+
case "-u":
294+
APP_USER = getValue(option, args, i);
295+
logOutput(INFO, "App User [" + APP_USER + "]");
296+
break;
297+
case "-pw":
298+
APP_PASSWORD = getValue(option, args, i);
299+
logOutput(INFO, "Password [" + "******" + "]");
300+
break;
301+
case "-q":
302+
QUEUE_NAME = getValue(option, args, i);
303+
logOutput(INFO, "Queue [" + QUEUE_NAME + "]");
304+
break;
305+
case "-t":
306+
i--; // no value for boolean flags, so realign
307+
doTls = true;
308+
logOutput(INFO, "TLS enabled");
309+
break;
310+
case "-put":
311+
i--; // no value for boolean flags, so realign
312+
doGet = false;
313+
logOutput(INFO, "put only mode");
314+
break;
315+
case "-get":
316+
i--; // no value for boolean flags, so realign
317+
doPut = false;
318+
logOutput(INFO, "get only mode");
319+
break;
320+
default:
321+
status = -1;
322+
if (!(option.equals("-h") || option.equals("-help"))) {
323+
status = 0;
324+
logOutput(ERROR, "Invalid option: \"" + option + "\"");
325+
}
326+
logOutput(INFO, "Usage:");
327+
logOutput(MSG, "Welcome to " + JmsPutGetInteractive.class.getSimpleName());
328+
logOutput(MSG, "A JMS Put and Get utility for the IBM MQ Developer Essential Workshop.");
329+
logOutput(MSG,
330+
"The default bahavior is to generate a random number and add this number to a new message payload. The message is then produced and then consumed from the specified queue. The following command line options are available. ");
331+
logOutput(MSG, ""); // Padding
332+
logOutput(MSG, "Options:");
333+
logOutput(MSG, "-help | -h Displays this message.");
334+
logOutput(MSG, "-host <hostname> Specifiy hostname");
335+
logOutput(MSG, "-p <port_number> Specifiy port number");
336+
logOutput(MSG, "-c <channel> Specifiy channel");
337+
logOutput(MSG, "-qm <qm_name> Specifiy queue manager name");
338+
logOutput(MSG, "-u <app_user> Specifiy App User name");
339+
logOutput(MSG, "-pw <password> Specifiy hostname");
340+
logOutput(MSG, "-q <queue_name> Specifiy queue name");
341+
logOutput(MSG, "-put Put only mode");
342+
logOutput(MSG, "-get Get only mode");
343+
logOutput(MSG, "-t TLS mode");
344+
logOutput(MSG, "");
345+
System.exit(status);
346+
}
347+
}
348+
349+
if (!doPut && !doGet) {
350+
// Both -put and -get must have been set as options
351+
doPut = true;
352+
doGet = true;
353+
}
354+
}
355+
}
356+
357+
/**
358+
* Get the next value in the args[] array i.e., the option value.
359+
*
360+
* @param option current option in scope
361+
* @param args the list of argument passed to the main method
362+
* @param index current position in the args list
363+
* @return the value set for the current option in scope
364+
*/
365+
private static String getValue(String option, String[] args, int index) {
366+
String theValue = null;
367+
if (args.length > index + 1) {
368+
theValue = args[index + 1];
369+
} else {
370+
logOutput(ERROR, "No value provided for option \"" + option + "\"");
371+
System.exit(status);
372+
}
373+
return theValue;
374+
}
375+
}

0 commit comments

Comments
 (0)