Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 342002

Summary: RestClientService.invokeRemoteCall throws exception on successful HTTP operation that returns HTTP status other than 200
Product: [RT] ECF Reporter: Dirk Olmes <dirk.olmes>
Component: ecf.remoteservicesAssignee: Scott Lewis <slewis>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: slewis
Version: unspecified   
Target Milestone: 3.5.1   
Hardware: PC   
OS: Linux   
Whiteboard:

Description Dirk Olmes CLA 2011-04-06 07:31:57 EDT
Build Identifier: org.eclipse.ecf.remoteservice.rest_2.1.0.v20110313-1843

I use ECF's remote service API to access a remote REST service. New resources are created using a POST request. Upon successful creation of the remote resource the service returns HTTP stauts code 201 (Created) which falls into the "Successful" category of HTTP status codes. 

The invokeRemoteCall method in RestClientService only checks for HTTP status 200 though (line 70) and throws an exception for any other status code. This logic should be extended a bit to allow all other 2xx status codes.

Reproducible: Always

Steps to Reproduce:
Sample code using a PUT method to a local couchdb:

String dbUrl = COUCH_DB_URL + "sample_database/";

IContainerFactory containerFactory = Activator.getDefault().getContainerFactory();
IContainer container = containerFactory.createContainer(REST_CONTAINER_TYPE, dbUrl);

IRemoteServiceClientContainerAdapter adapter  = (IRemoteServiceClientContainerAdapter) container.getAdapter(IRemoteServiceClientContainerAdapter.class);

IRemoteCallParameter[] parameters = RemoteCallParameterFactory.createParameters("body", null);
HttpPutRequestType requestType = new HttpPutRequestType(HttpPutRequestType.STRING_REQUEST_ENTITY, "text/plain");

String uuid = "/8f1f43ef03683be7b24b0de9db001632";
IRemoteCallable callable = RestCallableFactory.createCallable("createDocument", uuid, parameters, requestType);

String[] serviceInterfaceNames = new String[] { ICouchDB.class.getName() };
IRemoteCallable[][] remoteCallables = new IRemoteCallable[][] { { callable } };
IRemoteServiceRegistration registration = adapter.registerCallables(serviceInterfaceNames, remoteCallables, null);

IRemoteService remoteService = adapter.getRemoteService(registration.getReference());
Object[] callParameters = new Object[] { "{ \"name\" : \"Dirk Olmes\" }" };
IRestCall restCall = RestCallFactory.createRestCall(ICouchDB.class.getName() + ".createDocument", callParameters );
Object result = remoteService.callSync(restCall);
System.out.println(result);
Comment 1 Scott Lewis CLA 2011-04-06 13:36:19 EDT
I agree the logic in RestClientService needs to be generalized (to support at least 20* response values), but I would like to discuss with you how best to accomplish that.

Ideally, I would add a protected method in RestClientService...something like this:

protected boolean responseOk(int responseCode) {
    return (responseCode == HttpStatus.SC_OK || responseCode == HttpStatus.SC_CREATED || ...);
}

and then use this method in the RestClientService.invokeRemoteCall method.  This would fix this particular issue, and it would allow things to easily be customized.

However, ECF isn't planning a minor release for some time, and an addition like the above constitutes an API addition...and so would require a minor release.  So even if this addition is made, it won't be released for some time.

Another option is to simply embed the test against multiple response codes in the invokeRemoteCall method.  This would probably satisfy your needs for this bug, but would not be very general.  But it could be released as a bug fix only, and so could be released as part of ECF 3.5.1 (due near end of May...we're still discussing the date on ecf-dev mailing list).

Another possibility in the short term, BTW, is that you simply override invokeRemoteCall and implement it yourself in your own subclass of RestClientService.  

I think what I will do is to add the logic for testing against all response codes in invokeRemoteCall.  If you need an immediate fix (i.e. before ECF 3.5.1) then you can override invokeRemoteCall and implement the proper test in your implementation.
Comment 2 Scott Lewis CLA 2011-04-06 16:56:29 EDT
Fix as described in comment 1 released to master.  Resolving as fixed.  Dirk if you have comments about the comments and questions in comment 1 please continue to make them on this bug...or on ecf-dev.
Comment 3 Scott Lewis CLA 2011-04-06 16:56:49 EDT
actually resolving.
Comment 4 Dirk Olmes CLA 2011-04-07 00:04:43 EDT
Scott, thanks for fixing this issue so quickly. Pulling the latest update I see that you made the isResponseOk() method private. In the comment above you're talking about making this method protected which is much more friendly for subclassers. Was this just an oversight or did you do it on purpose?
Comment 5 Scott Lewis CLA 2011-04-07 09:50:07 EDT
(In reply to comment #4)
> Scott, thanks for fixing this issue so quickly. Pulling the latest update I see
> that you made the isResponseOk() method private. In the comment above you're
> talking about making this method protected which is much more friendly for
> subclassers. Was this just an oversight or did you do it on purpose?

I did it on purpose (made it private), because otherwise this constitutes an API change, and we would have to have release review, etc., etc. prior to release.