Solved

Unexpected HttpURLConnection connection behavior

Posted on 2016-10-19
2
185 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 36

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

Learn how to optimize MySQL for your business need

With the increasing importance of apps & networks in both business & personal interconnections, perfor. has become one of the key metrics of successful communication. This ebook is a hands-on business-case-driven guide to understanding MySQL query parameter tuning & database perf

Question has a verified solution.

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

Because your company can’t afford for you to make SEO mistakes, you’ll want to ensure you’re taking the right steps each and every time you post a new piece of content. This list of optimization do’s and don’ts can help you become an SEO wizard.
When crafting your “Why Us” page, there are a plethora of pitfalls to avoid. Follow these five tips, and you’ll be well on your way to creating an effective page.
The viewer will learn how to implement Singleton Design Pattern in Java.
The viewer will learn how to count occurrences of each item in an array.

630 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