> +
> @Payload("<ws:getDataCenter><dataCenterId>{id}</dataCenterId></ws:getDataCenter>")
> + @XMLResponseParser(GetVDCResponseHandler.class)
> + @Fallback(NullOnNotFoundOr404.class)
> + VirtualDataCenter getDataCenter(@PayloadParam("id") String identifier);
> +
> + /**
> + * Creates and saves a new, empty Virtual Data Center. Returns its
> identifier for further reference.
> + *
> + * @param vdc VDC payload containing dataCenterName, region (both
> optional)
> + * @return Version response
> + */
> + @POST
> + @Named("CreateDataCenter")
> + @MapBinder(CreateDataCenterRequestBinder.class)
> + @XMLResponseParser(VersionResponseHandler.class)
> + @Fallback(NullOnNotFoundOr404.class)
So this seems to be YAATS (Yet Another Api That Sucks :D). This is something
that needs to be configured a bit different.
jclouds by default tries to retry failed requests using a customizable
strategy. It first [sends the
request](https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/http/internal/BaseHttpCommandExecutorService.java#L96)
and decides if it must be retried [based on the response
code](https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/http/internal/BaseHttpCommandExecutorService.java#L104-L111).
If the response is a 2xx, then the operation just returns and the
`ResponseParsers` (such as the `XMLResponseParser`) are invoked to transform
the request in the right Java entity returned by the API.
However, if after the configured retries, the response is still a failure, then
the configured `ErrorHandler` (the PB error handler in this case) [will be
invoked](https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/http/internal/BaseHttpCommandExecutorService.java#L135)
to populate the right exception. That exception is [thrown
later](https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/http/internal/BaseHttpCommandExecutorService.java#L125-L126)
and [captured and
transformed](https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/internal/InvokeHttpMethod.java#L94)
if the API method defines a `Fallback`, so the right result is returned.
With this bit of context in mind, the `XMLResponseParser` won't be invoked if
the response is a 500, as an exception will be propagated before. The problem
here is that you need to read the response body to actually know if the request
failed (YAATS!). The current code only checks the response status, so you'll
have to override a bit of code to populate the proper response code.
The DigitalOcean API v1 has the same problem, and you can copy how it fixes it.
It defines a [subclass of the
JavaUrlHttpCommandExecutorService](https://github.com/jclouds/jclouds-labs/blob/master/digitalocean/src/main/java/org/jclouds/digitalocean/http/ResponseStatusFromPayloadHttpCommandExecutorService.java)
that inspects the body of the response and populates the right response code.
The configuration is done
[here](https://github.com/jclouds/jclouds-labs/blob/master/digitalocean/src/main/java/org/jclouds/digitalocean/config/DigitalOceanHttpApiModule.java#L48-L56)
and
[here](https://github.com/jclouds/jclouds-labs/blob/master/digitalocean/src/main/java/org/jclouds/digitalocean/DigitalOceanApiMetadata.java#L70),
so it is properly bound to the Guice context. With that in place, the response
body is read and the response code set accordingly, so the default jclouds
mechanisms to retry or fail the requests (and the subsequent invocations of the
response parsers, only when the
request
really suceeds, or the fallbacks) work as expected.
It is not optimal, because when the response is a 2xx you'll read the body
twice (one to determine if there is an error, and a second one in the response
parser) and often that means that the response body must be buffered, if the
InputSteram for the body is not repeatable, but it is the less intrusive
solution you have with APIs like this.
---
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/72/files#r17465022