Search code examples
javaandroidsoapsaxhttpsurlconnection

How can I make it work HttpsURLConnection and SAX parser to be stable?


So I have used good ol' HttpClient without a problem, everything worked fine, until Android 6 hits, then I have to also add a HttpsURLConnection, since our clients unfortunately are not that fortunate to have new devices with more recent Android, so I add this code to my already developed network class:

public static HashMap<String, Object> callSOAPServer(StringBuffer soap, String action) {
    HttpsURLConnection urlConnection = null;
    boolean download = true;
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = IsakApp.appContext.getResources().openRawResource(R.raw.thawte);
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
            } finally {
                caInput.close();
            }

            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);

            URL url = new URL("whateverPage.com");

            urlConnection =
                    (HttpsURLConnection) url.openConnection();

            urlConnection.setSSLSocketFactory(context.getSocketFactory());


            urlConnection.setRequestMethod("POST");
            urlConnection.setConnectTimeout(20000);
            urlConnection.setReadTimeout(20000);
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.setRequestProperty("Content-type", "text/xml; charset=utf-8");
            urlConnection.setRequestProperty("SOAPAction", action);
            OutputStream reqStream = urlConnection.getOutputStream();
            reqStream.write(soap.toString().getBytes());

            InputStream resStream = urlConnection.getInputStream();


            byte[] data = new byte[1024 * 1024];

            ByteArrayOutputStream buffer = new ByteArrayOutputStream();

            int count = urlConnection.getContentLength();
            int total = 0;
            int size = 0;
            while ((count = resStream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, count);
           }

            buffer.flush();
            String str = new String(buffer.toByteArray(), "UTF-8");
            System.out.println("--------");
            System.out.println(str);
            String sn = str.replace("&amp;", "AMP");
            String[] stringArray = sn.split("\\r?\\n");
            String soapNew = stringArray[1];
            byte[] bytes = soapNew.getBytes("UTF-8");
            HashMap<String, Object> xMap = new HashMap<String, Object>();
            xMap.put(IsakApp.STATUS, "true");
            xMap.put("soap", bytes);
            resStream.close();

            return xMap;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if( urlConnection != null) {
                urlConnection.disconnect();
            }
        }
 }

So my problem is that this is vastly unreliable a does not always downloads all the data I need, but somewhat this problem doesn't exist when I use my older device which works through HttpClient. My main problem is this:

System.err: org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 62973: no element found
System.err:     at org.apache.harmony.xml.ExpatParser.finish(ExpatParser.java:545)
System.err:     at org.apache.harmony.xml.ExpatParser.parseDocument(ExpatParser.java:475)
System.err:     at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:316)
System.err:     at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:279)
System.err:     at com.czami.isakmobileapp.handling.XMLParser.parseSoap(XMLParser.java:153)
System.err:     at com.czami.isakmobileapp.netInteraction.PostList.postList(PostList.java:44)
System.err:     at com.czami.isakmobileapp.services.UpdateOneShot.onHandleIntent(UpdateOneShot.java:338)

Problem is, that those SOAP messages, if I write them in file, they came normally, no problem whatsoever. And also on the with Android version less than 6, it works fine on HttpClient, event if it's deprecated. Now I am facing pretty huge problem and I am not sure, what is wrong with that. Some SOAP message goes through without a problem, but it seems like bigger ones does not work. Can someone point in some direction, I have other things to do on this app and this is like a 2 days of trying and still no go. I probably look in every page which explains HttpsURLConnection, every page here and also pages with this problem which is below the code. I am pretty hopeless. Thanks for any answers.


Solution

  • You can still use the old Apache HTTP API on the new devices. You just have to add a dependency in your gradle file. Add this in the android {} block of your module build.gradle file:

    android {
        useLibrary 'org.apache.http.legacy'
    }
    

    Once you do that you should be good to go to use all your old HttpClient code.


    EDITS

    I'm wondering if perhaps you are losing data in the transfer because of performance issues with the size of the request or something similar. You may try to use some Buffered types of readers instead. Below is some code I use in one of my apps to complete SOAP request using HttpURLConnection. Maybe you can try some of the things I use to see if they will help, for instance the BufferedReader for the input stream.

    String result = null;
    String requestInput = formatXmlRequest(input[0]); //returns a SOAP request String
    URL url;
    HttpURLConnection connection = null;
    OutputStreamWriter out = null;
    
    try {
        url = new URL(WEB_SERVICE_URL);
        connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestProperty("Content-Type", "application/soap+xml");
        connection.setRequestProperty("Accept", "application/soap+xml");
    
        out = new OutputStreamWriter(connection.getOutputStream());
        out.write(requestInput);
        out.flush();
    
        StringBuilder stringBuilder = new StringBuilder();
        int responseCode = connection.getResponseCode();
    
        if(responseCode == HttpURLConnection.HTTP_OK) {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
            String line;
            while((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }
        } else {
            Log.d("BAD RESPONSE", "Response from server: "+responseCode);
        }
    
        result = stringBuilder.toString();
    
    } catch (IOException ioe) {
        ioe.printStackTrace();
    } finally {
        if(connection != null) connection.disconnect();
        if(out != null) {
            try {
                out.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }
    
    return result;