JTOpen ProgramCall Socket Timeout - java

I'm working on a web app (running on Tomcat) that calls programs on an IBM i (AS/400) using the JTOpen ProgramCall class (com.ibm.as400.access.ProgramCall). My problem is with program calls that take more than 30s to respond, which are triggering a java.net.SocketTimeoutException: Read timed out exception.
There is a setTimeout() method available for this class, but it doesn't seem to have an effect on the socket timeout. I've also checked my Tomcat configurations and didn't see anything that would cause this behavior.
Does anyone know of a way to alter the timeout for such an implementation?
Code:
pgmCall.setProgram(getCompleteName(), parmList);
initializeAS400TextParameters();
// Run the AS/400 program.
try {
Trace.setTraceDiagnosticOn(true);
Trace.setTraceInformationOn(true);
Trace.setTraceWarningOn(true);
Trace.setTraceErrorOn(true);
Trace.setTraceDatastreamOn(true);
if (pgmCall.run() != true) {
messageList = pgmCall.getMessageList();
for (int i = 0; i < messageList.length; i++) {
log.debug("Error Message " + i + " " + messageList[i]);
}
setCompletionMsg("Program call failed.");
log.debug("442 Program call failed.");
return false;
} else {
messageList = pgmCall.getMessageList();
for (int i = 0; i < messageList.length; i++) {
log.debug("Success Message " + i + " " + messageList[i]);
}
setCompletionMsg("Program called ok.");
log.debug("452 Program called ok.");
return true;
}
} catch (Exception e) {
// This is where the timeout exception is thrown
log.debug("Error Running Program: " + e.getMessage() + " " + e.getLocalizedMessage());
setCompletionMsg(e.getMessage());
}

Well, after several more hours I've found the solution. Apparently the original developer added a socket timeout parameter to the JDBC connection string - simply removing the parameter did the trick as the default value is 0, or infinite timeout.
Before:
String connectionStr = "jdbc:as400://" + systemInfo.getIPAddress() + ":1527" + ";naming=system;socket timeout=30000;thread used=false;errors=full;prompt=false;date format=iso;block size=128;transaction isolation=none;user=" + systemInfo.getUserName() + ";password=" + systemInfo.getPassword();
After:
String connectionStr = "jdbc:as400://" + systemInfo.getIPAddress() + ":1527" + ";naming=system;thread used=false;errors=full;prompt=false;date format=iso;block size=128;transaction isolation=none;user=" + systemInfo.getUserName() + ";password=" + systemInfo.getPassword();
:\

Related

How to avoid Stack Overflow errors in infinitely recursive method?

I know there are tons of posts about stack overflow errors and i understand why my specific one is happening, my question is basically how to move away from recursion in this specific case. I have a class which establishes and maintains a client connection (for HL7 messaging specifically but it's essentially a glorified client connection) to another system which hosts corresponding server connections. This class' constructor starts a new thread and runs the following method :
#Override
public void connect()
{
try
{
setStatus("Connecting");
connection = context.newClient(intfc.getIp(), port, false);
connected = true;
setStatus("Connected");
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully connected " + connectionType + " client connection to "
+ intfc.getName() + "(" + intfc.getIp() + ") on port " + port);
monitor();
}
catch (HL7Exception ex)
{
connected = false;
setStatus("Disconnected");
try
{
TimeUnit.SECONDS.sleep(connectionRetryIntervalInSeconds);
connect();
}
catch (InterruptedException ex2)
{}
}
}
Upon successfully connecting with the server, the monitor method simply checks, in yet another thread, if the connection is still up at a given interval. If it goes down, the monitoring thread is interrupted and the connect() method is called again.
I did not anticipate this at first but you can quickly see why the connect() method is causing stack overflow errors after several days running. I'm struggling to think of a way to get the same functionality to work without the connect method calling itself again every time the connection fails.
Any suggestions would be appreciated.
Thanks!
Typically you'd use a Stack object to emulate recursion when required.
However, in your case, why are you using recursion at all? A while loop fits the purpose.
while(true /**or some relevant condition**/){
try{ //try to connect
....
catch(HL7Exception ex){
//sleep
}
}
I'm not sure of the purpose of your application, but there are may be better methods than sleeping. You could use a ScheduledExecutorService, but if it's a single threaded program with one purpose it's probably unnecessary.
When I had to deal with this issue in c# I used a Stack, and added new classes to it, instead of using recursion. Then a second loop would check to see if there were any objects in the stack that needed dealing with. That avoided stack overflow when I would have had huge amounts of recursion otherwise. Is there a similar Stack collection in Java?
Why are you calling the monitor() method in the first place? You mention that it is launched in a separate thread, then can't you just launch it in a new thread when the application comes up? Then there won't be a recursive call.
I changed my code to an iterative approach as suggested, works beautifully!
#Override
public void initThread()
{
initConnectionEntity();
mainThread = new Thread()
{
#Override
public void run()
{
while (running)
{
if (!connected)
{
try
{
connect();
}
catch (HL7Exception ex)
{
connected = false;
setStatus("Disconnected");
try
{
TimeUnit.SECONDS.sleep(connectionRetryIntervalInSeconds);
}
catch (InterruptedException ex2)
{}
}
}
try
{
TimeUnit.MILLISECONDS.sleep(500);
}
catch (InterruptedException ex2)
{}
}
}
};
mainThread.setName(intfc.getName() + " " + connectionType + " Main Thread");
mainThread.start();
}
#Override
public void connect() throws HL7Exception
{
setStatus("Connecting");
connection = context.newClient(intfc.getIp(), port, false);
connected = true;
setStatus("Connected");
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully connected " + connectionType + " client connection to "
+ intfc.getName() + "(" + intfc.getIp() + ") on port " + port);
monitor();
}
private void monitor()
{
monitoringThread = new Thread()
{
#Override
public void run()
{
try
{
while (running)
{
if (!connection.isOpen())
{
if (connected == true)
{
logEntryService.logWarning(LogEntry.CONNECTIVITY, "Lost " + connectionType + " connection to "
+ intfc.getName() + "(" + intfc.getIp() + ") on port " + port);
}
connected = false;
setStatus("Disconnected");
monitoringThread.interrupt();
}
else
{
connected = true;
}
TimeUnit.SECONDS.sleep(connectionMonitorIntervalInSeconds);
}
}
catch (InterruptedException ex)
{
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Monitoring thread for " + connectionType
+ " connection to " + intfc.getName() + " interrupted");
}
}
};
monitoringThread.setName(intfc.getName() + " " + connectionType + " Monitoring Thread");
monitoringThread.start();
}

Could not establish socket with any provided host Openfire

I've been searching for a solution for this problem for 2 days now..
I have an android chat application that I want to implement sending files into it.
Here's the sending code:
public void sendFile(Uri uri) {
FileTransferManager fileTransferManager = FileTransferManager.getInstanceFor(app.getConnection());
OutgoingFileTransfer fileTransfer = fileTransferManager.createOutgoingFileTransfer(userId + "/Spark");
try {
fileTransfer.sendFile(new File(uri.getPath()), "this is the description");
System.out.println("status is:" + fileTransfer.getStatus());
System.out.println("sent .. just");
while (!fileTransfer.isDone()) {
if (fileTransfer.getStatus() == FileTransfer.Status.refused) {
Toast.makeText(getActivity(), "File refused.", Toast.LENGTH_SHORT).show();
return;
}
if (fileTransfer.getStatus() == FileTransfer.Status.error) {
Toast.makeText(getActivity(), "Error occured.", Toast.LENGTH_SHORT).show();
return;
}
}
System.out.println(fileTransfer.getFileName() + "has been successfully transferred.");
System.out.println("The Transfer is " + fileTransfer.isDone());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
I know this code works fine as I sent file from android to spark and received it successfully.. The problem is in receiving that file in android.. Here's the code:
ProviderManager.addIQProvider("si", "http://jabber.org/protocol/si",
new StreamInitiationProvider());
ProviderManager.addIQProvider("query", "http://jabber.org/protocol/bytestreams",
new BytestreamsProvider());
ProviderManager.addIQProvider("open", "http://jabber.org/protocol/ibb",
new OpenIQProvider());
ProviderManager.addIQProvider("close", "http://jabber.org/protocol/ibb",
new CloseIQProvider());
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature("http://jabber.org/protocol/disco#info");
sdm.addFeature("jabber:iq:privacy");
final FileTransferManager manager = FileTransferManager.getInstanceFor(connection);
manager.addFileTransferListener(new FileTransferListener() {
public void fileTransferRequest(FileTransferRequest request) {
IncomingFileTransfer transfer = request.accept();
try {
File file = new File(Environment.getExternalStorageDirectory() + "/" + request.getFileName());
Log.i("Tawasol", "File Name: " + request.getFileName());
transfer.recieveFile(file);
while (!transfer.isDone() || (transfer.getProgress() < 1)) {
Thread.sleep(1000);
Log.i("Tawasol", "still receiving : " + (transfer.getProgress()) + " status " + transfer.getStatus());
if (transfer.getStatus().equals(org.jivesoftware.smackx.filetransfer.FileTransfer.Status.error)) {
// Log.i("Error file",
// transfer.getError().getMessage());
Log.i("Tawasol",
"cancelling still receiving : "
+ (transfer.getProgress())
+ " status "
+ transfer.getStatus() + ": " + transfer.getException().toString());
transfer.cancel();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
still receiving : 0.0 status Negotiating Stream
I get this log for about 5 seconds the I get that:
cancelling still receiving : 0.0 status Error: org.jivesoftware.smack.SmackException: Error in execution
I think that the problem is in the openfire server that I'm using.. I've openfire 3.9.3 server installed on my windows 7 64bit.. In the Smack logs I noticed this one:
<iq id="L87BF-73" to="59xrd#rightsho/Smack" type="set" from="h97qa#rightsho/Spark"><query xmlns="http://jabber.org/protocol/bytestreams" sid="jsi_4840101552711519219" mode="tcp"><streamhost jid="proxy.rightsho" host="192.168.56.1" port="7777"/></query></iq>
The host here is 192.168.56.1 which I think is local ip so that I can't access it from android.. So I wan't to use the IP of the pc to transfer files..
Excuse me for my lack of knowledge in this field.
From my little knowledge of smack the issue may be in this piece of code:
while (!transfer.isDone() || (transfer.getProgress() < 1)) {
Thread.sleep(1000);
Log.i("Tawasol", "still receiving : " + (transfer.getProgress()) + " status " + transfer.getStatus());
if (transfer.getStatus().equals(org.jivesoftware.smackx.filetransfer.FileTransfer.Status.error)) {
// Log.i("Error file",
// transfer.getError().getMessage());
Log.i("Tawasol",
"cancelling still receiving : "
+ (transfer.getProgress())
+ " status "
+ transfer.getStatus() + ": " + transfer.getException().toString());
transfer.cancel();
break;
}
}
If you move the monitoring while loop to another thread, suddenly this error goes away. I'm not sure why, but it has worked for me and my friends in the past.

Blackberry Connection Nightmare

I'm busy writing a Program that Transmits GPS Coordinates to a Server from a mobile phone where the coordinates are then used for calculations. But I'm constantly hitting a wall with blackberry. I have built the Android App and it works great but can't seem to contact the server on a real blackberry device. I have tested the application in a simulator and it works perfectly but when I install it on a real phone I get no request the phone.
I have read quite a bit about the secret strings to append at the end of the url so I adapted some demo code to get me the first available transport but still nothing ...
The Application is Signed and I normally then either install it by debugging through eclipse or directly on the device from the .jad file and allow the application the required permissions.
The current code was adapted from the HTTP Connection Demo in the Blackberry SDK.
Could you have a look and give me some direction. I'm losing too much hair here ...
The Backend Service that keeps running:
public void run() {
System.out.println("Starting Loop");
Criteria cr = new Criteria();
cr.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
cr.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
cr.setCostAllowed(false);
cr.setPreferredPowerConsumption(Criteria.NO_REQUIREMENT);
cr.setPreferredResponseTime(1000);
LocationProvider lp = null;
try {
lp = LocationProvider.getInstance(cr);
} catch (LocationException e) {
System.out.println("*****************Exception" + e);
}
if (lp == null) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("GPS not supported!");
return;
}
});
} else {
System.out
.println(lp.getState() + "-" + LocationProvider.AVAILABLE);
switch (lp.getState()) {
case LocationProvider.AVAILABLE:
// System.out.println("Provider is AVAILABLE");
while (true) {
Location l = null;
int timeout = 120;
try {
l = lp.getLocation(timeout);
final Location fi = l;
System.out.println("Got a Coordinate "
+ l.getQualifiedCoordinates().getLatitude()
+ ", "
+ l.getQualifiedCoordinates().getLongitude());
System.out.println("http://" + Constants.website_base
+ "/apis/location?device_uid=" + Constants.uid
+ "&lat="
+ l.getQualifiedCoordinates().getLatitude()
+ "&lng="
+ l.getQualifiedCoordinates().getLongitude());
if (!_connectionThread.isStarted()) {
fetchPage("http://"
+ Constants.website_base
+ "/apis/location?device_uid="
+ Constants.uid
+ "&lat="
+ l.getQualifiedCoordinates().getLatitude()
+ "&lng="
+ l.getQualifiedCoordinates()
.getLongitude());
} else {
createNewFetch("http://"
+ Constants.website_base
+ "/apis/location?device_uid="
+ Constants.uid
+ "&lat="
+ l.getQualifiedCoordinates().getLatitude()
+ "&lng="
+ l.getQualifiedCoordinates()
.getLongitude());
}
Thread.sleep(1000 * 60);
} catch (LocationException e) {
System.out.println("Location timeout");
} catch (InterruptedException e) {
System.out.println("InterruptedException"
+ e.getMessage());
} catch (Exception ex) {
System.err.println(ex.getMessage());
ex.printStackTrace();
}
}
}
}
My Connection is Made with:
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc = connFact.getConnection(getUrl());
// Open the connection and extract the data.
try {
// StreamConnection s = null;
// s = (StreamConnection) Connector.open(getUrl());
HttpConnection httpConn = (HttpConnection) connDesc.getConnection();
/* Data is Read here with a Input Stream */
Any Ideas ?
Figured it out!
Using a function I found online to determine which ; extension to use when connecting by using numerous Try / Catch. Then had to set the Internet APN settings. I'm in South-Africa using Vodacom so the APN is "Internet" with no Password.
Barely have hair left ....

IOException doesn't give enough information

My android program isn't working. I am using normal client-server sockets. I have tested my server with telnet and it works fine, but when I try it with my android program, it doesn't work (more details in a second). Here's my code:
Socket s = null;
try
{
String SocketServerAddress = db.getPhSsServerAddress();
Integer SocketServerPort = db.getPhSsServerPort();
s = new Socket(SocketServerAddress, SocketServerPort);
Log.d(MY_DEBUG_TAG, "Setting up Socket: " + SocketServerAddress + ":" + SocketServerPort);
DataOutputStream out = new DataOutputStream(s.getOutputStream());
DataInputStream in = new DataInputStream(s.getInputStream());
Log.d(MY_DEBUG_TAG, "Connected to: " + s.getInetAddress() + " on port " + s.getPort());
out.writeUTF("Helo, Server");
out.flush();
Log.d(MY_DEBUG_TAG, "Bytes written: " + out.size());
String st = in.readUTF();
Log.d(MY_DEBUG_TAG, "SocketServerResponse: " + st);
}
catch (UnknownHostException e)
{
Log.e(MY_ERROR_TAG, "UnknownHostException: " + e.getMessage() + "; " + e.getCause());
}
catch (IOException e)
{
Log.e(MY_ERROR_TAG, "IOException: " + e.getMessage() + "; " + e.getCause() + "; " + e.getLocalizedMessage());
}
finally
{
try {
s.close();
} catch (IOException e) {
Log.e(MY_ERROR_TAG, "IOException on socket.close(): " + e.getMessage() + "; " + e.getCause());
}
}
All I ever get here is a thrown IOException with no message or cause attached. The specific line causing the error is the String st = in.readUTF(). If I comment out that line, my code runs fine (no exceptions thrown), but my server does not acknowledge that any data has been sent to it. And of course I don't get any data back since that line is commented out.
So, how can I figure out what the problem is? Tonight I am going to try and see what is being passed with wireshark to see if that gives any insight.
Is the server using readUTF() and writeUTF() too? writeUTF() writes data in a unique format that can only be understood by readUTF(), which won't understand anything else.
EDIT EOFException means that there is no more data. You should catch it separately and handle it by closing the socket etc. It can certainly be caused spuriously by readUTF() trying to read data that wasn't written with writeUTF().
And deciding it was an IOException when it was really an EOFException means you didn't print out or log the exception itself, just its message. Always use the log methods provided for exceptions, or at least use Exception.toString().
As I remember I had a problem with DataInpuStream some day... try doing so:
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

closing MQ connection

Good afternoon, I wrote a project to Get Park Queue Info from the IBM MQ, it has producing an error when attempting to close the connection though. It is written in java.
Under application in Event Viewer on the MQ machine it displays two errors. They are:
“Channel program ended abnormally.
Channel program ‘system.def.surconn’ ended abnormally. Look at previous error messages for channel program ‘system.def.surconn’ in the error files to determine the cause of the failure.
The other message states:
“Error on receive from host rnanaj (10.10.12.34)
An error occurred receiving data from rnanaj (10.10.12.34) over tcp/ip. This may be due to a communications failure. The return code from tcp/ip recv() call was 10054 (X’2746’). Record these values.”
This must be something how I try to connect or close the connection, below I have my code to connect and close, any ideas??
Connect:
_logger.info("Start");
File outputFile = new File(System.getProperty("PROJECT_HOME"), "run/" + this.getClass().getSimpleName() + "." + System.getProperty("qmgr") + ".txt");
FileUtils.mkdirs(outputFile.getParentFile());
Connection jmsConn = null;
Session jmsSession = null;
QueueBrowser queueBrowser = null;
BufferedWriter commandsBw = null;
try {
// get queue connection
MQConnectionFactory MQConn = new MQConnectionFactory();
MQConn.setHostName(System.getProperty("host"));
MQConn.setPort(Integer.valueOf(System.getProperty("port")));
MQConn.setQueueManager(System.getProperty("qmgr"));
MQConn.setChannel("SYSTEM.DEF.SVRCONN");
MQConn.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
jmsConn = (Connection) MQConn.createConnection();
jmsSession = jmsConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue jmsQueue = jmsSession.createQueue("PARK");
// browse thru messages
queueBrowser = jmsSession.createBrowser(jmsQueue);
Enumeration msgEnum = queueBrowser.getEnumeration();
commandsBw = new BufferedWriter(new FileWriter(outputFile));
//
String line = "DateTime\tMsgID\tOrigMsgID\tCorrelationID\tComputerName\tSubsystem\tDispatcherName\tProcessor\tJobID\tErrorMsg";
commandsBw.write(line);
commandsBw.newLine();
while (msgEnum.hasMoreElements()) {
Message message = (Message) msgEnum.nextElement();
line = dateFormatter.format(new Date(message.getJMSTimestamp()))
+ "\t" + message.getJMSMessageID()
+ "\t" + message.getStringProperty("pkd_orig_jms_msg_id")
+ "\t" + message.getJMSCorrelationID()
+ "\t" + message.getStringProperty("pkd_computer_name")
+ "\t" + message.getStringProperty("pkd_subsystem")
+ "\t" + message.getStringProperty("pkd_dispatcher_name")
+ "\t" + message.getStringProperty("pkd_processor")
+ "\t" + message.getStringProperty("pkd_job_id")
+ "\t" + message.getStringProperty("pkd_sysex_msg");
_logger.info(line);
commandsBw.write(line);
commandsBw.newLine();
}
}
Close:
finally {
IO.close(commandsBw);
if (queueBrowser != null) { try { queueBrowser.close();} catch (Exception ignore) {}}
if (jmsSession != null) { try { jmsSession.close();} catch (Exception ignore) {}}
if (jmsConn != null) { try { jmsConn.stop();} catch (Exception ignore) {}}
}
As per the Javadoc for the connection object, the function of the stop() method is...
Temporarily stops a connection's
delivery of incoming messages.
So stop() doesn't actually sever the connection. You want the close() method.

Categories

Resources