Properly handler ProfitBricks service errors

This commit is contained in:
Ignasi Barrera 2016-02-25 12:23:10 +01:00
parent 59a88ff898
commit 72f2652dca
7 changed files with 136 additions and 59 deletions

View File

@ -302,11 +302,16 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
public Provisionable getImage(String id) {
// try search images
logger.trace("<< searching for image with id=%s", id);
try {
Image image = api.imageApi().getImage(id);
if (image != null) {
logger.trace(">> found image [%s].", image.name());
return image;
}
} catch (Exception ex) {
logger.warn(ex, ">> unexpected error getting image. Trying to get as a snapshot...");
}
// try search snapshots
logger.trace("<< not found from images. searching for snapshot with id=%s", id);
Snapshot snapshot = api.snapshotApi().getSnapshot(id);

View File

@ -16,12 +16,33 @@
*/
package org.jclouds.profitbricks.domain;
import org.jclouds.javax.annotation.Nullable;
import com.google.auto.value.AutoValue;
import com.google.common.base.Enums;
@AutoValue
public abstract class ServiceFault {
public abstract String faultCode();
public abstract String faultString();
@Nullable public abstract Details details();
public static Builder builder() {
return new AutoValue_ServiceFault.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder faultCode(String faultCode);
public abstract Builder faultString(String faultString);
public abstract Builder details(Details details);
public abstract ServiceFault build();
}
@AutoValue
public abstract static class Details {
public enum FaultCode {
BAD_REQUEST,
@ -42,29 +63,21 @@ public abstract class ServiceFault {
}
public abstract FaultCode faultCode();
public abstract int httpCode();
public abstract String message();
public abstract int requestId();
public static Builder builder() {
return new AutoValue_ServiceFault.Builder();
return new AutoValue_ServiceFault_Details.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder faultCode(FaultCode faultCode);
public abstract Builder httpCode(int httpCode);
public abstract Builder message(String message);
public abstract Builder requestId(int requestId);
public abstract ServiceFault build();
public abstract Details build();
}
}
}

View File

@ -16,6 +16,7 @@
*/
package org.jclouds.profitbricks.handlers;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import static org.jclouds.util.Closeables2.closeQuietly;
import javax.inject.Singleton;
@ -39,7 +40,15 @@ public class ProfitBricksHttpErrorHandler implements HttpErrorHandler {
@Override
public void handleError(final HttpCommand command, final HttpResponse response) {
Exception exception = null;
// it is important to always read fully and close streams
byte[] data = closeClientButKeepContentStream(response);
String message = data != null ? new String(data) : null;
Exception exception = message != null ? new HttpResponseException(command, response, message)
: new HttpResponseException(command, response);
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
response.getStatusLine());
try {
switch (response.getStatusCode()) {
case 400:
@ -49,6 +58,9 @@ public class ProfitBricksHttpErrorHandler implements HttpErrorHandler {
case 401:
exception = new AuthorizationException("This request requires authentication.", exception);
break;
case 403:
exception = new AuthorizationException(response.getMessage(), exception);
break;
case 402:
case 409:
exception = new IllegalStateException(response.getMessage(), exception);

View File

@ -94,10 +94,13 @@ public class ResponseStatusFromPayloadHttpCommandExecutorService extends JavaUrl
try {
if (isSoapPayload(in)) {
ServiceFault fault = faultHandler.parse(in);
if (fault != null)
responseBuilder
.statusCode(fault.httpCode())
.message(fault.message());
if (fault != null) {
if (fault.details() != null) {
responseBuilder.statusCode(fault.details().httpCode()).message(fault.details().message());
} else {
responseBuilder.message(fault.faultString());
}
}
}
} catch (Exception ex) {
// ignore

View File

@ -17,27 +17,40 @@
package org.jclouds.profitbricks.http.parser;
import org.jclouds.profitbricks.domain.ServiceFault;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
public class ServiceFaultResponseHandler extends BaseProfitBricksResponseHandler<ServiceFault> {
private final ServiceFault.Builder builder;
private ServiceFault.Details.Builder detailsBuilder;
private boolean done = false;
ServiceFaultResponseHandler() {
this.builder = ServiceFault.builder();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("detail".equals(qName)) {
detailsBuilder = ServiceFault.Details.builder();
}
}
@Override
protected void setPropertyOnEndTag(String qName) {
if ("faultCode".equals(qName))
builder.faultCode(ServiceFault.FaultCode.fromValue(textToStringValue()));
if ("faultcode".equals(qName))
builder.faultCode(textToStringValue());
else if ("faultstring".equals(qName))
builder.faultString(textToStringValue());
else if ("faultCode".equals(qName))
detailsBuilder.faultCode(ServiceFault.Details.FaultCode.fromValue(textToStringValue()));
else if ("httpCode".equals(qName))
builder.httpCode(textToIntValue());
detailsBuilder.httpCode(textToIntValue());
else if ("message".equals(qName))
builder.message(textToStringValue());
detailsBuilder.message(textToStringValue());
else if ("requestId".equals(qName))
builder.requestId(textToIntValue());
detailsBuilder.requestId(textToIntValue());
}
@Override
@ -45,8 +58,10 @@ public class ServiceFaultResponseHandler extends BaseProfitBricksResponseHandler
if (done)
return;
setPropertyOnEndTag(qName);
if ("detail".equals(qName))
if ("S:Fault".equals(qName))
done = true;
if ("detail".equals(qName))
builder.details(detailsBuilder.build());
clearTextBuffer();
}

View File

@ -21,6 +21,7 @@ import static org.testng.Assert.assertNotNull;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.profitbricks.domain.ServiceFault;
import org.jclouds.profitbricks.domain.ServiceFault.Details;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "ServiceFaultResponseHandlerTest")
@ -37,11 +38,30 @@ public class ServiceFaultResponseHandlerTest extends BaseResponseHandlerTest<Ser
ServiceFault actual = parser.parse(payloadFromResource("/fault-404.xml"));
assertNotNull(actual, "Parsed content returned null");
ServiceFault expected = ServiceFault.builder()
.faultCode(ServiceFault.FaultCode.RESOURCE_NOT_FOUND)
ServiceFault expected = ServiceFault
.builder()
.faultCode("S:Server")
.faultString(
"The requested resource could not be found. Please refer to Request Id : 16370720. [VDC-6-404] The requested resource does not exist or already deleted by the users. ResourceId random-non-existing-id")
.details(
Details
.builder()
.faultCode(ServiceFault.Details.FaultCode.RESOURCE_NOT_FOUND)
.httpCode(404)
.message("The requested resource could not be found. Please refer to Request Id : 16370720. [VDC-6-404] The requested resource does not exist or already deleted by the users. ResourceId random-non-existing-id")
.requestId(16370720)
.message(
"The requested resource could not be found. Please refer to Request Id : 16370720. [VDC-6-404] The requested resource does not exist or already deleted by the users. ResourceId random-non-existing-id")
.requestId(16370720).build()).build();
assertEquals(expected, actual);
}
@Test
public void testParseSoapServiceFaultWithoutDetails() {
ParseSax<ServiceFault> parser = createParser();
ServiceFault actual = parser.parse(payloadFromResource("/fault-500.xml"));
assertNotNull(actual, "Parsed content returned null");
ServiceFault expected = ServiceFault.builder().faultCode("S:Server").faultString("javax.ejb.EJBException")
.build();
assertEquals(expected, actual);

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>javax.ejb.EJBException</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>