brooklyn-rest-client: add org.apache package prefix

Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/c5256b18
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/c5256b18
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/c5256b18

Branch: refs/heads/master
Commit: c5256b186e13e67b356e3f68825858095add30ee
Parents: ffbd6ef
Author: Ciprian Ciubotariu <[email protected]>
Authored: Thu Jul 16 11:27:15 2015 +0300
Committer: Ciprian Ciubotariu <[email protected]>
Committed: Tue Aug 4 17:19:12 2015 +0300

----------------------------------------------------------------------
 .../java/brooklyn/rest/client/BrooklynApi.java  | 262 -------------------
 .../util/http/BuiltResponsePreservingError.java |  78 ------
 .../brooklyn/rest/client/BrooklynApi.java       | 262 +++++++++++++++++++
 .../util/http/BuiltResponsePreservingError.java |  78 ++++++
 .../ApplicationResourceIntegrationTest.java     | 190 --------------
 .../rest/client/BrooklynApiRestClientTest.java  | 134 ----------
 .../ApplicationResourceIntegrationTest.java     | 190 ++++++++++++++
 .../rest/client/BrooklynApiRestClientTest.java  | 134 ++++++++++
 8 files changed, 664 insertions(+), 664 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/main/java/brooklyn/rest/client/BrooklynApi.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/main/java/brooklyn/rest/client/BrooklynApi.java 
b/usage/rest-client/src/main/java/brooklyn/rest/client/BrooklynApi.java
deleted file mode 100644
index f57b4bd..0000000
--- a/usage/rest-client/src/main/java/brooklyn/rest/client/BrooklynApi.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.rest.client;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.annotation.Nullable;
-import javax.ws.rs.core.Response;
-
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.Credentials;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.jboss.resteasy.client.ClientExecutor;
-import org.jboss.resteasy.client.ClientRequest;
-import org.jboss.resteasy.client.ClientResponse;
-import org.jboss.resteasy.client.ProxyFactory;
-import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
-import org.jboss.resteasy.specimpl.BuiltResponse;
-import org.jboss.resteasy.util.GenericType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.gson.Gson;
-
-import brooklyn.rest.api.AccessApi;
-import brooklyn.rest.api.ActivityApi;
-import brooklyn.rest.api.ApplicationApi;
-import brooklyn.rest.api.CatalogApi;
-import brooklyn.rest.api.EffectorApi;
-import brooklyn.rest.api.EntityApi;
-import brooklyn.rest.api.EntityConfigApi;
-import brooklyn.rest.api.LocationApi;
-import brooklyn.rest.api.PolicyApi;
-import brooklyn.rest.api.PolicyConfigApi;
-import brooklyn.rest.api.ScriptApi;
-import brooklyn.rest.api.SensorApi;
-import brooklyn.rest.api.ServerApi;
-import brooklyn.rest.api.UsageApi;
-import brooklyn.rest.api.VersionApi;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.http.BuiltResponsePreservingError;
-
-import com.wordnik.swagger.core.ApiOperation;
-
-/**
- * @author Adam Lowe
- */
-@SuppressWarnings("deprecation")
-public class BrooklynApi {
-
-    private final String target;
-    private final ClientExecutor clientExecutor;
-    private static final Logger LOG = 
LoggerFactory.getLogger(BrooklynApi.class);
-
-    public BrooklynApi(URL endpoint) {
-        this(checkNotNull(endpoint, "endpoint").toString());
-    }
-
-    public BrooklynApi(String endpoint) {
-        // username/password cannot be null, but credentials can
-        this(endpoint, null);
-    }
-
-    public BrooklynApi(URL endpoint, String username, String password) {
-        this(endpoint.toString(), new UsernamePasswordCredentials(username, 
password));
-    }
-
-    public BrooklynApi(String endpoint, String username, String password) {
-        this(endpoint, new UsernamePasswordCredentials(username, password));
-    }
-
-    public BrooklynApi(URL endpoint, @Nullable Credentials credentials) {
-        this(endpoint.toString(), credentials);
-    }
-
-    public BrooklynApi(String endpoint, @Nullable Credentials credentials) {
-        try {
-            new URL(checkNotNull(endpoint, "endpoint"));
-        } catch (MalformedURLException e) {
-            throw new IllegalArgumentException(e);
-        }
-
-        this.target = endpoint;
-        if (credentials != null) {
-            DefaultHttpClient httpClient = new DefaultHttpClient();
-            httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, 
credentials);
-            this.clientExecutor = new ApacheHttpClient4Executor(httpClient);
-        } else {
-            this.clientExecutor = ClientRequest.getDefaultExecutor();
-        }
-    }
-
-    public BrooklynApi(URL endpoint, ClientExecutor clientExecutor) {
-        this.target = checkNotNull(endpoint, "endpoint").toString();
-        this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor");
-    }
-
-    @SuppressWarnings("unchecked")
-    private <T> T proxy(Class<T> clazz) {
-        final T result0 = ProxyFactory.create(clazz, target, clientExecutor);
-        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new 
Class<?>[] { clazz }, new InvocationHandler() {
-            @Override
-            public Object invoke(Object proxy, Method method, Object[] args) 
throws Throwable {                 
-                try {
-                    Object result1 = method.invoke(result0, args);
-                    Class<?> type = String.class;
-                    if (result1 instanceof Response) {
-                        Response resp = (Response)result1;
-                        if(isStatusCodeHealthy(resp.getStatus()) && 
method.isAnnotationPresent(ApiOperation.class)) {
-                           type = 
getClassFromMethodAnnotationOrDefault(method, type);
-                        }
-                        // wrap the original response so it self-closes
-                        result1 = 
BuiltResponsePreservingError.copyResponseAndClose(resp, type);
-                    }
-                    return result1;
-                } catch (Throwable e) {
-                    if (e instanceof InvocationTargetException) {
-                        // throw the original exception
-                        e = 
((InvocationTargetException)e).getTargetException();
-                    }
-                    throw Exceptions.propagate(e);
-                }  
-            }
-            
-            private boolean isStatusCodeHealthy(int code) { return (code>=200 
&& code<=299); }
-            
-            private Class<?> getClassFromMethodAnnotationOrDefault(Method 
method, Class<?> def){
-                Class<?> type;
-                try{
-                    String responseClass = 
method.getAnnotation(ApiOperation.class).responseClass();
-                    type = Class.forName(responseClass);
-                } catch (Exception e) {
-                    type = def;
-                    LOG.debug("Unable to get class from annotation: {}.  
Defaulting to {}", e.getMessage(), def.getName());
-                    Exceptions.propagateIfFatal(e);
-                }
-                return type;
-            }
-        });
-    }
-
-    public ActivityApi getActivityApi() {
-        return proxy(ActivityApi.class);
-    }
-
-    public ApplicationApi getApplicationApi() {
-        return proxy(ApplicationApi.class);
-    }
-
-    public CatalogApi getCatalogApi() {
-        return proxy(CatalogApi.class);
-    }
-
-    public EffectorApi getEffectorApi() {
-        return proxy(EffectorApi.class);
-    }
-
-    public EntityConfigApi getEntityConfigApi() {
-        return proxy(EntityConfigApi.class);
-    }
-
-    public EntityApi getEntityApi() {
-        return proxy(EntityApi.class);
-    }
-
-    public LocationApi getLocationApi() {
-        return proxy(LocationApi.class);
-    }
-
-    public PolicyConfigApi getPolicyConfigApi() {
-        return proxy(PolicyConfigApi.class);
-    }
-
-    public PolicyApi getPolicyApi() {
-        return proxy(PolicyApi.class);
-    }
-
-    public ScriptApi getScriptApi() {
-        return proxy(ScriptApi.class);
-    }
-
-    public SensorApi getSensorApi() {
-        return proxy(SensorApi.class);
-    }
-
-    public ServerApi getServerApi() {
-        return proxy(ServerApi.class);
-    }
-
-    public UsageApi getUsageApi() {
-        return proxy(UsageApi.class);
-    }
-
-    public VersionApi getVersionApi() {
-        return proxy(VersionApi.class);
-    }
-
-    public AccessApi getAccessApi() {
-        return proxy(AccessApi.class);
-    }
-
-    public static <T> T getEntity(Response response, Class<T> type) {
-        if (response instanceof ClientResponse) {
-            ClientResponse<?> clientResponse = (ClientResponse<?>) response;
-            return clientResponse.getEntity(type);
-        } else if (response instanceof BuiltResponse) {
-            // Handle BuiltResponsePreservingError turning objects into Strings
-            if (response.getEntity() instanceof String && 
!type.equals(String.class)) {
-                return new Gson().fromJson(response.getEntity().toString(), 
type);
-            }
-        }
-        // Last-gasp attempt.
-        return type.cast(response.getEntity());
-    }
-
-    public static <T> T getEntity(Response response, GenericType<T> type) {
-        if (response instanceof ClientResponse) {
-            ClientResponse<?> clientResponse = (ClientResponse<?>) response;
-            return clientResponse.getEntity(type);
-        } else if (response instanceof BuiltResponse) {
-            // Handle BuiltResponsePreservingError turning objects into Strings
-            if (response.getEntity() instanceof String) {
-                return new Gson().fromJson(response.getEntity().toString(), 
type.getGenericType());
-            }
-        }
-        // Last-gasp attempt.
-        return type.getType().cast(response.getEntity());
-    }
-
-    /**
-     * @deprecated Use {@link #getEntity(Response, GenericType)} instead.
-     */
-    @Deprecated
-    public static <T> T getEntityGeneric(Response response, GenericType<T> 
type) {
-        return getEntity(response, type);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/main/java/brooklyn/util/http/BuiltResponsePreservingError.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/main/java/brooklyn/util/http/BuiltResponsePreservingError.java
 
b/usage/rest-client/src/main/java/brooklyn/util/http/BuiltResponsePreservingError.java
deleted file mode 100644
index 3bd88e6..0000000
--- 
a/usage/rest-client/src/main/java/brooklyn/util/http/BuiltResponsePreservingError.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.util.http;
-
-import java.lang.annotation.Annotation;
-
-import javax.ws.rs.core.Response;
-
-import org.jboss.resteasy.client.core.BaseClientResponse;
-import org.jboss.resteasy.core.Headers;
-import org.jboss.resteasy.specimpl.BuiltResponse;
-
-import brooklyn.util.exceptions.Exceptions;
-
-/** 
- * Allows wrapping a {@link Response} with the stream fully read and closed so 
that the client can be re-used.
- * <p>
- * The entity may be stored as a string as type info is not available when it 
is deserialized, 
- * and that's a relatively convenient common format.
- *  
- * TODO It would be nice to support other parsing, storing the byte array.
- */
-public class BuiltResponsePreservingError extends BuiltResponse {
-
-    private Throwable error;
-
-    public BuiltResponsePreservingError(int status, Headers<Object> headers, 
Object entity, Annotation[] annotations, Throwable error) {
-        super(status, headers, entity, annotations);
-        this.error = error;
-    }
-    
-    @SuppressWarnings("deprecation")
-    public static <T> Response copyResponseAndClose(Response source, Class<T> 
type) {
-        int status = -1;
-        Headers<Object> headers = new Headers<Object>();
-        Object entity = null;
-        try {
-            status = source.getStatus();
-            if (source instanceof BaseClientResponse)
-                headers.putAll(((BaseClientResponse<?>)source).getMetadata());
-            if (source instanceof org.jboss.resteasy.client.ClientResponse) {
-                entity = 
((org.jboss.resteasy.client.ClientResponse<?>)source).getEntity(type);
-            } else {
-                entity = source.getEntity();
-            }
-            return new BuiltResponsePreservingError(status, headers, entity, 
new Annotation[0], null);
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            return new BuiltResponsePreservingError(status, headers, entity, 
new Annotation[0], e);
-        } finally {
-            if (source instanceof BaseClientResponse)
-                ((BaseClientResponse<?>)source).close();
-        }
-    }
-    
-    @Override
-    public Object getEntity() {
-        if (error!=null) Exceptions.propagate(error);
-        return super.getEntity();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java
 
b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java
new file mode 100644
index 0000000..f4b47e6
--- /dev/null
+++ 
b/usage/rest-client/src/main/java/org/apache/brooklyn/rest/client/BrooklynApi.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.client;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.annotation.Nullable;
+import javax.ws.rs.core.Response;
+
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.jboss.resteasy.client.ClientExecutor;
+import org.jboss.resteasy.client.ClientRequest;
+import org.jboss.resteasy.client.ClientResponse;
+import org.jboss.resteasy.client.ProxyFactory;
+import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
+import org.jboss.resteasy.specimpl.BuiltResponse;
+import org.jboss.resteasy.util.GenericType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+
+import brooklyn.rest.api.AccessApi;
+import brooklyn.rest.api.ActivityApi;
+import brooklyn.rest.api.ApplicationApi;
+import brooklyn.rest.api.CatalogApi;
+import brooklyn.rest.api.EffectorApi;
+import brooklyn.rest.api.EntityApi;
+import brooklyn.rest.api.EntityConfigApi;
+import brooklyn.rest.api.LocationApi;
+import brooklyn.rest.api.PolicyApi;
+import brooklyn.rest.api.PolicyConfigApi;
+import brooklyn.rest.api.ScriptApi;
+import brooklyn.rest.api.SensorApi;
+import brooklyn.rest.api.ServerApi;
+import brooklyn.rest.api.UsageApi;
+import brooklyn.rest.api.VersionApi;
+import brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.http.BuiltResponsePreservingError;
+
+import com.wordnik.swagger.core.ApiOperation;
+
+/**
+ * @author Adam Lowe
+ */
+@SuppressWarnings("deprecation")
+public class BrooklynApi {
+
+    private final String target;
+    private final ClientExecutor clientExecutor;
+    private static final Logger LOG = 
LoggerFactory.getLogger(BrooklynApi.class);
+
+    public BrooklynApi(URL endpoint) {
+        this(checkNotNull(endpoint, "endpoint").toString());
+    }
+
+    public BrooklynApi(String endpoint) {
+        // username/password cannot be null, but credentials can
+        this(endpoint, null);
+    }
+
+    public BrooklynApi(URL endpoint, String username, String password) {
+        this(endpoint.toString(), new UsernamePasswordCredentials(username, 
password));
+    }
+
+    public BrooklynApi(String endpoint, String username, String password) {
+        this(endpoint, new UsernamePasswordCredentials(username, password));
+    }
+
+    public BrooklynApi(URL endpoint, @Nullable Credentials credentials) {
+        this(endpoint.toString(), credentials);
+    }
+
+    public BrooklynApi(String endpoint, @Nullable Credentials credentials) {
+        try {
+            new URL(checkNotNull(endpoint, "endpoint"));
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException(e);
+        }
+
+        this.target = endpoint;
+        if (credentials != null) {
+            DefaultHttpClient httpClient = new DefaultHttpClient();
+            httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, 
credentials);
+            this.clientExecutor = new ApacheHttpClient4Executor(httpClient);
+        } else {
+            this.clientExecutor = ClientRequest.getDefaultExecutor();
+        }
+    }
+
+    public BrooklynApi(URL endpoint, ClientExecutor clientExecutor) {
+        this.target = checkNotNull(endpoint, "endpoint").toString();
+        this.clientExecutor = checkNotNull(clientExecutor, "clientExecutor");
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T proxy(Class<T> clazz) {
+        final T result0 = ProxyFactory.create(clazz, target, clientExecutor);
+        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new 
Class<?>[] { clazz }, new InvocationHandler() {
+            @Override
+            public Object invoke(Object proxy, Method method, Object[] args) 
throws Throwable {                 
+                try {
+                    Object result1 = method.invoke(result0, args);
+                    Class<?> type = String.class;
+                    if (result1 instanceof Response) {
+                        Response resp = (Response)result1;
+                        if(isStatusCodeHealthy(resp.getStatus()) && 
method.isAnnotationPresent(ApiOperation.class)) {
+                           type = 
getClassFromMethodAnnotationOrDefault(method, type);
+                        }
+                        // wrap the original response so it self-closes
+                        result1 = 
BuiltResponsePreservingError.copyResponseAndClose(resp, type);
+                    }
+                    return result1;
+                } catch (Throwable e) {
+                    if (e instanceof InvocationTargetException) {
+                        // throw the original exception
+                        e = 
((InvocationTargetException)e).getTargetException();
+                    }
+                    throw Exceptions.propagate(e);
+                }  
+            }
+            
+            private boolean isStatusCodeHealthy(int code) { return (code>=200 
&& code<=299); }
+            
+            private Class<?> getClassFromMethodAnnotationOrDefault(Method 
method, Class<?> def){
+                Class<?> type;
+                try{
+                    String responseClass = 
method.getAnnotation(ApiOperation.class).responseClass();
+                    type = Class.forName(responseClass);
+                } catch (Exception e) {
+                    type = def;
+                    LOG.debug("Unable to get class from annotation: {}.  
Defaulting to {}", e.getMessage(), def.getName());
+                    Exceptions.propagateIfFatal(e);
+                }
+                return type;
+            }
+        });
+    }
+
+    public ActivityApi getActivityApi() {
+        return proxy(ActivityApi.class);
+    }
+
+    public ApplicationApi getApplicationApi() {
+        return proxy(ApplicationApi.class);
+    }
+
+    public CatalogApi getCatalogApi() {
+        return proxy(CatalogApi.class);
+    }
+
+    public EffectorApi getEffectorApi() {
+        return proxy(EffectorApi.class);
+    }
+
+    public EntityConfigApi getEntityConfigApi() {
+        return proxy(EntityConfigApi.class);
+    }
+
+    public EntityApi getEntityApi() {
+        return proxy(EntityApi.class);
+    }
+
+    public LocationApi getLocationApi() {
+        return proxy(LocationApi.class);
+    }
+
+    public PolicyConfigApi getPolicyConfigApi() {
+        return proxy(PolicyConfigApi.class);
+    }
+
+    public PolicyApi getPolicyApi() {
+        return proxy(PolicyApi.class);
+    }
+
+    public ScriptApi getScriptApi() {
+        return proxy(ScriptApi.class);
+    }
+
+    public SensorApi getSensorApi() {
+        return proxy(SensorApi.class);
+    }
+
+    public ServerApi getServerApi() {
+        return proxy(ServerApi.class);
+    }
+
+    public UsageApi getUsageApi() {
+        return proxy(UsageApi.class);
+    }
+
+    public VersionApi getVersionApi() {
+        return proxy(VersionApi.class);
+    }
+
+    public AccessApi getAccessApi() {
+        return proxy(AccessApi.class);
+    }
+
+    public static <T> T getEntity(Response response, Class<T> type) {
+        if (response instanceof ClientResponse) {
+            ClientResponse<?> clientResponse = (ClientResponse<?>) response;
+            return clientResponse.getEntity(type);
+        } else if (response instanceof BuiltResponse) {
+            // Handle BuiltResponsePreservingError turning objects into Strings
+            if (response.getEntity() instanceof String && 
!type.equals(String.class)) {
+                return new Gson().fromJson(response.getEntity().toString(), 
type);
+            }
+        }
+        // Last-gasp attempt.
+        return type.cast(response.getEntity());
+    }
+
+    public static <T> T getEntity(Response response, GenericType<T> type) {
+        if (response instanceof ClientResponse) {
+            ClientResponse<?> clientResponse = (ClientResponse<?>) response;
+            return clientResponse.getEntity(type);
+        } else if (response instanceof BuiltResponse) {
+            // Handle BuiltResponsePreservingError turning objects into Strings
+            if (response.getEntity() instanceof String) {
+                return new Gson().fromJson(response.getEntity().toString(), 
type.getGenericType());
+            }
+        }
+        // Last-gasp attempt.
+        return type.getType().cast(response.getEntity());
+    }
+
+    /**
+     * @deprecated Use {@link #getEntity(Response, GenericType)} instead.
+     */
+    @Deprecated
+    public static <T> T getEntityGeneric(Response response, GenericType<T> 
type) {
+        return getEntity(response, type);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/main/java/org/apache/brooklyn/util/http/BuiltResponsePreservingError.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/main/java/org/apache/brooklyn/util/http/BuiltResponsePreservingError.java
 
b/usage/rest-client/src/main/java/org/apache/brooklyn/util/http/BuiltResponsePreservingError.java
new file mode 100644
index 0000000..32a5dfb
--- /dev/null
+++ 
b/usage/rest-client/src/main/java/org/apache/brooklyn/util/http/BuiltResponsePreservingError.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.http;
+
+import java.lang.annotation.Annotation;
+
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.client.core.BaseClientResponse;
+import org.jboss.resteasy.core.Headers;
+import org.jboss.resteasy.specimpl.BuiltResponse;
+
+import brooklyn.util.exceptions.Exceptions;
+
+/** 
+ * Allows wrapping a {@link Response} with the stream fully read and closed so 
that the client can be re-used.
+ * <p>
+ * The entity may be stored as a string as type info is not available when it 
is deserialized, 
+ * and that's a relatively convenient common format.
+ *  
+ * TODO It would be nice to support other parsing, storing the byte array.
+ */
+public class BuiltResponsePreservingError extends BuiltResponse {
+
+    private Throwable error;
+
+    public BuiltResponsePreservingError(int status, Headers<Object> headers, 
Object entity, Annotation[] annotations, Throwable error) {
+        super(status, headers, entity, annotations);
+        this.error = error;
+    }
+    
+    @SuppressWarnings("deprecation")
+    public static <T> Response copyResponseAndClose(Response source, Class<T> 
type) {
+        int status = -1;
+        Headers<Object> headers = new Headers<Object>();
+        Object entity = null;
+        try {
+            status = source.getStatus();
+            if (source instanceof BaseClientResponse)
+                headers.putAll(((BaseClientResponse<?>)source).getMetadata());
+            if (source instanceof org.jboss.resteasy.client.ClientResponse) {
+                entity = 
((org.jboss.resteasy.client.ClientResponse<?>)source).getEntity(type);
+            } else {
+                entity = source.getEntity();
+            }
+            return new BuiltResponsePreservingError(status, headers, entity, 
new Annotation[0], null);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            return new BuiltResponsePreservingError(status, headers, entity, 
new Annotation[0], e);
+        } finally {
+            if (source instanceof BaseClientResponse)
+                ((BaseClientResponse<?>)source).close();
+        }
+    }
+    
+    @Override
+    public Object getEntity() {
+        if (error!=null) Exceptions.propagate(error);
+        return super.getEntity();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/test/java/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/test/java/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
 
b/usage/rest-client/src/test/java/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
deleted file mode 100644
index a55aa45..0000000
--- 
a/usage/rest-client/src/test/java/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.rest.client;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.util.Collection;
-
-import javax.ws.rs.core.Response;
-
-import org.eclipse.jetty.server.Server;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.Application;
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.location.basic.BasicLocationRegistry;
-import brooklyn.management.ManagementContext;
-import brooklyn.management.internal.LocalManagementContext;
-import brooklyn.rest.BrooklynRestApiLauncher;
-import brooklyn.rest.BrooklynRestApiLauncherTest;
-import brooklyn.rest.domain.ApplicationSpec;
-import brooklyn.rest.domain.ApplicationSummary;
-import brooklyn.rest.domain.EntitySpec;
-import brooklyn.rest.domain.EntitySummary;
-import brooklyn.rest.domain.SensorSummary;
-import brooklyn.test.Asserts;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-@Test(singleThreaded = true)
-public class ApplicationResourceIntegrationTest {
-
-    private static final Logger log = 
LoggerFactory.getLogger(ApplicationResourceIntegrationTest.class);
-
-    private static final Duration LONG_WAIT = Duration.minutes(10);
-    
-    private final String redisSpec = "{\"name\": \"redis-app\", \"type\": 
\"brooklyn.entity.nosql.redis.RedisStore\", \"locations\": [ \"localhost\"]}";
-    
-    private final ApplicationSpec legacyRedisSpec = 
ApplicationSpec.builder().name("redis-legacy-app")
-            .entities(ImmutableSet.of(new EntitySpec("redis-ent", 
"brooklyn.entity.nosql.redis.RedisStore")))
-            .locations(ImmutableSet.of("localhost"))
-            .build();
-
-    private ManagementContext manager;
-
-    protected synchronized ManagementContext getManagementContext() throws 
Exception {
-        if (manager == null) {
-            manager = new LocalManagementContext();
-            
BrooklynRestApiLauncherTest.forceUseOfDefaultCatalogWithJavaClassPath(manager);
-            BasicLocationRegistry.setupLocationRegistryForTesting(manager);
-            BrooklynRestApiLauncherTest.enableAnyoneLogin(manager);
-        }
-        return manager;
-    }
-
-    BrooklynApi api;
-
-    @BeforeClass(groups = "Integration")
-    public void setUp() throws Exception {
-        Server server = BrooklynRestApiLauncher.launcher()
-                .managementContext(getManagementContext())
-                .start();
-
-        api = new BrooklynApi("http://localhost:"; + 
server.getConnectors()[0].getPort() + "/");
-    }
-
-    @AfterClass(alwaysRun = true)
-    public void tearDown() throws Exception {
-        for (Application app : getManagementContext().getApplications()) {
-            try {
-                ((StartableApplication) app).stop();
-            } catch (Exception e) {
-                log.warn("Error stopping app " + app + " during test teardown: 
" + e);
-            }
-        }
-    }
-
-    @Test(groups = "Integration")
-    public void testDeployRedisApplication() throws Exception {
-        Response response = 
api.getApplicationApi().createPoly(redisSpec.getBytes());
-        assertEquals(response.getStatus(), 201);
-        assertEquals(getManagementContext().getApplications().size(), 1);
-        final String entityId = 
getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId();
-        assertServiceStateEventually("redis-app", entityId, Lifecycle.RUNNING, 
LONG_WAIT);
-    }
-    
-    @Test(groups = "Integration", dependsOnMethods = 
"testDeployRedisApplication")
-    public void testDeployLegacyRedisApplication() throws Exception {
-        @SuppressWarnings("deprecation")
-        Response response = api.getApplicationApi().create(legacyRedisSpec);
-        assertEquals(response.getStatus(), 201);
-        assertEquals(getManagementContext().getApplications().size(), 2);
-        assertServiceStateEventually("redis-legacy-app", "redis-ent", 
Lifecycle.RUNNING, LONG_WAIT);
-        
-        // Tear the app down so it doesn't interfere with other tests 
-        Response deleteResponse = 
api.getApplicationApi().delete("redis-legacy-app");
-        assertEquals(deleteResponse.getStatus(), 202);
-        assertEquals(getManagementContext().getApplications().size(), 1);
-    }
-
-    @Test(groups = "Integration", dependsOnMethods = 
"testDeployRedisApplication")
-    public void testListEntities() {
-        Collection<EntitySummary> entities = 
api.getEntityApi().list("redis-app");
-        Assert.assertFalse(entities.isEmpty());
-    }
-
-    @Test(groups = "Integration", dependsOnMethods = 
"testDeployRedisApplication")
-    public void testListSensorsRedis() throws Exception {
-        String entityId = 
getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId();
-        Collection<SensorSummary> sensors = 
api.getSensorApi().list("redis-app", entityId);
-        assertTrue(sensors.size() > 0);
-        SensorSummary uptime = Iterables.find(sensors, new 
Predicate<SensorSummary>() {
-            @Override
-            public boolean apply(SensorSummary sensorSummary) {
-                return sensorSummary.getName().equals("redis.uptime");
-            }
-        });
-        assertEquals(uptime.getType(), "java.lang.Integer");
-    }
-
-    @Test(groups = "Integration", dependsOnMethods = {"testListSensorsRedis", 
"testListEntities"})
-    public void testTriggerRedisStopEffector() throws Exception {
-        final String entityId = 
getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId();
-        Response response = api.getEffectorApi().invoke("redis-app", entityId, 
"stop", "5000", ImmutableMap.<String, Object>of());
-
-        assertEquals(response.getStatus(), 
Response.Status.ACCEPTED.getStatusCode());
-        assertServiceStateEventually("redis-app", entityId, Lifecycle.STOPPED, 
LONG_WAIT);
-    }
-
-    @Test(groups = "Integration", dependsOnMethods = 
"testTriggerRedisStopEffector")
-    public void testDeleteRedisApplication() throws Exception {
-        int size = getManagementContext().getApplications().size();
-        Response response = api.getApplicationApi().delete("redis-app");
-        Assert.assertNotNull(response);
-        try {
-            Asserts.succeedsEventually(ImmutableMap.of("timeout", 
Duration.minutes(1)), new Runnable() {
-                public void run() {
-                    try {
-                        ApplicationSummary summary = 
api.getApplicationApi().get("redis-app");
-                        fail("Redis app failed to disappear: 
summary="+summary);
-                    } catch (Exception failure) {
-                        // expected -- it will be a ClientResponseFailure but 
that class is deprecated so catching all
-                        // and asserting contains the word 404
-                        Assert.assertTrue(failure.toString().indexOf("404") >= 
0, "wrong failure, got: "+failure);
-                    }
-                }});
-        } catch (Exception failure) {
-            // expected -- as above
-            Assert.assertTrue(failure.toString().indexOf("404") >= 0, "wrong 
failure, got: "+failure);
-        }
-
-        assertEquals(getManagementContext().getApplications().size(), size - 
1);
-    }
-
-    private void assertServiceStateEventually(final String app, final String 
entity, final Lifecycle state, Duration timeout) {
-        Asserts.succeedsEventually(ImmutableMap.of("timeout", timeout), new 
Runnable() {
-            public void run() {
-                Object status = api.getSensorApi().get(app, entity, 
"service.state", false);
-                
assertTrue(state.toString().equalsIgnoreCase(status.toString()), 
"status="+status);
-            }});
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/test/java/brooklyn/rest/client/BrooklynApiRestClientTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/test/java/brooklyn/rest/client/BrooklynApiRestClientTest.java
 
b/usage/rest-client/src/test/java/brooklyn/rest/client/BrooklynApiRestClientTest.java
deleted file mode 100644
index 7a320e7..0000000
--- 
a/usage/rest-client/src/test/java/brooklyn/rest/client/BrooklynApiRestClientTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.rest.client;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.ws.rs.core.Response;
-
-import org.eclipse.jetty.server.Server;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.Application;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.location.basic.BasicLocationRegistry;
-import brooklyn.management.ManagementContext;
-import brooklyn.management.internal.LocalManagementContext;
-import brooklyn.rest.BrooklynRestApiLauncher;
-import brooklyn.rest.BrooklynRestApiLauncherTest;
-import brooklyn.rest.domain.ApplicationSummary;
-import brooklyn.rest.domain.CatalogLocationSummary;
-import brooklyn.rest.security.provider.TestSecurityProvider;
-import brooklyn.test.HttpTestUtils;
-import brooklyn.test.entity.TestEntity;
-
-@Test
-public class BrooklynApiRestClientTest {
-
-    private static final Logger log = 
LoggerFactory.getLogger(BrooklynApiRestClientTest.class);
-
-    private ManagementContext manager;
-
-    private BrooklynApi api;
-
-    protected synchronized ManagementContext getManagementContext() throws 
Exception {
-        if (manager == null) {
-            manager = new LocalManagementContext();
-            
BrooklynRestApiLauncherTest.forceUseOfDefaultCatalogWithJavaClassPath(manager);
-            BasicLocationRegistry.setupLocationRegistryForTesting(manager);
-            BrooklynRestApiLauncherTest.enableAnyoneLogin(manager);
-        }
-        return manager;
-    }
-
-    @BeforeClass
-    public void setUp() throws Exception {
-        Server server = BrooklynRestApiLauncher.launcher()
-                .managementContext(manager)
-                .securityProvider(TestSecurityProvider.class)
-                .start();
-
-        api = new BrooklynApi("http://localhost:"; + 
server.getConnectors()[0].getPort() + "/",
-                TestSecurityProvider.USER, TestSecurityProvider.PASSWORD);
-    }
-
-    @AfterClass(alwaysRun = true)
-    public void tearDown() throws Exception {
-        for (Application app : getManagementContext().getApplications()) {
-            try {
-                ((StartableApplication) app).stop();
-            } catch (Exception e) {
-                log.warn("Error stopping app " + app + " during test teardown: 
" + e);
-            }
-        }
-        Entities.destroyAll(getManagementContext());
-    }
-
-    public void testLocationApi() throws Exception {
-        log.info("Testing location API");
-        Map<String, Map<String, Object>> locations = 
api.getLocationApi().getLocatedLocations();
-        log.info("locations located are: "+locations);
-    }
-
-    public void testCatalogApiLocations() throws Exception {
-        List<CatalogLocationSummary> locations = 
api.getCatalogApi().listLocations(".*", null, false);
-        log.info("locations from catalog are: "+locations);
-    }
-
-    public void testApplicationApiList() throws Exception {
-        List<ApplicationSummary> apps = api.getApplicationApi().list(null);
-        log.info("apps are: "+apps);
-    }
-    
-    public void testApplicationApiCreate() throws Exception {
-        Response r1 = api.getApplicationApi().createFromYaml("name: 
test-1234\n"
-            + "services: [ { type: "+TestEntity.class.getName()+" } ]");
-        HttpTestUtils.assertHealthyStatusCode(r1.getStatus());
-        log.info("creation result: "+r1.getEntity());
-        List<ApplicationSummary> apps = api.getApplicationApi().list(null);
-        log.info("apps with test: "+apps);
-        Assert.assertTrue(apps.toString().contains("test-1234"), "should have 
had test-1234 as an app; instead: "+apps);
-    }
-    
-    public void testApplicationApiHandledError() throws Exception {
-        Response r1 = api.getApplicationApi().createFromYaml("name: test");
-        Assert.assertTrue(r1.getStatus()/100 != 2, "needed an unhealthy 
status, not "+r1.getStatus());
-        Object entity = r1.getEntity();
-        Assert.assertTrue(entity.toString().indexOf("Unrecognized application 
blueprint format: no services defined")>=0,
-            "Missing expected text in response: "+entity.toString());
-    }
-
-    public void testApplicationApiThrownError() throws Exception {
-        try {
-            ApplicationSummary summary = 
api.getApplicationApi().get("test-5678");
-            Assert.fail("Should have thrown, not given: "+summary);
-        } catch (Exception e) {
-            e.printStackTrace();
-            Assert.assertTrue(e.toString().toLowerCase().contains("not found"),
-                "Missing expected text in response: "+e.toString());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
 
b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
new file mode 100644
index 0000000..02c19bb
--- /dev/null
+++ 
b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/ApplicationResourceIntegrationTest.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.client;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.Collection;
+
+import javax.ws.rs.core.Response;
+
+import org.eclipse.jetty.server.Server;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Application;
+import brooklyn.entity.basic.Lifecycle;
+import brooklyn.entity.basic.StartableApplication;
+import brooklyn.location.basic.BasicLocationRegistry;
+import brooklyn.management.ManagementContext;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.rest.BrooklynRestApiLauncher;
+import brooklyn.rest.BrooklynRestApiLauncherTest;
+import brooklyn.rest.domain.ApplicationSpec;
+import brooklyn.rest.domain.ApplicationSummary;
+import brooklyn.rest.domain.EntitySpec;
+import brooklyn.rest.domain.EntitySummary;
+import brooklyn.rest.domain.SensorSummary;
+import brooklyn.test.Asserts;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+@Test(singleThreaded = true)
+public class ApplicationResourceIntegrationTest {
+
+    private static final Logger log = 
LoggerFactory.getLogger(ApplicationResourceIntegrationTest.class);
+
+    private static final Duration LONG_WAIT = Duration.minutes(10);
+    
+    private final String redisSpec = "{\"name\": \"redis-app\", \"type\": 
\"brooklyn.entity.nosql.redis.RedisStore\", \"locations\": [ \"localhost\"]}";
+    
+    private final ApplicationSpec legacyRedisSpec = 
ApplicationSpec.builder().name("redis-legacy-app")
+            .entities(ImmutableSet.of(new EntitySpec("redis-ent", 
"brooklyn.entity.nosql.redis.RedisStore")))
+            .locations(ImmutableSet.of("localhost"))
+            .build();
+
+    private ManagementContext manager;
+
+    protected synchronized ManagementContext getManagementContext() throws 
Exception {
+        if (manager == null) {
+            manager = new LocalManagementContext();
+            
BrooklynRestApiLauncherTest.forceUseOfDefaultCatalogWithJavaClassPath(manager);
+            BasicLocationRegistry.setupLocationRegistryForTesting(manager);
+            BrooklynRestApiLauncherTest.enableAnyoneLogin(manager);
+        }
+        return manager;
+    }
+
+    BrooklynApi api;
+
+    @BeforeClass(groups = "Integration")
+    public void setUp() throws Exception {
+        Server server = BrooklynRestApiLauncher.launcher()
+                .managementContext(getManagementContext())
+                .start();
+
+        api = new BrooklynApi("http://localhost:"; + 
server.getConnectors()[0].getPort() + "/");
+    }
+
+    @AfterClass(alwaysRun = true)
+    public void tearDown() throws Exception {
+        for (Application app : getManagementContext().getApplications()) {
+            try {
+                ((StartableApplication) app).stop();
+            } catch (Exception e) {
+                log.warn("Error stopping app " + app + " during test teardown: 
" + e);
+            }
+        }
+    }
+
+    @Test(groups = "Integration")
+    public void testDeployRedisApplication() throws Exception {
+        Response response = 
api.getApplicationApi().createPoly(redisSpec.getBytes());
+        assertEquals(response.getStatus(), 201);
+        assertEquals(getManagementContext().getApplications().size(), 1);
+        final String entityId = 
getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId();
+        assertServiceStateEventually("redis-app", entityId, Lifecycle.RUNNING, 
LONG_WAIT);
+    }
+    
+    @Test(groups = "Integration", dependsOnMethods = 
"testDeployRedisApplication")
+    public void testDeployLegacyRedisApplication() throws Exception {
+        @SuppressWarnings("deprecation")
+        Response response = api.getApplicationApi().create(legacyRedisSpec);
+        assertEquals(response.getStatus(), 201);
+        assertEquals(getManagementContext().getApplications().size(), 2);
+        assertServiceStateEventually("redis-legacy-app", "redis-ent", 
Lifecycle.RUNNING, LONG_WAIT);
+        
+        // Tear the app down so it doesn't interfere with other tests 
+        Response deleteResponse = 
api.getApplicationApi().delete("redis-legacy-app");
+        assertEquals(deleteResponse.getStatus(), 202);
+        assertEquals(getManagementContext().getApplications().size(), 1);
+    }
+
+    @Test(groups = "Integration", dependsOnMethods = 
"testDeployRedisApplication")
+    public void testListEntities() {
+        Collection<EntitySummary> entities = 
api.getEntityApi().list("redis-app");
+        Assert.assertFalse(entities.isEmpty());
+    }
+
+    @Test(groups = "Integration", dependsOnMethods = 
"testDeployRedisApplication")
+    public void testListSensorsRedis() throws Exception {
+        String entityId = 
getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId();
+        Collection<SensorSummary> sensors = 
api.getSensorApi().list("redis-app", entityId);
+        assertTrue(sensors.size() > 0);
+        SensorSummary uptime = Iterables.find(sensors, new 
Predicate<SensorSummary>() {
+            @Override
+            public boolean apply(SensorSummary sensorSummary) {
+                return sensorSummary.getName().equals("redis.uptime");
+            }
+        });
+        assertEquals(uptime.getType(), "java.lang.Integer");
+    }
+
+    @Test(groups = "Integration", dependsOnMethods = {"testListSensorsRedis", 
"testListEntities"})
+    public void testTriggerRedisStopEffector() throws Exception {
+        final String entityId = 
getManagementContext().getApplications().iterator().next().getChildren().iterator().next().getId();
+        Response response = api.getEffectorApi().invoke("redis-app", entityId, 
"stop", "5000", ImmutableMap.<String, Object>of());
+
+        assertEquals(response.getStatus(), 
Response.Status.ACCEPTED.getStatusCode());
+        assertServiceStateEventually("redis-app", entityId, Lifecycle.STOPPED, 
LONG_WAIT);
+    }
+
+    @Test(groups = "Integration", dependsOnMethods = 
"testTriggerRedisStopEffector")
+    public void testDeleteRedisApplication() throws Exception {
+        int size = getManagementContext().getApplications().size();
+        Response response = api.getApplicationApi().delete("redis-app");
+        Assert.assertNotNull(response);
+        try {
+            Asserts.succeedsEventually(ImmutableMap.of("timeout", 
Duration.minutes(1)), new Runnable() {
+                public void run() {
+                    try {
+                        ApplicationSummary summary = 
api.getApplicationApi().get("redis-app");
+                        fail("Redis app failed to disappear: 
summary="+summary);
+                    } catch (Exception failure) {
+                        // expected -- it will be a ClientResponseFailure but 
that class is deprecated so catching all
+                        // and asserting contains the word 404
+                        Assert.assertTrue(failure.toString().indexOf("404") >= 
0, "wrong failure, got: "+failure);
+                    }
+                }});
+        } catch (Exception failure) {
+            // expected -- as above
+            Assert.assertTrue(failure.toString().indexOf("404") >= 0, "wrong 
failure, got: "+failure);
+        }
+
+        assertEquals(getManagementContext().getApplications().size(), size - 
1);
+    }
+
+    private void assertServiceStateEventually(final String app, final String 
entity, final Lifecycle state, Duration timeout) {
+        Asserts.succeedsEventually(ImmutableMap.of("timeout", timeout), new 
Runnable() {
+            public void run() {
+                Object status = api.getSensorApi().get(app, entity, 
"service.state", false);
+                
assertTrue(state.toString().equalsIgnoreCase(status.toString()), 
"status="+status);
+            }});
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c5256b18/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java
----------------------------------------------------------------------
diff --git 
a/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java
 
b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java
new file mode 100644
index 0000000..c36a456
--- /dev/null
+++ 
b/usage/rest-client/src/test/java/org/apache/brooklyn/rest/client/BrooklynApiRestClientTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.client;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+
+import org.eclipse.jetty.server.Server;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Application;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.StartableApplication;
+import brooklyn.location.basic.BasicLocationRegistry;
+import brooklyn.management.ManagementContext;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.rest.BrooklynRestApiLauncher;
+import brooklyn.rest.BrooklynRestApiLauncherTest;
+import brooklyn.rest.domain.ApplicationSummary;
+import brooklyn.rest.domain.CatalogLocationSummary;
+import brooklyn.rest.security.provider.TestSecurityProvider;
+import brooklyn.test.HttpTestUtils;
+import brooklyn.test.entity.TestEntity;
+
+@Test
+public class BrooklynApiRestClientTest {
+
+    private static final Logger log = 
LoggerFactory.getLogger(BrooklynApiRestClientTest.class);
+
+    private ManagementContext manager;
+
+    private BrooklynApi api;
+
+    protected synchronized ManagementContext getManagementContext() throws 
Exception {
+        if (manager == null) {
+            manager = new LocalManagementContext();
+            
BrooklynRestApiLauncherTest.forceUseOfDefaultCatalogWithJavaClassPath(manager);
+            BasicLocationRegistry.setupLocationRegistryForTesting(manager);
+            BrooklynRestApiLauncherTest.enableAnyoneLogin(manager);
+        }
+        return manager;
+    }
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        Server server = BrooklynRestApiLauncher.launcher()
+                .managementContext(manager)
+                .securityProvider(TestSecurityProvider.class)
+                .start();
+
+        api = new BrooklynApi("http://localhost:"; + 
server.getConnectors()[0].getPort() + "/",
+                TestSecurityProvider.USER, TestSecurityProvider.PASSWORD);
+    }
+
+    @AfterClass(alwaysRun = true)
+    public void tearDown() throws Exception {
+        for (Application app : getManagementContext().getApplications()) {
+            try {
+                ((StartableApplication) app).stop();
+            } catch (Exception e) {
+                log.warn("Error stopping app " + app + " during test teardown: 
" + e);
+            }
+        }
+        Entities.destroyAll(getManagementContext());
+    }
+
+    public void testLocationApi() throws Exception {
+        log.info("Testing location API");
+        Map<String, Map<String, Object>> locations = 
api.getLocationApi().getLocatedLocations();
+        log.info("locations located are: "+locations);
+    }
+
+    public void testCatalogApiLocations() throws Exception {
+        List<CatalogLocationSummary> locations = 
api.getCatalogApi().listLocations(".*", null, false);
+        log.info("locations from catalog are: "+locations);
+    }
+
+    public void testApplicationApiList() throws Exception {
+        List<ApplicationSummary> apps = api.getApplicationApi().list(null);
+        log.info("apps are: "+apps);
+    }
+    
+    public void testApplicationApiCreate() throws Exception {
+        Response r1 = api.getApplicationApi().createFromYaml("name: 
test-1234\n"
+            + "services: [ { type: "+TestEntity.class.getName()+" } ]");
+        HttpTestUtils.assertHealthyStatusCode(r1.getStatus());
+        log.info("creation result: "+r1.getEntity());
+        List<ApplicationSummary> apps = api.getApplicationApi().list(null);
+        log.info("apps with test: "+apps);
+        Assert.assertTrue(apps.toString().contains("test-1234"), "should have 
had test-1234 as an app; instead: "+apps);
+    }
+    
+    public void testApplicationApiHandledError() throws Exception {
+        Response r1 = api.getApplicationApi().createFromYaml("name: test");
+        Assert.assertTrue(r1.getStatus()/100 != 2, "needed an unhealthy 
status, not "+r1.getStatus());
+        Object entity = r1.getEntity();
+        Assert.assertTrue(entity.toString().indexOf("Unrecognized application 
blueprint format: no services defined")>=0,
+            "Missing expected text in response: "+entity.toString());
+    }
+
+    public void testApplicationApiThrownError() throws Exception {
+        try {
+            ApplicationSummary summary = 
api.getApplicationApi().get("test-5678");
+            Assert.fail("Should have thrown, not given: "+summary);
+        } catch (Exception e) {
+            e.printStackTrace();
+            Assert.assertTrue(e.toString().toLowerCase().contains("not found"),
+                "Missing expected text in response: "+e.toString());
+        }
+    }
+}

Reply via email to