I am currently facing a problem right now wherein I am getting the error I/O error occurred. and I don't know how to pin point where the error occurred. This happened when I get a message queue from the queue. Below is the stack trace of the error.
StackTrace: at AlertTrigger.Data.ServiceAgents.WebSphereAgent.GetMessageQueue(String queueManagerName, String queueName)
at AlertTrigger.Business.AlertTriggerComponent.QueueListener()
Below is the code for the GetMessageQueue:
public string GetMessageQueue(string queueManagerName, string queueName)
{
MQQueueManager mqQueueManager;
MQQueue storeQueue;
string result = string.Empty;
try
{
MQMessage mqMessage = new MQMessage();
MQGetMessageOptions mqGetMessageOption = new MQGetMessageOptions();
mqGetMessageOption.Options = MQC.MQGMO_WAIT;
mqGetMessageOption.WaitInterval = 15000;
mqQueueManager = new MQQueueManager(queueManagerName);
storeQueue = mqQueueManager.AccessQueue(queueName, MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING);
storeQueue.Get(mqMessage, mqGetMessageOption);
result = mqMessage.ReadString(mqMessage.DataLength);
}
catch (MQException MQEx)
{
// Close request Queue if still opened
if (storeQueue != null && storeQueue.OpenStatus)
storeQueue.Close();
// Close Queue manager if still opened
if (mqQueueManager != null && mqQueueManager.OpenStatus)
mqQueueManager.Close();
throw new MQAdapterException(MQEx.Reason.ToString());
//throw new MQAdapterException("Error Code: " + MQAdapterErrorReasons.GetMQFailureReasonErrorCode(MQEx.Reason));
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
// Close request Queue if still opened
if (storeQueue != null && storeQueue.OpenStatus)
storeQueue.Close();
// Close Queue manager if still opened
if (mqQueueManager != null && mqQueueManager.OpenStatus)
mqQueueManager.Close();
}
return result;
}
I hope you can help me on this as I am quite new to WebSphere MQ.
Is this a Java or C# application? If it is Java, you should do:
result = mqMessage.ReadString(mqMessage.getMessageLength());
Related
MQQueue get call fails to retrieve the message from the queue with 2033 (07F1) (RC2033): MQRC_NO_MSG_AVAILABLE error. I am using the following code to get the message from the queue:
GET message:
byte[] replyMessageBytes = null;
try {
this.replyConnection.open();
MQQueue replyQueue = this.replyConnection.getQueue(CMQC.MQOO_INPUT_AS_Q_DEF);
if (null == replyQueue) {
logger.error("Could not create reply queue.");
throw new PFMCommunicationException("Could not create reply queue.");
}
MQMessage replyMessage = new MQMessage();
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.resolvedQueueName = replyQueue.getResolvedQName();
if (timeout.length > 0) {
try {
gmo.waitInterval = Integer.valueOf("" + timeout[0]);
} catch (NumberFormatException e) {
}
} else {
gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
}
gmo.options = MQConstants.MQGMO_WAIT;
if (null != correlationId) {
gmo.matchOptions = MQConstants.MQMO_MATCH_MSG_ID | MQConstants.MQMO_MATCH_CORREL_ID;
replyMessage.messageId = correlationId.getBytes();
replyMessage.correlationId = correlationId.getBytes();
} else {
gmo.matchOptions = MQConstants.MQMO_NONE;
replyMessage.messageId = MQConstants.MQMI_NONE;
replyMessage.correlationId = MQConstants.MQCI_NONE;
}
try {
replyQueue.get(replyMessage, gmo);
int length = replyMessage.getMessageLength();
replyMessageBytes = replyMessage.readStringOfByteLength(length).getBytes();
} catch (MQException e) {
logger.error("ERROR on receiving reply: CC=" + e.completionCode + " RC=" + e.reasonCode + " "
+ e.getMessage());
} catch (IOException e) {
logger.error("ERROR on receiving reply.", e);
}
if (null == replyMessageBytes) {
logger.error("No reply received.");
} else {
logger.debug("Received message: " + new String(replyMessageBytes));
}
} catch (MQException e) {
logger.error("ERROR:", e);
throw new PFMCommunicationException(e);
} catch (PFMConnectionException e) {
logger.error(e.getMessage());
throw new PFMCommunicationException(e);
} finally {
this.replyConnection.close();
logger.debug("Closed connection with MQ replies.");
}
I confirm that the message is present in the queue before the waitInterval expires and the correlationId also matches. In-fact, when I run the code without trying to match the correlationId, I am able to get the message. I guess this means either something is wrong with the response message or I am making a mistake creating the matchOptions properly.
gmo.matchOptions = MQConstants.MQMO_NONE;
replyMessage.messageId = MQConstants.MQMI_NONE;
replyMessage.correlationId = MQConstants.MQCI_NONE;
This is what my response message header looks like:
<Header Origin="DISPUTE1" Addressee="PSXDX2" Date="20180802" Time="123055" Area="QUERY" Content="RAddr" ID="8af3257cf01a4842bf5eec8d" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="cms/customerAccountDetails.xsd">
I tried with putting CorrelId instead of ID in the response header but it's still the same. Can someone please help me to find the issue?
if (null != correlationId) {
gmo.matchOptions = MQConstants.MQMO_MATCH_MSG_ID | MQConstants.MQMO_MATCH_CORREL_ID;
replyMessage.messageId = correlationId.getBytes();
replyMessage.correlationId = correlationId.getBytes();
}
Well, that's your problem. It would be extremely rare, if ever, that an MQ message would have the same value in BOTH the MsgId and CorrelId fields.
If you are getting a reply message for a request that you sent, and you saved the request message's MsgId after the MQPUT, then the code should be:
if (null != correlationId) {
gmo.matchOptions = MQConstants.MQMO_MATCH_CORREL_ID;
replyMessage.correlationId = correlationId.getBytes();
}
Note: You don't save the request (outbound) message's CorrelId but rather the MsgId. The server processing your request, should put the incoming MsgId in the reply message's CorrelId. Hence, that is why you ONLY match on CorrelId for the reply message.
I was try to send message to the MQ Server using the MQ Client
The error is:- A WebSphere MQ Error occurred : Completion Code 2 Reason Code 2058.I know this reason code because of the wrong Queue Manager Name..But the Queue Manager Name is correct...
After installed the WebSphere MQ Client I just run the command:
SET MQSERVER=QM_ORANGE/TCP/IPADDRESS(PORT NUMBER)
and run this program
public class MQSample {
// code identifier
static final String sccsid = "#(#) MQMBID sn=p750-002-131001_DE su=_FswqMCqGEeOZ3ui-rZDONA pn=MQJavaSamples/wmqjava/MQSample.java";
// define the name of the QueueManager
private static final String qManager = "QM_ORANGE";
// and define the name of the Queue
private static final String qName = "Q1";
/**
* Main entry point
*
* #param args - command line arguments (ignored)
*/
public static void main(String args[]) {
try {
// Create a connection to the QueueManager
System.out.println("Connecting to queue manager: " + qManager);
MQQueueManager qMgr = new MQQueueManager(qManager);
// Set up the options on the queue we wish to open
//int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_OUTPUT;
int openOptions = MQConstants.MQOO_OUTPUT;
// int openOptions1 = MQConstants.MQOO_INPUT_AS_Q_DEF;
// Now specify the queue that we wish to open and the open options
System.out.println("Accessing queue: " + qName);
MQQueue queue = qMgr.accessQueue(qName, openOptions);
//MQQueue queue1 = qMgr.accessQueue(qName, openOptions1);
// Define a simple WebSphere MQ Message ...
MQMessage msg = new MQMessage();
// ... and write some text in UTF8 format
msg.writeUTF("Hello, World!");
// Specify the default put message options
MQPutMessageOptions pmo = new MQPutMessageOptions();
// Put the message to the queue
System.out.println("Sending a message...");
queue.put(msg, pmo);
//
openOptions = MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING
+ MQC.MQOO_INPUT_SHARED;
queue = qMgr.accessQueue("QM_APPLE", openOptions,
null, // default q manager
null, // no dynamic q name
null); // no alternate user id
System.out.println("MQRead v1.0 connected.\n");
int depth = queue.getCurrentDepth();
System.out.println("Current depth: " + depth + "\n");
if (depth == 0) {
return;
}
MQGetMessageOptions getOptions = new MQGetMessageOptions();
getOptions.options = MQC.MQGMO_NO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING
+ MQC.MQGMO_CONVERT;
while (true) {
MQMessage message = new MQMessage();
try {
queue.get(message, getOptions);
byte[] b = new byte[message.getMessageLength()];
message.readFully(b);
System.out.println(new String(b));
message.clearMessage();
} catch (IOException e) {
System.out.println("IOException during GET: " + e.getMessage());
break;
} catch (MQException e) {
if (e.completionCode == 2
&& e.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) {
if (depth > 0) {
System.out.println("All messages read.");
}
} else {
System.out.println("GET Exception: " + e);
}
break;
}
}
queue.close();
//_queueManager.disconnect();
// Disconnect from the QueueManager
System.out.println("Disconnecting from the Queue Manager");
qMgr.disconnect();
System.out.println("Done!");
}
catch (MQException ex) {
System.out.println("A WebSphere MQ Error occured : Completion Code " + ex.completionCode
+ " Reason Code " + ex.reasonCode);
ex.printStackTrace();
for (Throwable t = ex.getCause(); t != null; t = t.getCause()) {
System.out.println("... Caused by ");
t.printStackTrace();
}
}
catch (java.io.IOException ex) {
System.out.println("An IOException occured whilst writing to the message buffer: " + ex);
}
return;
}
}
You have set the MQSERVER environment variable. MQ C Client understands this environment variable and accordingly connects to queue manager running on the machine specified in IP address. MQ Java does not behave in the same way.
In your application you have specified just the queue manager name in MQQueueManager constructor. This mean application wants to connect to queue manager running on the same machine via server bindings connection.
You could do as below to connect to queue manager: (change the host, port, channel and queue manager name). Note the sample is written with MQ v8 Java client.
Hashtable properties = new Hashtable<String, Object>();
properties.put(MQConstants.HOST_NAME_PROPERTY, "qm.mycomp.com");
properties.put(MQConstants.PORT_PROPERTY, 1414);
properties.put(MQConstants.CHANNEL_PROPERTY, "APP.SVRCONN");
properties.put(MQConstants.USE_MQCSP_AUTHENTICATION_PROPERTY,"true");
properties.put(MQConstants.USER_ID_PROPERTY, "myuserid");
properties.put(MQConstants.PASSWORD_PROPERTY, "passw0rd");
/**
* Connect to a queue manager
*/
MQQueueManager queueManager = new MQQueueManager("QM", properties);
Update
So you don't want to hard code connection parameters in your program? You can use the MQSERVER environment variable it self, get it, parse it and the connection parameters. You can also use a configuration file or a LDAP server to pull the connection information.
Update II
You have not read the MQ documentation at all. MQ Client is a set of libraries/jars/.net assemblies etc which expose APIs in different languages. You develop application using these APIs to communicate with queue manager. That is what you have done in your program above. Without these libraries you can't connect to a queue manager (many people think queue manager as server). When your application runs on the same machine as the queue manager, it is possible to communicate with queue manager over shared memory. But when running on different machine the communication is over TCP/IP (or SNA).
Hope this clears the confusion.
I'm trying to create an application for windows phone 7 which acts as a client and which sends requests to a server which is written in Java. The client supposed to send a request, and wait for an answer from the server.
My problem is that I can't seem to communicate with the server properly. When I tried testing it in a simple .NET C# program and used blocking calls such as socket.send() and socket.receive() it works but the Windows Phone application doesn't have blocking calls.
This is what the server (Java) does once it detects a connection:
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
String message = reader.readLine();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"));
writer.println("hiBack");
writer.close();
and this is how the client(C#) is implemented:
public void sendRequest()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var connectionOperation = new SocketAsyncEventArgs { RemoteEndPoint = new DnsEndPoint(server, serverPort) };
connectionOperation.Completed += new EventHandler<SocketAsyncEventArgs>(onConnectCompleted);
socket.ConnectAsync(connectionOperation);
}
private void onConnectCompleted(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success)
{
System.Console.WriteLine("Error! " + e.SocketError);
return;
}
var sendListener = new SocketAsyncEventArgs();
string msg = "hi";
var buffer = new System.Text.UTF8Encoding().GetBytes(msg + Environment.NewLine);
sendListener.SetBuffer(buffer, 0, buffer.Length);
sendListener = new SocketAsyncEventArgs { RemoteEndPoint = new DnsEndPoint(server, serverPort) };
sendListener.Completed += new EventHandler<SocketAsyncEventArgs>(onSendCompleted);
socket.SendToAsync(sendListener);
}
private void onSendCompleted(object sender, SocketAsyncEventArgs e)
{
socket.ReceiveAsync(e);
}
I've got a problem with the line: socket.SendToAsync(sendListener); on the C# side which end the program without doing anything (exit with return code 0).
the Java server starts it's work instantly when it detects the connection so it might also cause a problem?
What can I do to make the communication work?
I've been doing some very basic SNMP4J programming. All I want to do is send a simple "get" request but so far my responses have been null. I opened up wireshark and found that in the under Simple Network Management Protocol, my msgUserName is blank and I need that to be populated.
I thought I had set it using the following code:
Snmp snmp = new Snmp(transport);
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
transport.listen();
UsmUser user = new UsmUser(new OctetString("SNMPManager"), AuthSHA.ID,new OctetString("password"),null,null);
// add user to the USM
snmp.getUSM().addUser(user.getSecurityName(), user);
Am I going about it the wrong way? If not, how do I set the msgUserName as seen in my wireshark dump of the get-request? I'm very new to SNMP, so I'm essentially running off examples.
This is a working snmpset you can write snmp get same way.Snmp4j v2 and v3 not using same api classes.
private void snmpSetV3(VariableBinding[] bindings) throws TimeOutException, OperationFailed {
Snmp snmp = null;
try {
PDU pdu = new ScopedPDU();
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
snmp = new Snmp(new DefaultUdpTransportMapping());
snmp.getUSM().addUser(new OctetString(Username), new UsmUser(new OctetString(Username), AuthMD5.ID, new OctetString(Password), AuthMD5.ID, null));
ScopedPDU scopedPDU = (ScopedPDU) pdu;
scopedPDU.setType(PDU.SET);
scopedPDU.addAll(bindings);
UserTarget target = new UserTarget();
target.setAddress(new UdpAddress(IPAddress + "/" + Port));
target.setVersion(version); //SnmpConstants.version3
target.setRetries(retries);
target.setTimeout(timeout);
target.setSecurityLevel(securityLevel); //SecurityLevel.AUTH_NOPRIV
target.setSecurityName(new OctetString(Username));
snmp.listen();
ResponseEvent response = snmp.send(pdu, target);
if (response.getResponse() != null) {
PDU responsePDU = response.getResponse();
if (responsePDU != null) {
if (responsePDU.getErrorStatus() == PDU.noError) {
return;
}
throw new OperationFailed("Error: Request Failed, "
+ "Error Status = " + responsePDU.getErrorStatus()
+ ", Error Index = " + responsePDU.getErrorIndex()
+ ", Error Status Text = " + responsePDU.getErrorStatusText());
}
}
throw new TimeOutException("Error: Agent Timeout... ");
} catch (IOException e) {
throw new OperationFailed(e.getMessage(), e);
} finally {
if (snmp != null) {
try {
snmp.close();
} catch (IOException ex) {
_logger.error(ex.getMessage(), ex);
}
}
}
}
public bool AddEntity(int parentId, string description)
{
try
{
_connection.Open();
SqlCommand command = new SqlCommand("INSERT Structure (Path,Description) " +
"VALUES(" + GetPath(parentId) + ".GetDescendant(" + GetLastChildPath(parentId, 1) + ", NULL), " +
description + ")", _connection);
if (command.ExecuteNonQuery() <= 0) _success = false;
command.Connection.Close();
if (_success)
{
return true;
}
throw new Exception("An error has occured whilst trying to add a entity");
}
catch (Exception ex)
{
AddError(new ErrorModel("An error has occured whilst trying to add a entity", ErrorHelper.ErrorTypes.Critical, ex));
return false;
}
}
Is there a better way of handling the exceptions in the example above?
Thanks in advance for any help.
Clare
There's quite a few things wrong here.
a. You're using inline SQL and injecting what I can only assume to be user generated data into it. This is a security risk. Use a parameterised query.
b. You're exception handling is ok but this will leave the connection open if an error occurs. I'd write it like so:
public bool AddEntity(int parentId, string description)
{
try
{
//Assuming you have a string field called connection string
using(SqlConnection conn = new SqlConnection(_connectionString))
{
SqlParameter descriptionParam = new SqlParameter("#description", SqlDbType.VarChar, 11);
descriptionParam.Value = description;
SqlParameter parentIdParam = new SqlParameter("#parentId", SqlDbType.Int, 4);
parentIdParam.Value = parentId;
//Bit confused about the GetPath bit.
SqlCommand command = new SqlCommand("INSERT Structure (Path,Description) " +
"VALUES(" + GetPath(parentId) + ".GetDescendant(" + GetLastChildPath(parentId, 1) + ", NULL),#description)", conn);
command.Parameters.Add(descriptionParam);
if (command.ExecuteNonQuery() <= 0) _success = false;
}
if (_success)
{
return true;
}
//This isn't really an exception. You know an error has a occured handle it properly here.
throw new Exception("An error has occured whilst trying to add a entity");
}
catch (Exception ex)
{
AddError(new ErrorModel("An error has occured whilst trying to add a entity", ErrorHelper.ErrorTypes.Critical, ex));
return false;
}
You can take advantage of the IDisposable interface, and the power of a using block.
using(var connection = new Connection()) // Not sure what _connection is, in this method, so making pseudo-code
{
// ... work with connection
}
This will close the connection even if an exception is thrown. It turns into (more-or-less) this:
var connection = new Connection();
try
{
// ... work with connection
}
finally
{
connection.Dispose();
}
Dispose, in this case, will close the connection.