以下 Java 程序是用于向 IBM MQ 发送消息的代码示例。这是用来说明问题的:
import com.ibm.mq.MQC;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQtheQueueMgr;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Hashtable;
import java.util.ResourceBundle;
@SuppressWarnings({ "rawtypes", "unchecked","deprecation" })
public class TestIBMMQ {
static String theQueueMgr;
static String theRequestQueue;
static String respQueue;
static String mesgId = null;
static String corrId = null;
static MQQueue objQueue = null;
static String replyQueue;
static String replyQmgr;
static boolean isSSLActive;
public TestIBMMQ() {
}
public static ResourceBundle getProperties(String file) {
ResourceBundle resourceBundle = ResourceBundle.getBundle(file);
return resourceBundle;
}
public static String getFileContent(String path) {
StringBuffer stringbuffer = null;
try {
File file = new File(path);
FileReader filereader = new FileReader(file);
BufferedReader bufferedreader = new BufferedReader(filereader);
stringbuffer = new StringBuffer();
String s = System.getProperty("line.separator");
String s1;
while ((s1 = bufferedreader.readLine()) != null) {
stringbuffer.append(s1);
stringbuffer.append(s);
}
filereader.close();
bufferedreader.close();
} catch (IOException ioexception) {
ioexception.printStackTrace();
}
return stringbuffer.toString();
}
public static void sendMessage(String msgText, MQtheQueueMgr qMgr, boolean isResponse) {
try {
String theQueueMgr = <fetch Queue Manager Name>;
String theRequestQueue = <fetch Request Queue Name>;
if (theRequestQueue != null && theRequestQueue.length() > 0) {
objQueue = qMgr.accessQueue(theRequestQueue, MQC.MQOO_OUTPUT, null, null, null);
} else {
System.out.println("Request Queue (request_queue) was not configured! Tool now tries to get any response..");
}
MQMessage mqmessage = new MQMessage();
// Added below 2 lines as per Mike's suggestion
if (resBund.getString("message_expiry") != null && resBund.getString("message_expiry").length() > 0) {
mqmessage.expiry = Integer.valueOf(resBund.getString("message_expiry"));
}
// The default value is MQC.MQEI_UNLIMITED (-1), which means that
// the message never expires.
System.out.println("Message expiry set to ... " + mqmessage.expiry);
if (!mesgId.equalsIgnoreCase("")) {
mqmessage.messageId = mesgId.getBytes();
// mqmessage.correlationId = mesgId.getBytes();
} else {
mqmessage.messageId = MQC.MQMI_NONE;
}
if (!corrId.equalsIgnoreCase("")) {
mqmessage.correlationId = corrId.getBytes();
} else {
mqmessage.correlationId = MQC.MQCI_NONE;
}
mqmessage.writeString(msgText);
if (!isResponse) {
mqmessage.replyTotheQueueMgrName = resBund.getString("replyToQmgr");
mqmessage.replyToQueueName = resBund.getString("replyToQueue");
}
MQPutMessageOptions mqputmessageoptions = new MQPutMessageOptions();
objQueue.put(mqmessage, mqputmessageoptions);
System.out.println("Message successfully PUT... ");
} catch (MQException mqexception) {
System.out.println("An MQSeries error occurred : Completion code " + mqexception.completionCode + " Reason code " + mqexception.reasonCode);
System.out.println(mqexception.getCause());
} catch (IOException ioexception1) {
System.out.println("An error occurred whilst writing to the message buffer: " + ioexception1);
ioexception1.printStackTrace();
} catch (Exception exception) {
System.out.println("An error occurred : " + exception.getMessage());
exception.printStackTrace();
} finally {
try {
if (objQueue != null)
objQueue.close();
// qMgr.disconnect();
} catch (MQException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void getAndPutMessage(MQtheQueueMgr qMgr) {
System.out.println("\n=========== GET Message ===========");
byte[] data = null;
try {
System.out.println("Getting message from queue - " + theRequestQueue + " .....");
MQGetMessageOptions getMessageOptions = new MQGetMessageOptions();
getMessageOptions.options = MQC.MQGMO_WAIT | MQC.MQGMO_COMPLETE_MSG;
MQMessage mqMsg = new MQMessage();
int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_BROWSE;
System.out.println("GET Message MQOPEN to theQueueMgr(" + theQueueMgr + "), queue(" + theRequestQueue + ")");
objQueue = null;
objQueue = qMgr.accessQueue(theRequestQueue, openOptions, null, null, null);
objQueue.get(mqMsg, getMessageOptions);
int msgLength = mqMsg.getTotalMessageLength();
replyQmgr = mqMsg.replyTotheQueueMgrName;
replyQueue = mqMsg.replyToQueueName;
System.out.println("Getting replyQMgr from header: " + replyQmgr);
System.out.println("Getting replyQueue from header: " + replyQueue);
data = new byte[msgLength];
mqMsg.readFully(data, 0, msgLength);
System.out.println("Get message completed");
if ((mqMsg.replyToQueueName != null && !"".equalsIgnoreCase(mqMsg.replyToQueueName)) || (mqMsg.replyTotheQueueMgrName != null && !"".equalsIgnoreCase(mqMsg.replyTotheQueueMgrName))) {
sendMessage(new String(data), qMgr, true);
} else {
System.out.println("Reply to Queue Mgr & Queue not set");
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MQException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws ATSException {
String prop;
if (args.length > 0) {
prop = args[0];
} else {
prop = "<some properties file...";
}
resBund = getProperties(prop);
// MQ Objects
theQueueMgr = resBund.getString("queue_manager");
theRequestQueue = resBund.getString("request_queue");
respQueue = resBund.getString("response_queue");
mesgId = resBund.getString("mesg_id");
corrId = resBund.getString("corrID");
MQtheQueueMgr qMgr = null;
Hashtable mqProperties = new Hashtable();
mqProperties.put(MQC.HOST_NAME_PROPERTY, resBund.getString("host"));
mqProperties.put(MQC.CHANNEL_PROPERTY, resBund.getString("channel"));
mqProperties.put(MQC.PORT_PROPERTY, Integer.parseInt(resBund.getString("port")));
mqProperties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
if (resBund.getString("ssl_active") != null && resBund.getString("ssl_active").equalsIgnoreCase("y")) {
isSSLActive = true;
System.setProperty("javax.net.ssl.trustStore", resBund.getString("sslmq.trust.store"));
System.setProperty("javax.net.ssl.keyStore", resBund.getString("sslmq.key.store"));
System.setProperty("javax.net.ssl.keyStorePassword", ATSPasswordEncoder.decode(resBund.getString("mqssl.keystore.pwd")));
}
try {
File targDir = new File(resBund.getString("msg_file_path"));
if (!isSSLActive) {
qMgr = new MQtheQueueMgr(theQueueMgr, mqProperties);
} else {
mqProperties.put(MQC.SSL_CIPHER_SUITE_PROPERTY, resBund.getString("sslmq.cipher.suite"));
qMgr = new MQtheQueueMgr(theQueueMgr, mqProperties);
}
if (resBund.getString("send_req") != null && resBund.getString("send_req").equalsIgnoreCase("y")) {
if (targDir.isDirectory()) {
for (File file : targDir.listFiles()) {
if (theRequestQueue != null && theRequestQueue.length() > 0) {
System.out.println(file.getName() + " is being sent to Queue ..... " + theRequestQueue);
sendMessage(getFileContent(file.getAbsolutePath()), qMgr, false);
}
}
}
}
if (qMgr != null) {
qMgr.disconnect();
qMgr = null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (qMgr != null) {
try {
qMgr.disconnect();
} catch (MQException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
qMgr = null;
}
}
}// main ends
}
MQ Server 安装在 Windows Server 2019 上,MQ Server 版本为 9.3。总的来说,上述Java程序或基于上述Java代码使用的整体方法运行良好。
运行上述程序的用户存在于两个域DEV和PROD中。我不明白为什么,但这就是它的工作原理。
使用上述 Java 程序执行 PUT 的用户帐户(DEV 和 PROD)将被添加到 MQ Server 的
mqm
和 admins
组中,并且还被分配了作为服务登录的权限。
为了测试向 MQ 服务器发送消息,用户使用其 DEV 帐户(域)登录到 DEV 机器,并运行上述程序,它将成功使用 SSL 执行 PUT 到 MQ 服务器。大多数时候没有问题。
据观察,如果用户登录 MQ 服务器(使用 DEV 或 PROD 帐户)来使用 MQ Explorer,例如使用 MQ Explorer 浏览 MQ 队列,那么在随机情况下,同一用户将不再是能够向 MQ 服务器发送消息,但所有其他用户都可以运行上面的程序向 MQ 发送消息。以下是在这种情况下收到的错误:
Java 程序错误:
com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2063'.
来自 C:\ProgramData\IBM\MQ\qmgrs\QueueMangerName rrors\AMQERR01 中的 MQ 服务器的错误:
----- amqrimna.c : 911 --------------------------------------------------------
11/21/2024 01:37:37 - Process(6976.19) User(MQ_USER) Program(amqzlaa0.exe)
Host(HOST_NAME) Installation(Installation2)
VRMF(9.3.5.0) QMgr(QueueMgrName)
Time(2024-11-21T07:37:37.774Z)
CommentInsert1(UNKNOWN (1722) - The RPC server is unavailable.)
AMQ7227W: IBM MQ encountered the following network error: UNKNOWN (1722) - The
RPC server is unavailable.
EXPLANATION:
MQ failed to successfully complete a network operation due to the specified
error. If the error is encountered on systems that are part of a Windows 2000
domain it can indicate incorrect DNS or WINS configuration.
ACTION:
Ensure that your network is functioning correctly. On the Windows platform
check DNS and/or WINS settings to ensure that domain controllers, used for
authentication or authorisation functions, are accessible.
----- amqzfubn.c : 4130 -------------------------------------------------------
11/21/2024 01:37:37 - Process(7556.6) User(MQ_USER) Program(amqrmppa.exe)
Host(HOST_NAME) Installation(Installation2)
VRMF(9.3.5.0) QMgr(QueueMgrName)
Time(2024-11-21T07:37:37.777Z)
ArithInsert1(2) ArithInsert2(2063)
CommentInsert1(windows_acc_running_java_program)
AMQ9557E: Queue Manager User ID initialization failed.
EXPLANATION:
The call to initialize a user ID failed with CompCode 2 and Reason 2063.
The channel MCA user at the time of the failure is 'windows_acc_running_java_program'. If an MQCSP
structure was sent by a client, the user ID in the MQCSP is ''. The user ID is
displayed as '*TOKEN' if the client supplied an authentication token in the
MQCSP structure.
The client remote user ID is ''. Any CHLAUTH rules applied prior to user
adoption were evaluated case-sensitively against this value.
ACTION:
Check for previous error messages that indicate the cause of the problem.
Correct the error and try again.
然后观察到,如果为登录 MQ 服务器的用户创建的用户帐户从 DEV 和 PROD 的
C:\USERS
中删除,并且相关用户帐户的 RegEdit
条目也从 Windows NT\ProfileList
中删除,检查权限和组成员分配,重新启动 MQ 服务器后,PUT 将使用上述 Java 程序成功运行。
在Linux上安装了新的MQ Server 9.3,并成功使用上述程序向Linux上的MQ Server发送消息,到目前为止我们没有遇到这个问题,可能是因为我们没有登录基于Linux的MQ Server。奇怪的是,我们没有向运行上述程序的用户的用户帐户授予任何权限,但它仍然可以正常工作。
知道如何解决这个问题吗?
我正在考虑创建一个特殊的用户帐户来登录 Windows 上的 MQ 服务器以使用 MQ Explorer。或者,在 DEV 服务器上(而不是在 MQ 服务器上)安装 MQ Explorer。
如果您有任何建议,请告诉我。
使用以下命令执行 PUT 的用户帐户(DEV 和 PROD) 将上面的Java程序添加到MQ的mqm和admins组中 服务器,并且还被分配了作为服务登录的权限。
这是一个极其糟糕的主意。您没有采取适当的 MQ 安全措施,而是将用户放入 mqm 组中。除了“mqm”用户 ID 之外,任何人都不应属于 mqm 组,就这样,故事结束了。 MQAdmin 应该/将会使用 sudo 来获得正确的权限。
MQ 错误消息显示服务器正在运行 MQ v9.3.5.0。您的 Java 应用程序使用哪个 MQ 客户端版本?对于不同版本的 MQ,您是否有不同的行为?
我将您的代码复制并粘贴到 Eclipse 中,并给出了大量错误。如果您要发布代码,请发布工作代码!!
这是什么:
import com.ibm.mq.MQtheQueueMgr;
为什么代码中有一个名为 getAndPutMessage() 的方法,但没有被任何其他方法调用?
错误消息为您提供了原因代码 2063 的原因:
客户端远程用户 ID 为“”。之前应用的任何 CHLAUTH 规则 用户采用率根据该值进行区分大小写的评估。
您的代码未设置 UserId(也未设置密码),因此 MQ 客户端库未填充 UserId(或密码)字段。
您似乎正在使用旧版本的 MQ 客户端 JAR 文件。这是真的吗?
如果您的 MQ 环境和 MQ 应用程序要经过安全检查,它就会失败。您应该执行以下操作:
mqProperties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
应改为:
mqProperties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
在Java应用程序中,设置应用程序的UserId和Password:
mqProperties.put(MQC.USER_ID_PROPERTY, "app_UID");
mqProperties.put(MQC.PASSWORD_PROPERTY, "app_pwd");
“MQC”类已折旧。您应该使用“MQConstants”类或“CMQC”类。