cancel
Showing results for 
Search instead for 
Did you mean: 

ProxyException and RestClientException when using SAP NW Gateway proxy for Java from Android application

Former Member
0 Kudos

I am creating an Android app (for Android 4.0 - API level 15) to consume data from a SAP NetWeaver Gateway 2.0 through an odata channel.

I used the Eclipse plugin for Java (http://www.sdn.sap.com/irj/scn/downloads?rid=/webcontent/uuid/b09d414f-f227-2f10-bdbf-ba31c844b432) to generate proxy classes for the entities in the gateway service.

When I try to use the proxy class to GET an a collection from the gateway, the call fails in the "getResponseString(String url)" method of the proxy class. More specifically, the line

IRestResponse response = client.execute(request);

throws a RestClientException which, in turn, triggers a ProxyException.

The RestClientException prints the request URL is called. Using the RESTClient plugin in Mozilla Firefox, the exact same URL returns the wanted collection XML data.

In addition, the triggered ProxyException prints the message:

     System expected the element '{&EXPECTED_NAMESPACE&}&EXPECTED_NAME&'

I have tried using the DefaultHttpClient class to manually issue a GET request to the same gateway requesting the same data. Since this method works, I assume that the gateway connection from within the Android emulator works fine. As this method would require a lot of manual work that has to be done for each Android application individually, I would prefer not having to resort to it.

I have been stuck with this problem for a while now and couldn't find a solution so far, so I would very much appreciate any input that might take me closer to a solution to this.

Thanks!

Sebastian

P.S.: Using Wireshark, I found out that the application sends a POST request, although I am specifically setting GET as the method for the request (request.setMethod(Method.GET)). Could a POST request with an empty payload cause an error message like this? And how do I get the request to actually use GET?

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

I finally found the problem. I tested the same code within a plain Java command line programm and it worked with no errors. In this case, the application actally sends out a GET request (proof by Wireshark) and the call works like a charm.

Knowing this, I started looking around for a specific Android problem involving GET and POST and pretty soon found this: http://webdiary.com/2011/12/14/ics-get-post/

So, apparently they changed something in the java.net.HttpURLConnection implementation in Android 4.0 which results in every GET request being sent out as a POST request. Using the SAP Gateway library for Java, I don't have control over the instance of the HttpURLConnection instance, so I cannot use the fix recommended in the article above.

It seems that my only option, right now, is to wait until an Android-compatible version of the SAP Gateway library comes out which takes this issue into account. Until then, I will use the Android API level 12 which doesn't come with this problem.

If you have a nicer solution, please let me know!

Former Member
0 Kudos

Former Member is this something your team can fix in future release of the proxy generation tools?

Regards

Dagfinn

Former Member
0 Kudos

Thank you, Dagfinn, for guiding attention to this issue!

As it seems, a brand-new version of the Eclipse plugin (2.5.200) has just been released. When I checked last week, it was still at 2.4.x. In the next days, I will check to see whether this update already fixes the issue.

Former Member
0 Kudos

I am happy to say that we have released a new Android Toolkit as part of the SAP NetWeaver Gateway plug-in for Eclipse 2.5.200, you can find it here!

However, the new toolkit uses SAP OData Mobile SDK 2.1.3 which currently supports Android 2.2 - 3.2 (API level 8 - 13).

might be able to suggest a better solution of how you can still manipulate the HttpURLConnection instance.

Answers (2)

Answers (2)

Former Member
0 Kudos

Just a last quick update on this topic...

I just changed the finished application to use the current Eclipse plugin version (2.5.200) which officially supports Android. Although it doesn't officially support Android 4.0, it runs without any modifications like the ones described above. It probably uses another HttpClient class for sending the requests.

boris_tsirulnik
Participant
0 Kudos

Hi,

I can suggest as a workaround to implement a new class which will extend the class

com.sap.nw.gateway.odata.client.connectivity.impl.DefaultRestClient

In this class you should replace the send method with your implementation.

If needed I can provide the DefaultRestClient code for this method so you will have a base code which you can modify.

Regards,

Boris

Former Member
0 Kudos

Hello Boris,

that would actually be really great and would help me out a lot!

Thanks to everyone for your attention to this matter.

Best regards,

Sebastian

boris_tsirulnik
Participant
0 Kudos

public IRestResponse send(IRestRequest restRequest) throws RestClientException

{


String urlString = getUrl(restRequest.getUrl());



HttpURLConnection httpURLConnection = null;


OutputStreamWriter outputStreamWriter = null;


OutputStream outputStream = null;


InputStream inputStream = null;



try


{




httpURLConnection = (HttpURLConnection) new URL(urlString).openConnection();




if (this.serverConnectionParameters.useHttps())



{




if (this.sslSocketFactory != null)




{





if (httpURLConnection instanceof HttpsURLConnection)





{






((HttpsURLConnection) httpURLConnection).setSSLSocketFactory(this.sslSocketFactory);





}




}



}




httpURLConnection.setRequestMethod(restRequest.getMethod().toString());




httpURLConnection.setDoOutput(true);




httpURLConnection.setDoInput(true);




if (!cookies.isEmpty())



{




StringBuilder cookies = new StringBuilder();




for (Map.Entry<String, String> entry : this.cookies.entrySet())




{





cookies.append(entry.getKey()).append("=").append(entry.getValue()).append(";");




}




cookies.deleteCharAt(cookies.lastIndexOf(";"));




httpURLConnection.setRequestProperty(ConnectivityConstants.COOKIE, cookies.toString());




}




// add additional headers to request



addHeadersToRequest(httpURLConnection, restRequest.getHeaders());




if (restRequest.getBody() != null)



{




httpURLConnection.setRequestProperty(ConnectivityConstants.CONTENT_LENGTH,






Integer.toString(restRequest.getBody().length()));



}




if (restRequest.getBody() != null)



{




outputStream = httpURLConnection.getOutputStream();




outputStreamWriter = new OutputStreamWriter(outputStream, UTF_8);




outputStreamWriter.write(restRequest.getBody());




outputStreamWriter.close(); // $JL-RESOURCE$



}




IRestResponse restResponse;




try



{




inputStream = httpURLConnection.getInputStream();




restResponse = new RestResponse();




}



catch (IOException e)



{




inputStream = httpURLConnection.getErrorStream();




restResponse = new RestClientException(e.getMessage());



}




restResponse.setStatusCode(httpURLConnection.getResponseCode());




restResponse.setBody(Util.convertStreamToByteArray(inputStream)); // restResponse.setBody(Util.convertStreamToString(inputStream));




Headers headers = new Headers();




for (int i = 0;; i++)



{




String headerName = httpURLConnection.getHeaderFieldKey(i);




String headerValue = httpURLConnection.getHeaderField(i);





headers.put(headerName, headerValue);





if (headerName == null && headerValue == null)




{





// No more headers





break;




}



}




restResponse.setHeaders(headers);




httpURLConnection.disconnect();




return restResponse;


}


catch (MalformedURLException e)


{



LOGGER.severe(e.getMessage());



throw new RestClientException(e.getMessage(), e);


}


catch (ProtocolException e)


{



LOGGER.severe(e.getMessage());



throw new RestClientException(e.getMessage(), e);


}


catch (IOException e)


{



LOGGER.severe(e.getMessage());



throw new RestClientException(e.getMessage(), e);


}


finally


{



if (outputStreamWriter != null)



{




try




{





outputStreamWriter.close();




}




catch (IOException e)




{





LOGGER.severe(e.getMessage());





throw new RestClientException(e.getMessage(), e);




}



}


}

}
Former Member
0 Kudos

Thank you very much for the code! I just wanted to try it out, but I am stuck with the calls to the methods "getUrl(String)" and "addHeadersToRequest(HttpURLConnection, Headers)".

I guess, I could replace "String urlString = getUrl(restRequest.getUrl());" with "String urlString = restRequest.getUrl();" assuming that nothing else happens in the getUrl()-Method of DefaultRestClient...

But what about the second method? Could you please post the code for both methods, too? Or alternatively tell me what extra work needs to be done there?

Thanks again for your great support!

boris_tsirulnik
Participant
0 Kudos

Here it is:


private String getUrl(String urlString) throws RestClientException

{


urlString = urlString.toLowerCase(Locale.ENGLISH).startsWith("http") ? urlString : baseUrl + urlString;


if (this.serverConnectionParameters.getClient() != null




&& !(this.serverConnectionParameters.getClient().trim().length() == 0))


{



urlString = Util.addParameter(urlString, "sap-client", this.serverConnectionParameters.getClient());//$NON-NLS-1$ //$NON-NLS-2$


}


urlString = urlString.replace(" ", "%20");


return urlString;

}

private void addHeadersToRequest(HttpURLConnection httpURLConnection, Headers headers)

{


if (headers.isEmpty())



return;



for (Entry<String, List<String>> entry : headers.entrySet())


{



for (String value : entry.getValue())



{




httpURLConnection.addRequestProperty(entry.getKey(), value);



}


}

}
Former Member
0 Kudos

Thank you again, Boris!

I only had to make a minor modification to the "getUrl()" method because the field "baseUrl" isn't visibile to subclasses of DefaultRestClient. I put together the string by using the values of the field IServerConnectionParameters serverConnectionParameters.

The crucial modification for making the client send a GET request in Android 4.0 has to be made in the send() method, where the line

httpURLConnection.setDoOutput(true);

has to be replaced with

httpURLConnection.setDoOutput(false);

in case of a GET request.

Thank you so much for your help, this enables my application to run on Android 4.0 devices. In addition, the modifcations do not seem to have a negative effect on the application when running on a 3.1 device.

0 Kudos

Hi Boris,

    I am also trying to access ABAP oData from java and i have problem in authentication issue .Is there any basic code to connect .