Solved

Unexpected HttpURLConnection connection behavior

Posted on 2016-10-19
2
113 Views
Last Modified: 2016-10-20
Greetings.

I am converting an Applet into a Desktop Application, and one of the internal program's services includes a SOAP client, designed to send information to a remote server. Here is a piece of the code in charge of this process:

package my.package.app.utils;

import my.package.app.main.MainClass;
import my.package.app.org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SoapClient {
    
    public static JSONObject callMethod(String path, String method, Object... args) {
        HttpURLConnection connection = null;
        String            data       = null;
        try {
            data = parseXML(method, args);
            
            MainClass.debug("Making http POST connections to : " + path);
            
            URL           u  = new URL(path);
            URLConnection uc = u.openConnection();
            connection = (HttpURLConnection) uc;
            
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("SOAPAction", method);
            connection.setUseCaches(false);
            
            OutputStream out  = connection.getOutputStream();
            Writer       wout = new OutputStreamWriter(out);
            
            wout.write(data);
            wout.flush();
            wout.close();
            
            InputStream            in  = connection.getInputStream();
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder        db  = dbf.newDocumentBuilder();
            Document               doc = db.parse(in);
            
            doc.getDocumentElement().normalize();
            
            NodeList childs       = doc.getElementsByTagName("return");
            String   responseText = childs.item(0).getTextContent();
            
            if ("false".equals(responseText)) {
                return null;
            }
            
            JSONObject response = new JSONObject(responseText);
            
            in.close();
            return response;
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        return null;
    }
    
    private static String parseXML(String method, Object... args) {
        
        StringBuilder xml = new StringBuilder();
        
        xml.append(XMLTemplates.soapHeader);
        xml.append("<ns1:");
        xml.append(method);
        xml.append(">");
        
        for (int i = 0; i < args.length; i++) {
            
            String dataType = "xsi:type=\"xsd:string\"";
            
            xml.append("<param");
            xml.append(i);
            xml.append(" ");
            
            if (args[i] instanceof Integer) {
                dataType = "xsi:type=\"xsd:integer\"";
            }
            
            if (args[i] instanceof Double) {
                dataType = "xsi:type=\"xsd:decimal\"";
            }
            
            if (args[i] instanceof Boolean) {
                dataType = "xsi:type=\"xsd:boolean\"";
            }
            
            xml.append(dataType);
            xml.append(">");
            xml.append(String.valueOf(args[i]));
            xml.append("</param");
            xml.append(i);
            xml.append(">");
        }
        
        xml.append("</ns1:");
        xml.append(method);
        xml.append(">");
        
        xml.append(XMLTemplates.soapFooter);
        
        return xml.toString();
    }
    
}

Open in new window


When the callMethod  is used, it received in my case a path string with an URL with HTTPS protocol like this: "https://fileserver.myserver.net:9000/lf_soap_document_server_main.php".

When running the callMethod with that URL, the applet's Java console displays the following:

18:15:45.476-DEBUG: Making http POST connections to : https://fileserver.myserver.net:9000/lf_soap_document_server_main.php
network: Connecting https://fileserver.myserver.net:9000/lf_soap_document_server_main.php with proxy=DIRECT
network: Connecting http://fileserver.myserver.net:9000/ with proxy=DIRECT

Open in new window


and the process completes successfully.

But when the same piece of code, with the same information is executed from the Desktop Application version, the following happens:

18:28:29.991-DEBUG: Making http POST connections to : https://fileserver.myserver.net:9000/lf_soap_document_server_main.php
network: Connecting https://fileserver.myserver.net:9000/lf_soap_document_server_main.php with proxy=DIRECT
network: Connecting socket://fileserver.myserver.net:9000 with proxy=DIRECT
java.net.ConnectException: Connection timed out: connect

Open in new window


Here the problems occurs when OutputStream out  = connection.getOutputStream(); is called. And please note that the log message changes the protocol of the URL from https:// to socket://, and also seems to remove the last slash (/).

This is the full exception:
java.net.ConnectException: Connection timed out: connect
  at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
  at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
  at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
  at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
  at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
  at java.net.PlainSocketImpl.connect(Unknown Source)
  at java.net.SocksSocketImpl.connect(Unknown Source)
  at java.net.Socket.connect(Unknown Source)
  at sun.security.ssl.SSLSocketImpl.connect(Unknown Source)
  at sun.net.NetworkClient.doConnect(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.protocol.https.HttpsClient.<init>(Unknown Source)
  at sun.net.www.protocol.https.HttpsClient.New(Unknown Source)
  at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$6.run(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$6.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.AccessController.doPrivilegedWithCombiner(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
  at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.access$100(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$8.run(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$8.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.AccessController.doPrivilegedWithCombiner(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
  at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
  at my.package.app.utils.SoapClient.callMethod(SoapClient.java:42)
  at my.package.app.services.scanner.LFScanner$SoapUpload.run(LFScanner.java:746)

Open in new window


The desktop application uses Jetty to create a connection to a secure websocket server, and also creates a local websocket server in the user's machine, but none of them has business with the SoapClient class where the problem happens.

I have tested setting a 5 minutes timeout for connection and read to the HttpURLConnection instance but the problem keeps happening on the desktop application in less than a minute.

I am using 1.8.0_111-b14 as runtime to execute the programs (applet and desktop application), on a Windows 10 machine, 64 bits.

I need to know if there is anything wrong with this code, or if there is a missing setting here to prevent this from happening.

Any help is highly appreciated.

Thanks.
0
Comment
Question by:lfmaleon
2 Comments
 
LVL 35

Accepted Solution

by:
mccarl earned 500 total points
ID: 41851491
Looking at the lines in your console output that start with "network:", my guess is that your application is installing some custom functionality that is logging those lines, and handling the redirection/scheme change and proxy details. It is probably doing this via the Socket.setSocketImplFactory() method. This maybe Jetty or some other part of your code, but the problem with the above is that it applies JVM wide. Can you try extracting just your SoapClient class above, into a totally separate project and running it standalone? I'm guessing that you WON'T see those "network:" lines and that it might just work, which will at least tell us if it is some other part of the app that is affecting the connection behaviour. If so, then you will have to dig further to find out what is being configued elsewhere in the app.
0
 

Author Comment

by:lfmaleon
ID: 41852540
I did as mccarl suggested, and found that the isolated piece of code is failing sometimes as well, and sometimes it passes through correctly. I then tested in depth the SOAP URL and found that the general availability of that service is not 100% which explains the behavior of both programs.

It was more like a coincidence that the Applet code passes through and the Desktop Application code doesn't. But in the end the problem is the SOAP server itself.

Thanks for the suggestion.
0

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Since pre-biblical times, humans have sought ways to keep secrets, and share the secrets selectively.  This article explores the ways PHP can be used to hide and encrypt information.
This video teaches users how to migrate an existing Wordpress website to a new domain.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question