Solved

Unexpected HttpURLConnection connection behavior

Posted on 2016-10-19
2
140 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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

Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Bootstrap list items overlap 3 36
Level out logo and increase size? 16 26
MS Access VBA How To Properly Set Up A multipart/related HTTP Request 13 71
Java array 10 63
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 article will inform Clients about common and important expectations from the freelancers (Experts) who are looking at your Gig.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).

733 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