Repository: brooklyn-server Updated Branches: refs/heads/master a2820e5f6 -> fa19e8f5f
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullHttpServletRequestProvider.java ---------------------------------------------------------------------- diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullHttpServletRequestProvider.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullHttpServletRequestProvider.java deleted file mode 100644 index 7a24f31..0000000 --- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullHttpServletRequestProvider.java +++ /dev/null @@ -1,46 +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 org.apache.brooklyn.rest.util; - -import java.lang.reflect.Type; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.Context; -import javax.ws.rs.ext.Provider; - -import com.sun.jersey.core.spi.component.ComponentContext; -import com.sun.jersey.core.spi.component.ComponentScope; -import com.sun.jersey.spi.inject.Injectable; -import com.sun.jersey.spi.inject.InjectableProvider; - -@Provider -public class NullHttpServletRequestProvider implements InjectableProvider<Context, Type> { - public Injectable<HttpServletRequest> getInjectable(ComponentContext ic, - Context a, Type c) { - if (HttpServletRequest.class == c) { - return new Injectable<HttpServletRequest>() { - public HttpServletRequest getValue() { return null; } - }; - } else - return null; - } - public ComponentScope getScope() { - return ComponentScope.Singleton; - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullServletConfigProvider.java ---------------------------------------------------------------------- diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullServletConfigProvider.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullServletConfigProvider.java deleted file mode 100644 index 106780d..0000000 --- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/NullServletConfigProvider.java +++ /dev/null @@ -1,51 +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 org.apache.brooklyn.rest.util; - -import java.lang.reflect.Type; - -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.ext.Provider; - -import com.sun.jersey.core.spi.component.ComponentContext; -import com.sun.jersey.core.spi.component.ComponentScope; -import com.sun.jersey.spi.container.servlet.WebConfig; -import com.sun.jersey.spi.inject.Injectable; -import com.sun.jersey.spi.inject.InjectableProvider; - -@Provider -public class NullServletConfigProvider implements InjectableProvider<Context, Type> { - public Injectable<ServletContext> getInjectable(ComponentContext ic, - Context a, Type c) { - if (ServletContext.class == c) { - return new Injectable<ServletContext>() { - public ServletContext getValue() { return null; } - }; - } else if (WebConfig.class == c) { - return new Injectable<ServletContext>() { - public ServletContext getValue() { return null; } - }; - } else - return null; - } - public ComponentScope getScope() { - return ComponentScope.Singleton; - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerIntegrationTest.java ---------------------------------------------------------------------- diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerIntegrationTest.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerIntegrationTest.java new file mode 100644 index 0000000..1cf79e8 --- /dev/null +++ b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerIntegrationTest.java @@ -0,0 +1,173 @@ +/* + * 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.util.json; + +import java.io.NotSerializableException; +import java.net.URI; +import java.util.Map; + +import javax.ws.rs.core.MediaType; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; +import org.apache.brooklyn.core.test.entity.TestApplication; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.rest.BrooklynRestApiLauncher; +import org.apache.brooklyn.rest.util.json.BrooklynJacksonSerializerTest.SelfRefNonSerializableClass; +import org.apache.brooklyn.util.http.HttpTool; +import org.apache.http.client.HttpClient; +import org.apache.http.client.utils.URIBuilder; +import org.eclipse.jetty.server.NetworkConnector; +import org.eclipse.jetty.server.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.Gson; + +public class BrooklynJacksonSerializerIntegrationTest { + + private static final Logger log = LoggerFactory.getLogger(BrooklynJacksonSerializerIntegrationTest.class); + + // Ensure TEXT_PLAIN just returns toString for ManagementContext instance. + // Strangely, testWithLauncherSerializingListsContainingEntitiesAndOtherComplexStuff ended up in the + // EntityConfigResource.getPlain code, throwing a ClassCastException. + // + // TODO This tests the fix for that ClassCastException, but does not explain why + // testWithLauncherSerializingListsContainingEntitiesAndOtherComplexStuff was calling it. + @Test(groups="Integration") //because of time + public void testWithAcceptsPlainText() throws Exception { + ManagementContext mgmt = LocalManagementContextForTests.newInstance(); + Server server = null; + try { + server = BrooklynRestApiLauncher.launcher().managementContext(mgmt).start(); + HttpClient client = HttpTool.httpClientBuilder().build(); + + TestApplication app = TestApplication.Factory.newManagedInstanceForTests(mgmt); + + String serverAddress = "http://localhost:"+((NetworkConnector)server.getConnectors()[0]).getLocalPort(); + String appUrl = serverAddress + "/v1/applications/" + app.getId(); + String entityUrl = appUrl + "/entities/" + app.getId(); + URI configUri = new URIBuilder(entityUrl + "/config/" + TestEntity.CONF_OBJECT.getName()) + .addParameter("raw", "true") + .build(); + + // assert config here is just mgmt.toString() + app.config().set(TestEntity.CONF_OBJECT, mgmt); + String content = get(client, configUri, ImmutableMap.of("Accept", MediaType.TEXT_PLAIN)); + log.info("CONFIG MGMT is:\n"+content); + Assert.assertEquals(content, mgmt.toString(), "content="+content); + + } finally { + try { + if (server != null) server.stop(); + } catch (Exception e) { + log.warn("failed to stop server: "+e); + } + Entities.destroyAll(mgmt); + } + } + + @Test(groups="Integration") //because of time + public void testWithLauncherSerializingListsContainingEntitiesAndOtherComplexStuff() throws Exception { + ManagementContext mgmt = LocalManagementContextForTests.newInstance(); + Server server = null; + try { + server = BrooklynRestApiLauncher.launcher().managementContext(mgmt).start(); + HttpClient client = HttpTool.httpClientBuilder().build(); + + TestApplication app = TestApplication.Factory.newManagedInstanceForTests(mgmt); + + String serverAddress = "http://localhost:"+((NetworkConnector)server.getConnectors()[0]).getLocalPort(); + String appUrl = serverAddress + "/v1/applications/" + app.getId(); + String entityUrl = appUrl + "/entities/" + app.getId(); + URI configUri = new URIBuilder(entityUrl + "/config/" + TestEntity.CONF_OBJECT.getName()) + .addParameter("raw", "true") + .build(); + + // assert config here is just mgmt + app.config().set(TestEntity.CONF_OBJECT, mgmt); + String content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); + log.info("CONFIG MGMT is:\n"+content); + @SuppressWarnings("rawtypes") + Map values = new Gson().fromJson(content, Map.class); + Assert.assertEquals(values, ImmutableMap.of("type", LocalManagementContextForTests.class.getCanonicalName()), "values="+values); + + // assert normal API returns the same, containing links + content = get(client, entityUrl, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); + log.info("ENTITY is: \n"+content); + values = new Gson().fromJson(content, Map.class); + Assert.assertTrue(values.size()>=3, "Map is too small: "+values); + Assert.assertTrue(values.size()<=6, "Map is too big: "+values); + Assert.assertEquals(values.get("type"), TestApplication.class.getCanonicalName(), "values="+values); + Assert.assertNotNull(values.get("links"), "Map should have contained links: values="+values); + + // but config etc returns our nicely json serialized + app.config().set(TestEntity.CONF_OBJECT, app); + content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); + log.info("CONFIG ENTITY is:\n"+content); + values = new Gson().fromJson(content, Map.class); + Assert.assertEquals(values, ImmutableMap.of("type", Entity.class.getCanonicalName(), "id", app.getId()), "values="+values); + + // and self-ref gives error + toString + SelfRefNonSerializableClass angry = new SelfRefNonSerializableClass(); + app.config().set(TestEntity.CONF_OBJECT, angry); + content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); + log.info("CONFIG ANGRY is:\n"+content); + assertErrorObjectMatchingToString(content, angry); + + // as does Server + app.config().set(TestEntity.CONF_OBJECT, server); + content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); + // NOTE, if using the default visibility / object mapper, the getters of the object are invoked + // resulting in an object which is huge, 7+MB -- and it wreaks havoc w eclipse console regex parsing! + // (but with our custom VisibilityChecker server just gives us the nicer error!) + log.info("CONFIG SERVER is:\n"+content); + assertErrorObjectMatchingToString(content, server); + Assert.assertTrue(content.contains(NotSerializableException.class.getCanonicalName()), "server should have contained things which are not serializable"); + Assert.assertTrue(content.length() < 1024, "content should not have been very long; instead was: "+content.length()); + + } finally { + try { + if (server != null) server.stop(); + } catch (Exception e) { + log.warn("failed to stop server: "+e); + } + Entities.destroyAll(mgmt); + } + } + + private void assertErrorObjectMatchingToString(String content, Object expected) { + Object value = new Gson().fromJson(content, Object.class); + Assert.assertTrue(value instanceof Map, "Expected map, got: "+value); + Assert.assertEquals(((Map<?,?>)value).get("toString"), expected.toString()); + } + + private String get(HttpClient client, String uri, Map<String, String> headers) { + return get(client, URI.create(uri), headers); + } + + private String get(HttpClient client, URI uri, Map<String, String> headers) { + return HttpTool.httpGet(client, uri, headers).getContentAsString(); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java ---------------------------------------------------------------------- diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java deleted file mode 100644 index 9542eda..0000000 --- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java +++ /dev/null @@ -1,399 +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 org.apache.brooklyn.rest.util.json; - -import java.io.NotSerializableException; -import java.net.URI; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.MediaType; - -import org.apache.http.client.HttpClient; -import org.apache.http.client.utils.URIBuilder; -import org.eclipse.jetty.server.Server; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.core.entity.Attributes; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; -import org.apache.brooklyn.core.test.entity.TestApplication; -import org.apache.brooklyn.core.test.entity.TestEntity; -import org.apache.brooklyn.rest.BrooklynRestApiLauncher; -import org.apache.brooklyn.util.collections.MutableList; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.http.HttpTool; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.stream.Streams; -import org.apache.brooklyn.util.text.Strings; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import com.google.gson.Gson; -import org.eclipse.jetty.server.NetworkConnector; - -public class BrooklynJacksonSerializerTest { - - private static final Logger log = LoggerFactory.getLogger(BrooklynJacksonSerializerTest.class); - - public static class SillyClassWithManagementContext { - @JsonProperty - ManagementContext mgmt; - @JsonProperty - String id; - - public SillyClassWithManagementContext() { } - - public SillyClassWithManagementContext(String id, ManagementContext mgmt) { - this.id = id; - this.mgmt = mgmt; - } - - @Override - public String toString() { - return super.toString()+"[id="+id+";mgmt="+mgmt+"]"; - } - } - - @Test - public void testCustomSerializerWithSerializableSillyManagementExample() throws Exception { - ManagementContext mgmt = LocalManagementContextForTests.newInstance(); - try { - - ObjectMapper mapper = BrooklynJacksonJsonProvider.newPrivateObjectMapper(mgmt); - - SillyClassWithManagementContext silly = new SillyClassWithManagementContext("123", mgmt); - log.info("silly is: "+silly); - - String sillyS = mapper.writeValueAsString(silly); - - log.info("silly json is: "+sillyS); - - SillyClassWithManagementContext silly2 = mapper.readValue(sillyS, SillyClassWithManagementContext.class); - log.info("silly2 is: "+silly2); - - Assert.assertEquals(silly.id, silly2.id); - - } finally { - Entities.destroyAll(mgmt); - } - } - - public static class SelfRefNonSerializableClass { - @JsonProperty - Object bogus = this; - } - - @Test - public void testSelfReferenceFailsWhenStrict() { - checkNonSerializableWhenStrict(new SelfRefNonSerializableClass()); - } - @Test - public void testSelfReferenceGeneratesErrorMapObject() throws Exception { - checkSerializesAsMapWithErrorAndToString(new SelfRefNonSerializableClass()); - } - @Test - public void testNonSerializableInListIsShownInList() throws Exception { - List<?> result = checkSerializesAs(MutableList.of(1, new SelfRefNonSerializableClass()), List.class); - Assert.assertEquals( result.get(0), 1 ); - Assert.assertEquals( ((Map<?,?>)result.get(1)).get("errorType"), NotSerializableException.class.getName() ); - } - @Test - public void testNonSerializableInMapIsShownInMap() throws Exception { - Map<?,?> result = checkSerializesAs(MutableMap.of("x", new SelfRefNonSerializableClass()), Map.class); - Assert.assertEquals( ((Map<?,?>)result.get("x")).get("errorType"), NotSerializableException.class.getName() ); - } - static class TupleWithNonSerializable { - String good = "bon"; - SelfRefNonSerializableClass bad = new SelfRefNonSerializableClass(); - } - @Test - public void testNonSerializableInObjectIsShownInMap() throws Exception { - String resultS = checkSerializesAs(new TupleWithNonSerializable(), null); - log.info("nested non-serializable json is "+resultS); - Assert.assertTrue(resultS.startsWith("{\"good\":\"bon\",\"bad\":{"), "expected a nested map for the error field, not "+resultS); - - Map<?,?> result = checkSerializesAs(new TupleWithNonSerializable(), Map.class); - Assert.assertEquals( result.get("good"), "bon" ); - Assert.assertTrue( result.containsKey("bad"), "Should have had a key for field 'bad'" ); - Assert.assertEquals( ((Map<?,?>)result.get("bad")).get("errorType"), NotSerializableException.class.getName() ); - } - - public static class EmptyClass { - } - - @Test - public void testEmptySerializesAsEmpty() throws Exception { - // deliberately, a class with no fields and no annotations serializes as an error, - // because the alternative, {}, is useless. however if it *is* annotated, as below, then it will serialize fine. - checkSerializesAsMapWithErrorAndToString(new SelfRefNonSerializableClass()); - } - @Test - public void testEmptyNonSerializableFailsWhenStrict() { - checkNonSerializableWhenStrict(new EmptyClass()); - } - - @JsonSerialize - public static class EmptyClassWithSerialize { - } - - @Test - public void testEmptyAnnotatedSerializesAsEmptyEvenWhenStrict() throws Exception { - try { - BidiSerialization.setStrictSerialization(true); - testEmptyAnnotatedSerializesAsEmpty(); - } finally { - BidiSerialization.clearStrictSerialization(); - } - } - - @Test - public void testEmptyAnnotatedSerializesAsEmpty() throws Exception { - Map<?, ?> map = checkSerializesAs( new EmptyClassWithSerialize(), Map.class ); - Assert.assertTrue(map.isEmpty(), "Expected an empty map; instead got: "+map); - - String result = checkSerializesAs( MutableList.of(new EmptyClassWithSerialize()), null ); - result = result.replaceAll(" ", "").trim(); - Assert.assertEquals(result, "[{}]"); - } - - @Test - public void testSensorFailsWhenStrict() { - checkNonSerializableWhenStrict(MutableList.of(Attributes.HTTP_PORT)); - } - @Test - public void testSensorSensible() throws Exception { - Map<?,?> result = checkSerializesAs(Attributes.HTTP_PORT, Map.class); - log.info("SENSOR json is: "+result); - Assert.assertFalse(result.toString().contains("error"), "Shouldn't have had an error, instead got: "+result); - } - - @Test - public void testLinkedListSerialization() throws Exception { - LinkedList<Object> ll = new LinkedList<Object>(); - ll.add(1); ll.add("two"); - String result = checkSerializesAs(ll, null); - log.info("LLIST json is: "+result); - Assert.assertFalse(result.contains("error"), "Shouldn't have had an error, instead got: "+result); - Assert.assertEquals(Strings.collapseWhitespace(result, ""), "[1,\"two\"]"); - } - - @Test - public void testMultiMapSerialization() throws Exception { - Multimap<String, Integer> m = MultimapBuilder.hashKeys().arrayListValues().build(); - m.put("bob", 24); - m.put("bob", 25); - String result = checkSerializesAs(m, null); - log.info("multimap serialized as: " + result); - Assert.assertFalse(result.contains("error"), "Shouldn't have had an error, instead got: "+result); - Assert.assertEquals(Strings.collapseWhitespace(result, ""), "{\"bob\":[24,25]}"); - } - - @Test - public void testSupplierSerialization() throws Exception { - String result = checkSerializesAs(Strings.toStringSupplier(Streams.byteArrayOfString("x")), null); - log.info("SUPPLIER json is: "+result); - Assert.assertFalse(result.contains("error"), "Shouldn't have had an error, instead got: "+result); - } - - @Test - public void testWrappedStreamSerialization() throws Exception { - String result = checkSerializesAs(BrooklynTaskTags.tagForStream("TEST", Streams.byteArrayOfString("x")), null); - log.info("WRAPPED STREAM json is: "+result); - Assert.assertFalse(result.contains("error"), "Shouldn't have had an error, instead got: "+result); - } - - @SuppressWarnings("unchecked") - protected <T> T checkSerializesAs(Object x, Class<T> type) { - ManagementContext mgmt = LocalManagementContextForTests.newInstance(); - try { - ObjectMapper mapper = BrooklynJacksonJsonProvider.newPrivateObjectMapper(mgmt); - String tS = mapper.writeValueAsString(x); - log.debug("serialized "+x+" as "+tS); - Assert.assertTrue(tS.length() < 1000, "Data too long, size "+tS.length()+" for "+x); - if (type==null) return (T) tS; - return mapper.readValue(tS, type); - } catch (Exception e) { - throw Exceptions.propagate(e); - } finally { - Entities.destroyAll(mgmt); - } - } - protected Map<?,?> checkSerializesAsMapWithErrorAndToString(Object x) { - Map<?,?> rt = checkSerializesAs(x, Map.class); - Assert.assertEquals(rt.get("toString"), x.toString()); - Assert.assertEquals(rt.get("error"), Boolean.TRUE); - return rt; - } - protected void checkNonSerializableWhenStrict(Object x) { - checkNonSerializable(x, true); - } - protected void checkNonSerializable(Object x, boolean strict) { - ManagementContext mgmt = LocalManagementContextForTests.newInstance(); - try { - ObjectMapper mapper = BrooklynJacksonJsonProvider.newPrivateObjectMapper(mgmt); - if (strict) - BidiSerialization.setStrictSerialization(true); - - String tS = mapper.writeValueAsString(x); - Assert.fail("Should not have serialized "+x+"; instead gave: "+tS); - - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - log.info("Got expected error, when serializing "+x+": "+e); - - } finally { - if (strict) - BidiSerialization.clearStrictSerialization(); - Entities.destroyAll(mgmt); - } - } - - // Ensure TEXT_PLAIN just returns toString for ManagementContext instance. - // Strangely, testWithLauncherSerializingListsContainingEntitiesAndOtherComplexStuff ended up in the - // EntityConfigResource.getPlain code, throwing a ClassCastException. - // - // TODO This tests the fix for that ClassCastException, but does not explain why - // testWithLauncherSerializingListsContainingEntitiesAndOtherComplexStuff was calling it. - @Test(groups="Integration") //because of time - public void testWithAcceptsPlainText() throws Exception { - ManagementContext mgmt = LocalManagementContextForTests.newInstance(); - Server server = null; - try { - server = BrooklynRestApiLauncher.launcher().managementContext(mgmt).start(); - HttpClient client = HttpTool.httpClientBuilder().build(); - - TestApplication app = TestApplication.Factory.newManagedInstanceForTests(mgmt); - - String serverAddress = "http://localhost:"+((NetworkConnector)server.getConnectors()[0]).getLocalPort(); - String appUrl = serverAddress + "/v1/applications/" + app.getId(); - String entityUrl = appUrl + "/entities/" + app.getId(); - URI configUri = new URIBuilder(entityUrl + "/config/" + TestEntity.CONF_OBJECT.getName()) - .addParameter("raw", "true") - .build(); - - // assert config here is just mgmt.toString() - app.config().set(TestEntity.CONF_OBJECT, mgmt); - String content = get(client, configUri, ImmutableMap.of("Accept", MediaType.TEXT_PLAIN)); - log.info("CONFIG MGMT is:\n"+content); - Assert.assertEquals(content, mgmt.toString(), "content="+content); - - } finally { - try { - if (server != null) server.stop(); - } catch (Exception e) { - log.warn("failed to stop server: "+e); - } - Entities.destroyAll(mgmt); - } - } - - @Test(groups="Integration") //because of time - public void testWithLauncherSerializingListsContainingEntitiesAndOtherComplexStuff() throws Exception { - ManagementContext mgmt = LocalManagementContextForTests.newInstance(); - Server server = null; - try { - server = BrooklynRestApiLauncher.launcher().managementContext(mgmt).start(); - HttpClient client = HttpTool.httpClientBuilder().build(); - - TestApplication app = TestApplication.Factory.newManagedInstanceForTests(mgmt); - - String serverAddress = "http://localhost:"+((NetworkConnector)server.getConnectors()[0]).getLocalPort(); - String appUrl = serverAddress + "/v1/applications/" + app.getId(); - String entityUrl = appUrl + "/entities/" + app.getId(); - URI configUri = new URIBuilder(entityUrl + "/config/" + TestEntity.CONF_OBJECT.getName()) - .addParameter("raw", "true") - .build(); - - // assert config here is just mgmt - app.config().set(TestEntity.CONF_OBJECT, mgmt); - String content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); - log.info("CONFIG MGMT is:\n"+content); - @SuppressWarnings("rawtypes") - Map values = new Gson().fromJson(content, Map.class); - Assert.assertEquals(values, ImmutableMap.of("type", LocalManagementContextForTests.class.getCanonicalName()), "values="+values); - - // assert normal API returns the same, containing links - content = get(client, entityUrl, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); - log.info("ENTITY is: \n"+content); - values = new Gson().fromJson(content, Map.class); - Assert.assertTrue(values.size()>=3, "Map is too small: "+values); - Assert.assertTrue(values.size()<=6, "Map is too big: "+values); - Assert.assertEquals(values.get("type"), TestApplication.class.getCanonicalName(), "values="+values); - Assert.assertNotNull(values.get("links"), "Map should have contained links: values="+values); - - // but config etc returns our nicely json serialized - app.config().set(TestEntity.CONF_OBJECT, app); - content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); - log.info("CONFIG ENTITY is:\n"+content); - values = new Gson().fromJson(content, Map.class); - Assert.assertEquals(values, ImmutableMap.of("type", Entity.class.getCanonicalName(), "id", app.getId()), "values="+values); - - // and self-ref gives error + toString - SelfRefNonSerializableClass angry = new SelfRefNonSerializableClass(); - app.config().set(TestEntity.CONF_OBJECT, angry); - content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); - log.info("CONFIG ANGRY is:\n"+content); - assertErrorObjectMatchingToString(content, angry); - - // as does Server - app.config().set(TestEntity.CONF_OBJECT, server); - content = get(client, configUri, ImmutableMap.of("Accept", MediaType.APPLICATION_JSON)); - // NOTE, if using the default visibility / object mapper, the getters of the object are invoked - // resulting in an object which is huge, 7+MB -- and it wreaks havoc w eclipse console regex parsing! - // (but with our custom VisibilityChecker server just gives us the nicer error!) - log.info("CONFIG SERVER is:\n"+content); - assertErrorObjectMatchingToString(content, server); - Assert.assertTrue(content.contains(NotSerializableException.class.getCanonicalName()), "server should have contained things which are not serializable"); - Assert.assertTrue(content.length() < 1024, "content should not have been very long; instead was: "+content.length()); - - } finally { - try { - if (server != null) server.stop(); - } catch (Exception e) { - log.warn("failed to stop server: "+e); - } - Entities.destroyAll(mgmt); - } - } - - private void assertErrorObjectMatchingToString(String content, Object expected) { - Object value = new Gson().fromJson(content, Object.class); - Assert.assertTrue(value instanceof Map, "Expected map, got: "+value); - Assert.assertEquals(((Map<?,?>)value).get("toString"), expected.toString()); - } - - private String get(HttpClient client, String uri, Map<String, String> headers) { - return get(client, URI.create(uri), headers); - } - - private String get(HttpClient client, URI uri, Map<String, String> headers) { - return HttpTool.httpGet(client, uri, headers).getContentAsString(); - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/rest/rest-server/src/test/resources/brooklyn/scanning.catalog.bom ---------------------------------------------------------------------- diff --git a/rest/rest-server/src/test/resources/brooklyn/scanning.catalog.bom b/rest/rest-server/src/test/resources/brooklyn/scanning.catalog.bom deleted file mode 100644 index cddb832..0000000 --- a/rest/rest-server/src/test/resources/brooklyn/scanning.catalog.bom +++ /dev/null @@ -1,19 +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. -# -brooklyn.catalog: - scanJavaAnnotations: true http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/utils/rest-swagger/pom.xml ---------------------------------------------------------------------- diff --git a/utils/rest-swagger/pom.xml b/utils/rest-swagger/pom.xml index 83849f9..3afa7e0 100644 --- a/utils/rest-swagger/pom.xml +++ b/utils/rest-swagger/pom.xml @@ -36,21 +36,11 @@ </parent> <dependencies> - - <!-- ATTN: this moves jersey-server from 1.7 to 1.12 --> - <dependency> - <groupId>com.sun.jersey</groupId> - <artifactId>jersey-servlet</artifactId> - </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> - <dependency> - <groupId>com.google.code.findbugs</groupId> - <artifactId>jsr305</artifactId> - </dependency> - + <dependency> <groupId>org.apache.brooklyn</groupId> <artifactId>brooklyn-utils-common</artifactId> @@ -58,6 +48,11 @@ </dependency> <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + + <dependency> <groupId>org.apache.brooklyn</groupId> <artifactId>brooklyn-test-support</artifactId> <version>${project.version}</version> @@ -86,6 +81,10 @@ <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> </exclusion> + <exclusion> + <groupId>javax.ws.rs</groupId> + <artifactId>jsr311-api</artifactId> + </exclusion> </exclusions> </dependency> <dependency> @@ -151,10 +150,15 @@ io.swagger.jaxrs.*, !* </Export-Package> + <Import-Package> + javax.ws.rs;version="[1.1,2.0]", + javax.ws.rs.core;version="[1.1,2.0]", + javax.ws.rs.ext;version="[1.1,2.0]", + * + </Import-Package> </instructions> </configuration> </plugin> </plugins> </build> - </project> http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/ApiListingResource.java ---------------------------------------------------------------------- diff --git a/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/ApiListingResource.java b/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/ApiListingResource.java index 84c52f8..2d08329 100644 --- a/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/ApiListingResource.java +++ b/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/ApiListingResource.java @@ -15,246 +15,6 @@ */ package org.apache.brooklyn.rest.apidoc; -import com.sun.jersey.spi.container.servlet.WebConfig; -import io.swagger.annotations.ApiOperation; -import io.swagger.config.FilterFactory; -import io.swagger.config.Scanner; -import io.swagger.config.ScannerFactory; -import io.swagger.config.SwaggerConfig; -import io.swagger.core.filter.SpecFilter; -import io.swagger.core.filter.SwaggerSpecFilter; -import io.swagger.jaxrs.Reader; -import io.swagger.jaxrs.config.JaxrsScanner; -import io.swagger.jaxrs.config.ReaderConfigUtils; -import io.swagger.jaxrs.listing.SwaggerSerializers; -import io.swagger.models.Swagger; -import io.swagger.util.Yaml; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Application; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Cookie; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - -import org.apache.brooklyn.util.text.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * ApiListingResource usable within a jersey servlet filter. - * - * Taken from io.swagger:swagger-jaxrs, class - * io.swagger.jaxrs.listing.ApiListingResource, which can only be used within a - * servlet context. We are here using a filter, but jersey has a WebConfig class - * that can substitute ServletConfig and FilterConfig. - * - * @todo Remove when the rest-server is no longer running within a filter (e.g. - * as a standalone OSGi http service) - * - * @author Ciprian Ciubotariu <cheepe...@gmx.net> - */ -public class ApiListingResource { - - static Logger LOGGER = LoggerFactory.getLogger(ApiListingResource.class); - - @Context - ServletContext context; - - boolean initialized = false; - - private static class ServletConfigAdapter implements ServletConfig { - - private final WebConfig webConfig; - - private ServletConfigAdapter(WebConfig webConfig) { - this.webConfig = webConfig; - } - - @Override - public String getServletName() { - return webConfig.getName(); - } - - @Override - public ServletContext getServletContext() { - return webConfig.getServletContext(); - } - - @Override - public String getInitParameter(String name) { - return webConfig.getInitParameter(name); - } - - @Override - public Enumeration<String> getInitParameterNames() { - return webConfig.getInitParameterNames(); - } - - } - - protected synchronized Swagger scan(Application app, WebConfig sc) { - Swagger swagger = null; - Scanner scanner = ScannerFactory.getScanner(); - LOGGER.debug("using scanner " + scanner); - - if (scanner != null) { - SwaggerSerializers.setPrettyPrint(scanner.getPrettyPrint()); - swagger = (Swagger) context.getAttribute("swagger"); - - Set<Class<?>> classes; - if (scanner instanceof JaxrsScanner) { - JaxrsScanner jaxrsScanner = (JaxrsScanner) scanner; - classes = jaxrsScanner.classesFromContext(app, new ServletConfigAdapter(sc)); - } else { - classes = scanner.classes(); - } - if (classes != null) { - Reader reader = new Reader(swagger, ReaderConfigUtils.getReaderConfig(context)); - swagger = reader.read(classes); - if (scanner instanceof SwaggerConfig) { - swagger = ((SwaggerConfig) scanner).configure(swagger); - } else { - SwaggerConfig configurator = (SwaggerConfig) context.getAttribute("reader"); - if (configurator != null) { - LOGGER.debug("configuring swagger with " + configurator); - configurator.configure(swagger); - } else { - LOGGER.debug("no configurator"); - } - } - context.setAttribute("swagger", swagger); - } - } - initialized = true; - return swagger; - } - - private Swagger process( - Application app, - WebConfig sc, - HttpHeaders headers, - UriInfo uriInfo) { - Swagger swagger = (Swagger) context.getAttribute("swagger"); - if (!initialized) { - swagger = scan(app, sc); - } - if (swagger != null) { - SwaggerSpecFilter filterImpl = FilterFactory.getFilter(); - if (filterImpl != null) { - SpecFilter f = new SpecFilter(); - swagger = f.filter(swagger, filterImpl, getQueryParams(uriInfo.getQueryParameters()), getCookies(headers), - getHeaders(headers)); - } - } - return swagger; - } - - @GET - @Produces({MediaType.APPLICATION_JSON, "application/yaml"}) - @ApiOperation(value = "The swagger definition in either JSON or YAML", hidden = true) - @Path("/swagger.{type:json|yaml}") - public Response getListing( - @Context Application app, - @Context WebConfig sc, - @Context HttpHeaders headers, - @Context UriInfo uriInfo, - @PathParam("type") String type) { - if (Strings.isNonBlank(type) && type.trim().equalsIgnoreCase("yaml")) { - return getListingYaml(app, sc, headers, uriInfo); - } else { - return getListingJson(app, sc, headers, uriInfo); - } - } - - @GET - @Produces({MediaType.APPLICATION_JSON}) - @Path("/swagger") - @ApiOperation(value = "The swagger definition in JSON", hidden = true) - public Response getListingJson( - @Context Application app, - @Context WebConfig sc, - @Context HttpHeaders headers, - @Context UriInfo uriInfo) { - Swagger swagger = process(app, sc, headers, uriInfo); - - if (swagger != null) { - return Response.ok().entity(swagger).build(); - } else { - return Response.status(404).build(); - } - } - - @GET - @Produces("application/yaml") - @Path("/swagger") - @ApiOperation(value = "The swagger definition in YAML", hidden = true) - public Response getListingYaml( - @Context Application app, - @Context WebConfig sc, - @Context HttpHeaders headers, - @Context UriInfo uriInfo) { - Swagger swagger = process(app, sc, headers, uriInfo); - try { - if (swagger != null) { - String yaml = Yaml.mapper().writeValueAsString(swagger); - StringBuilder b = new StringBuilder(); - String[] parts = yaml.split("\n"); - for (String part : parts) { - b.append(part); - b.append("\n"); - } - return Response.ok().entity(b.toString()).type("application/yaml").build(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return Response.status(404).build(); - } - - protected Map<String, List<String>> getQueryParams(MultivaluedMap<String, String> params) { - Map<String, List<String>> output = new HashMap<>(); - if (params != null) { - for (String key : params.keySet()) { - List<String> values = params.get(key); - output.put(key, values); - } - } - return output; - } - - protected Map<String, String> getCookies(HttpHeaders headers) { - Map<String, String> output = new HashMap<>(); - if (headers != null) { - for (String key : headers.getCookies().keySet()) { - Cookie cookie = headers.getCookies().get(key); - output.put(key, cookie.getValue()); - } - } - return output; - } - - protected Map<String, List<String>> getHeaders(HttpHeaders headers) { - Map<String, List<String>> output = new HashMap<>(); - if (headers != null) { - for (String key : headers.getRequestHeaders().keySet()) { - List<String> values = headers.getRequestHeaders().get(key); - output.put(key, values); - } - } - return output; - } +public class ApiListingResource extends io.swagger.jaxrs.listing.ApiListingResource { } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6f624c78/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java ---------------------------------------------------------------------- diff --git a/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java b/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java index 96bd821..1bb86b9 100644 --- a/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java +++ b/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java @@ -16,16 +16,18 @@ package org.apache.brooklyn.rest.apidoc; -import io.swagger.annotations.Api; -import io.swagger.jaxrs.config.AbstractScanner; -import io.swagger.jaxrs.config.JaxrsScanner; - import java.util.HashSet; import java.util.Set; import javax.servlet.ServletConfig; import javax.ws.rs.core.Application; +import io.swagger.annotations.Api; +import io.swagger.config.SwaggerConfig; +import io.swagger.jaxrs.config.AbstractScanner; +import io.swagger.jaxrs.config.JaxrsScanner; +import io.swagger.models.Swagger; + /** * Much like DefaultJaxrsScanner, but looks at annotations of ancestors as well. @@ -34,7 +36,7 @@ import javax.ws.rs.core.Application; * that interface will be added as well. * */ -public class RestApiResourceScanner extends AbstractScanner implements JaxrsScanner { +public class RestApiResourceScanner extends AbstractScanner implements JaxrsScanner, SwaggerConfig { private Set<Class<?>> apiClasses = null; @@ -78,4 +80,15 @@ public class RestApiResourceScanner extends AbstractScanner implements JaxrsScan return new HashSet<>(); } + @Override + public Swagger configure(Swagger swagger) { + swagger.setBasePath("/v1"); + return swagger; + } + + @Override + public String getFilterClass() { + return null; + } + }