diff --git a/azure/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java b/azure/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java index cf0cbd58ce..6a165e8dcd 100644 --- a/azure/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java +++ b/azure/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java @@ -89,7 +89,6 @@ public class ParseAzureStorageErrorFromXmlContent implements HttpErrorHandler { exception = new AuthorizationException(command.getRequest(), message); break; case 404: - if (!command.getRequest().getMethod().equals("DELETE")) { String path = command.getRequest().getEndpoint().getPath(); Matcher matcher = CONTAINER_PATH.matcher(path); diff --git a/azure/src/test/java/org/jclouds/azure/storage/handlers/ParseAzureErrorFromXmlContentTest.java b/azure/src/test/java/org/jclouds/azure/storage/handlers/ParseAzureErrorFromXmlContentTest.java index 5f19192af7..8600120f44 100644 --- a/azure/src/test/java/org/jclouds/azure/storage/handlers/ParseAzureErrorFromXmlContentTest.java +++ b/azure/src/test/java/org/jclouds/azure/storage/handlers/ParseAzureErrorFromXmlContentTest.java @@ -28,6 +28,7 @@ import static org.easymock.classextension.EasyMock.verify; import java.net.URI; import org.easymock.IArgumentMatcher; +import org.jclouds.azure.storage.AzureStorageResponseException; import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication; import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpRequest; @@ -54,6 +55,14 @@ public class ParseAzureErrorFromXmlContentTest { "Length Required", "text/html; charset=us-ascii", "Length Required\r\n", IllegalArgumentException.class); } + + @Test + public void test412WithTextHtmlHttpResponseException() { + assertCodeMakes("GET", URI + .create("https://jclouds.blob.core.windows.net/adriancole-blobstore2?restype=container&comp=list&prefix=apps/apps/apps/&include=metadata"), 412, + "HTTP/1.1 412 The condition specified using HTTP conditional header(s) is not met.", "application/xml", "ConditionNotMetThe condition specified using HTTP conditional header(s) is not met.\nRequestId:921efcad-84bc-4e0a-863d-24810d1096e1\nTime:2010-11-04T15:03:07.8694513Z", + AzureStorageResponseException.class); + } private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType, String content, Class expected) { diff --git a/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java b/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java index fa5e52477e..9594a7ecff 100644 --- a/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java +++ b/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java @@ -35,6 +35,7 @@ import javax.inject.Inject; import javax.inject.Named; import org.jclouds.concurrent.Timeout; +import org.jclouds.http.HttpResponseException; import org.jclouds.internal.ClassMethodArgs; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ResourceNotFoundException; @@ -57,7 +58,7 @@ public class SyncProxy implements InvocationHandler { @SuppressWarnings("unchecked") public static T proxy(Class clazz, SyncProxy proxy) throws IllegalArgumentException, SecurityException, - NoSuchMethodException { + NoSuchMethodException { return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, proxy); } @@ -72,8 +73,8 @@ public class SyncProxy implements InvocationHandler { @Inject public SyncProxy(Class declaring, Object async, - @Named("sync") ConcurrentMap delegateMap, Map, Class> sync2Async) - throws SecurityException, NoSuchMethodException { + @Named("sync") ConcurrentMap delegateMap, Map, Class> sync2Async) + throws SecurityException, NoSuchMethodException { this.delegateMap = delegateMap; this.delegate = async; this.declaring = declaring; @@ -92,7 +93,7 @@ public class SyncProxy implements InvocationHandler { Method delegatedMethod = delegate.getClass().getMethod(method.getName(), method.getParameterTypes()); if (!Arrays.equals(delegatedMethod.getExceptionTypes(), method.getExceptionTypes())) throw new IllegalArgumentException(String.format( - "method %s has different typed exceptions than delegated method %s", method, delegatedMethod)); + "method %s has different typed exceptions than delegated method %s", method, delegatedMethod)); if (delegatedMethod.getReturnType().isAssignableFrom(ListenableFuture.class)) { if (method.isAnnotationPresent(Timeout.class)) { Timeout methodTimeout = method.getAnnotation(Timeout.class); @@ -124,7 +125,7 @@ public class SyncProxy implements InvocationHandler { } else if (method.isAnnotationPresent(Delegate.class)) { Class asyncClass = sync2Async.get(method.getReturnType()); checkState(asyncClass != null, "please configure corresponding async class for " + method.getReturnType() - + " in your RestClientModule"); + + " in your RestClientModule"); Object returnVal = delegateMap.get(new ClassMethodArgs(asyncClass, method, args)); return returnVal; } else if (syncMethodMap.containsKey(method)) { @@ -132,7 +133,7 @@ public class SyncProxy implements InvocationHandler { } else { try { return ((ListenableFuture) methodMap.get(method).invoke(delegate, args)).get(timeoutMap.get(method), - TimeUnit.NANOSECONDS); + TimeUnit.NANOSECONDS); } catch (ProvisionException e) { throw throwTypedExceptionOrCause(method.getExceptionTypes(), e); } catch (ExecutionException e) { @@ -143,6 +144,7 @@ public class SyncProxy implements InvocationHandler { } } + // Note this needs to be kept up-to-date with all top-level exceptions jclouds works against @SuppressWarnings("unchecked") public static Exception throwTypedExceptionOrCause(Class[] exceptionTypes, Exception exception) throws Exception { for (Class type : exceptionTypes) { @@ -154,6 +156,7 @@ public class SyncProxy implements InvocationHandler { Throwables.propagateIfInstanceOf(exception, IllegalStateException.class); Throwables.propagateIfInstanceOf(exception, AuthorizationException.class); Throwables.propagateIfInstanceOf(exception, ResourceNotFoundException.class); + Throwables.propagateIfInstanceOf(exception, HttpResponseException.class); Throwables.throwCause(exception, true); return exception; } diff --git a/core/src/main/java/org/jclouds/http/functions/ParseSax.java b/core/src/main/java/org/jclouds/http/functions/ParseSax.java index cb2045e2c1..d313e468ca 100644 --- a/core/src/main/java/org/jclouds/http/functions/ParseSax.java +++ b/core/src/main/java/org/jclouds/http/functions/ParseSax.java @@ -26,12 +26,10 @@ import static com.google.common.io.Closeables.closeQuietly; import java.io.InputStream; import java.io.StringReader; -import javax.annotation.Resource; import javax.inject.Inject; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; -import org.jclouds.logging.Logger; import org.jclouds.rest.InvocationContext; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.util.Utils; @@ -41,6 +39,7 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import com.google.common.base.Function; +import com.google.common.base.Throwables; /** * This object will parse the body of an HttpResponse and return the result of type back to the @@ -52,8 +51,6 @@ public class ParseSax implements Function, InvocationContext private final XMLReader parser; private final HandlerWithResult handler; - @Resource - protected Logger logger = Logger.NULL; private HttpRequest request; public static interface Factory { @@ -71,7 +68,7 @@ public class ParseSax implements Function, InvocationContext checkNotNull(from, "http response"); checkNotNull(from.getPayload(), "payload in " + from); } catch (NullPointerException e) { - return addRequestDetailsToException(e); + return addDetailsAndPropagate(from, e); } if (from.getStatusCode() >= 300) return convertStreamToStringAndParse(from); @@ -82,7 +79,7 @@ public class ParseSax implements Function, InvocationContext try { return parse(Utils.toStringAndClose(from.getPayload().getInput())); } catch (Exception e) { - return addRequestDetailsToException(e); + return addDetailsAndPropagate(from, e); } } @@ -91,7 +88,7 @@ public class ParseSax implements Function, InvocationContext checkNotNull(from, "xml string"); checkArgument(from.indexOf('<') >= 0, String.format("not an xml document [%s] ", from)); } catch (RuntimeException e) { - return addRequestDetailsToException(e); + return addDetailsAndPropagate(null, e); } return parse(new InputSource(new StringReader(from))); } @@ -113,31 +110,39 @@ public class ParseSax implements Function, InvocationContext parser.parse(from); return getHandler().getResult(); } catch (Exception e) { - return addRequestDetailsToException(e); + return addDetailsAndPropagate(null, e); } } - private T addRequestDetailsToException(Exception e) { - String exceptionMessage = e.getMessage(); + public T addDetailsAndPropagate(HttpResponse response, Exception e) { + StringBuilder message = new StringBuilder(); + if (request != null) { + message.append("request: ").append(request.getRequestLine()); + } + if (response != null) { + if (message.length() != 0) + message.append("; "); + message.append("response: ").append(response.getStatusLine()); + } if (e instanceof SAXParseException) { SAXParseException parseException = (SAXParseException) e; String systemId = parseException.getSystemId(); if (systemId == null) { systemId = ""; } - exceptionMessage = String.format("Error on line %d of document %s: %s", systemId, parseException - .getLineNumber(), parseException.getMessage()); + if (message.length() != 0) + message.append("; "); + message.append(String.format("error at %d:%d in document %s", parseException.getColumnNumber(), + parseException.getLineNumber(), systemId)); } - if (request != null) { - StringBuilder message = new StringBuilder(); - message.append("Error parsing input for ").append(request.getRequestLine()).append(": "); - message.append(exceptionMessage); - logger.error(e, message.toString()); + if (message.length() != 0) { + message.append("; cause: ").append(e.toString()); throw new RuntimeException(message.toString(), e); } else { - logger.error(e, exceptionMessage.toString()); - throw new RuntimeException(exceptionMessage.toString(), e); + Throwables.propagate(e); + return null; } + } public HandlerWithResult getHandler() {