0

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.

Michal Žídek
  • 464
  • 2
  • 17

1 Answers1

1

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;
NoChinDeluxe
  • 3,446
  • 1
  • 16
  • 29
  • I use that, but for 6 is a no go, it works for 5 though. I have that in my gradle build file. – Michal Žídek May 24 '16 at 15:55
  • I use `HttpURLConnection` to make a SOAP request in one of my apps, and it works fine on all APIs. I've posted the code I used above. Maybe you can try some of the techniques I used. I'm wondering if you need to use a `BufferedReader` to get your input stream instead? There could be some performance issues leading to your data loss, and that could possibly help. – NoChinDeluxe May 24 '16 at 16:21
  • I try your solution and let you know how that goes and I definitely might be loosing data, hopefully HttpURLConnection and HttpsURLConnection is just the same same thing just one needs some extra work which really does not involve rest of the code. Thanks a lot! – Michal Žídek May 24 '16 at 16:31
  • Yes `HttpURLConnection` and `HttpsURLConnection` are essentially interchangeable. – NoChinDeluxe May 24 '16 at 16:49
  • I somewhat don't have this formatXmlRequest function, where can I find it? – Michal Žídek May 24 '16 at 17:14
  • That's just a custom function of mine that formats my SOAP request into a single string that I can pass to the server. You shouldn't need to call that since you already pass in a `StringBuffer` which I assume contains your SOAP request in String format already. So instead, you would just pass in your String by calling `soap.toString()`. – NoChinDeluxe May 24 '16 at 17:17
  • But you write to that function in a out.write(requestInput); Could you please update your post with this function please? I am pretty sure that I would pass in there the SOAP message, but it does not take String, StringBuffer, etc. And Android studio writes me "No documentation found". That's my last request and I won't you bother anymore if this is going to work. – Michal Žídek May 24 '16 at 17:31
  • That function doesn't do anything. It just puts a bunch of Strings together to build a SOAP request that I can then pass to the server. It would make no sense for you to use that because it builds a request for my server with my data. You should already have your SOAP request available to you in `StringBuffer soap`. So you should just have to call `out.write(soap.toString());` to send your own SOAP request to the server. – NoChinDeluxe May 24 '16 at 17:51
  • 1
    I made it work, thanks a lot, you are life saver, take care and again thanks a lot! – Michal Žídek May 24 '16 at 18:29