diff options
17 files changed, 1041 insertions, 117 deletions
diff --git a/policy-endpoints/pom.xml b/policy-endpoints/pom.xml index 202c9c2b..4a7f91fe 100644 --- a/policy-endpoints/pom.xml +++ b/policy-endpoints/pom.xml @@ -139,6 +139,11 @@ <artifactId>jersey-common</artifactId> <version>${jersey.version}</version> </dependency> + + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/event/comm/bus/internal/BusTopicParams.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/event/comm/bus/internal/BusTopicParams.java index b752d91c..6e3c2632 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/event/comm/bus/internal/BusTopicParams.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/event/comm/bus/internal/BusTopicParams.java @@ -3,7 +3,7 @@ * policy-endpoints * ================================================================================ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * Modifications Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2018-2019 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,6 +72,7 @@ public class BusTopicParams { private String clientName; private String hostname; private String basePath; + private String serializationProvider; public static TopicParamsBuilder builder() { return new TopicParamsBuilder(); @@ -254,6 +255,10 @@ public class BusTopicParams { return additionalProps != null; } + public String getSerializationProvider() { + return serializationProvider; + } + public static class TopicParamsBuilder { final BusTopicParams params = new BusTopicParams(); @@ -385,6 +390,11 @@ public class BusTopicParams { return this; } + public TopicParamsBuilder serializationProvider(String serializationProvider) { + this.params.serializationProvider = serializationProvider; + return this; + } + } } diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClientFactory.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClientFactory.java index f482eb01..5f4c4c9d 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClientFactory.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClientFactory.java @@ -36,7 +36,7 @@ public interface HttpClientFactory { * Build and http client with the following parameters. */ HttpClient build(BusTopicParams busTopicParams) - throws KeyManagementException, NoSuchAlgorithmException; + throws KeyManagementException, NoSuchAlgorithmException, ClassNotFoundException; /** * Build http client from properties. diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/IndexedHttpClientFactory.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/IndexedHttpClientFactory.java index 9aef09e4..5cc0071e 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/IndexedHttpClientFactory.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/IndexedHttpClientFactory.java @@ -49,7 +49,7 @@ class IndexedHttpClientFactory implements HttpClientFactory { @Override public synchronized HttpClient build(BusTopicParams busTopicParams) - throws KeyManagementException, NoSuchAlgorithmException { + throws KeyManagementException, NoSuchAlgorithmException, ClassNotFoundException { if (clients.containsKey(busTopicParams.getClientName())) { return clients.get(busTopicParams.getClientName()); } @@ -109,6 +109,9 @@ class IndexedHttpClientFactory implements HttpClientFactory { String password = properties.getProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + clientName + PolicyEndPointProperties.PROPERTY_HTTP_AUTH_PASSWORD_SUFFIX); + final String classProv = properties.getProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + + "." + clientName + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER); + String managedString = properties.getProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + clientName + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX); boolean managed = true; @@ -128,6 +131,7 @@ class IndexedHttpClientFactory implements HttpClientFactory { .userName(userName) .password(password) .managed(managed) + .serializationProvider(classProv) .build()); clientList.add(client); } catch (Exception e) { diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java index b55a7bb2..2287486e 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java @@ -22,7 +22,6 @@ package org.onap.policy.common.endpoints.http.client.internal; import com.fasterxml.jackson.annotation.JsonIgnore; - import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -30,7 +29,6 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Map; import java.util.Map.Entry; - import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; @@ -39,7 +37,7 @@ import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation.Builder; import javax.ws.rs.core.Response; - +import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams; import org.onap.policy.common.endpoints.http.client.HttpClient; @@ -48,6 +46,10 @@ import org.slf4j.LoggerFactory; /** * Http Client implementation using a Jersey Client. + * + * <p>Note: the serialization provider will be ignored if the maven artifact, + * <i>jersey-media-json-jackson</i>, is included, regardless of whether it's included + * directly or indirectly. */ public class JerseyClient implements HttpClient { @@ -55,6 +57,9 @@ public class JerseyClient implements HttpClient { * Logger. */ private static Logger logger = LoggerFactory.getLogger(JerseyClient.class); + + protected static final String JERSEY_DEFAULT_SERIALIZATION_PROVIDER = + "com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider"; protected final String name; protected final boolean https; @@ -73,14 +78,17 @@ public class JerseyClient implements HttpClient { /** * Constructor. * - * <p>name the name https is it https or not selfSignedCerts are there self signed certs hostname - * the hostname port port being used basePath base context userName user password password + * <p>name the name https is it https or not selfSignedCerts are there self signed certs + * hostname the hostname port port being used basePath base context userName user + * password password * * @param busTopicParams Input parameters object * @throws KeyManagementException key exception * @throws NoSuchAlgorithmException no algorithm exception + * @throws ClassNotFoundException if the serialization provider cannot be found */ - public JerseyClient(BusTopicParams busTopicParams) throws KeyManagementException, NoSuchAlgorithmException { + public JerseyClient(BusTopicParams busTopicParams) + throws KeyManagementException, NoSuchAlgorithmException, ClassNotFoundException { super(); @@ -147,10 +155,28 @@ public class JerseyClient implements HttpClient { this.client.register(authFeature); } + registerSerProviders(busTopicParams.getSerializationProvider()); + + this.client.property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true"); + this.baseUrl = tmpBaseUrl.append(this.hostname).append(":").append(this.port).append("/") .append((this.basePath == null) ? "" : this.basePath).toString(); } + /** + * Registers the serialization provider(s) with the client. + * + * @param serializationProvider comma-separated list of serialization providers + * @throws ClassNotFoundException if the serialization provider cannot be found + */ + private void registerSerProviders(String serializationProvider) throws ClassNotFoundException { + String providers = (serializationProvider == null || serializationProvider.isEmpty() + ? JERSEY_DEFAULT_SERIALIZATION_PROVIDER : serializationProvider); + for (String prov : providers.split(",")) { + this.client.register(Class.forName(prov)); + } + } + @Override public Response get(String path) { if (path != null && !path.isEmpty()) { diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/HttpServletServer.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/HttpServletServer.java index c4db9fbe..b674e265 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/HttpServletServer.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/HttpServletServer.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,6 +62,13 @@ public interface HttpServletServer extends Startable { boolean isAaf(); /** + * Sets the serialization provider to be used when classes are added to the service. + * + * @param provider the provider to use for message serialization and de-serialization + */ + void setSerializationProvider(String provider); + + /** * Adds a filter at the specified path. * * @param filterPath filter path diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/IndexedHttpServletServerFactory.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/IndexedHttpServletServerFactory.java index ad8ef99c..b2c49eae 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/IndexedHttpServletServerFactory.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/IndexedHttpServletServerFactory.java @@ -129,6 +129,9 @@ class IndexedHttpServletServerFactory implements HttpServletServerFactory { final String restUriPath = properties.getProperty(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + serviceName + PolicyEndPointProperties.PROPERTY_HTTP_REST_URIPATH_SUFFIX); + final String classProv = properties.getProperty(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + + "." + serviceName + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER); + final String managedString = properties.getProperty(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + serviceName + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX); boolean managed = true; @@ -157,9 +160,14 @@ class IndexedHttpServletServerFactory implements HttpServletServerFactory { aaf = Boolean.parseBoolean(aafString); } + HttpServletServer service = build(serviceName, https, hostName, servicePort, contextUriPath, swagger, managed); + if (classProv != null && !classProv.isEmpty()) { + service.setSerializationProvider(classProv); + } + /* authentication method either AAF or HTTP Basic Auth */ if (aaf) { diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/GsonMessageBodyHandler.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/GsonMessageBodyHandler.java new file mode 100644 index 00000000..a29afef4 --- /dev/null +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/GsonMessageBodyHandler.java @@ -0,0 +1,128 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.endpoints.http.server.internal; + +import com.google.gson.Gson; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; + +/** + * Provider that serializes and de-serializes JSON via gson. + * + * <p>Note: <i>jersey</i> will ignore this class if the maven artifact, + * <i>jersey-media-json-jackson</i>, is included, regardless of whether it's included + * directly or indirectly. + */ +@Provider +@Consumes(MediaType.WILDCARD) +@Produces(MediaType.WILDCARD) +public class GsonMessageBodyHandler implements MessageBodyReader<Object>, MessageBodyWriter<Object> { + + /** + * Object to be used to serialize and de-serialize. + */ + private Gson gson; + + /** + * Constructs the object, using a plain Gson object. + */ + public GsonMessageBodyHandler() { + this(new Gson()); + } + + /** + * Constructs the object. + * + * @param gson the Gson object to be used to serialize and de-serialize + */ + public GsonMessageBodyHandler(Gson gson) { + this.gson = gson; + } + + @Override + public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return canHandle(mediaType); + } + + @Override + public long getSize(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return -1; + } + + @Override + public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + + try (OutputStreamWriter writer = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8)) { + Type jsonType = (type.equals(genericType) ? type : genericType); + gson.toJson(object, jsonType, writer); + } + } + + @Override + public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return canHandle(mediaType); + } + + /** + * Determines if this provider can handle the given media type. + * + * @param mediaType the media type of interest + * @return {@code true} if this provider handles the given media type, {@code false} + * otherwise + */ + private boolean canHandle(MediaType mediaType) { + if (mediaType == null) { + return true; + } + + String subtype = mediaType.getSubtype(); + + return "json".equalsIgnoreCase(subtype) || subtype.endsWith("+json") || "javascript".equals(subtype) + || "x-javascript".equals(subtype) || "x-json".equals(subtype); + } + + @Override + public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, String> httpHeaders, InputStream entityStream) + throws IOException, WebApplicationException { + + try (InputStreamReader streamReader = new InputStreamReader(entityStream, StandardCharsets.UTF_8)) { + Type jsonType = (type.equals(genericType) ? type : genericType); + return gson.fromJson(streamReader, jsonType); + } + } +} diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/JettyJerseyServer.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/JettyJerseyServer.java index a97a9bf5..22fc9ac3 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/JettyJerseyServer.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/JettyJerseyServer.java @@ -2,14 +2,14 @@ * ============LICENSE_START======================================================= * policy-endpoints * ================================================================================ - * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed 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. @@ -23,12 +23,23 @@ package org.onap.policy.common.endpoints.http.server.internal; import io.swagger.jersey.config.JerseyJaxrsConfig; import java.util.HashMap; import org.eclipse.jetty.servlet.ServletHolder; +import org.glassfish.jersey.server.ServerProperties; import org.onap.policy.common.utils.network.NetworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * REST Jetty Server that uses Jersey Servlets to support JAX-RS Web Services. + * + * <p>Note: the serialization provider will always be added to the server's class providers, + * as will the swagger providers (assuming swagger has been enabled). This happens whether + * {@link #addServletClass(String, String)} is used or + * {@link #addServletPackage(String, String)} is used. Thus it's possible to have both the + * server's class provider property and the server's package provider property populated. + * + * <p>Also note: the serialization provider will be ignored if the maven artifact, + * <i>jersey-media-json-jackson</i>, is included, regardless of whether it's included + * directly or indirectly. */ public class JettyJerseyServer extends JettyServletServer { @@ -53,26 +64,6 @@ public class JettyJerseyServer extends JettyServletServer { protected static final String SWAGGER_PRETTY_PRINT = "swagger.pretty.print"; /** - * Swagger Packages. - */ - protected static final String SWAGGER_INIT_PACKAGES_PARAM_VALUE = "io.swagger.jaxrs.listing"; - - /** - * Jersey Packages Init Param Name. - */ - protected static final String JERSEY_INIT_PACKAGES_PARAM_NAME = "jersey.config.server.provider.packages"; - - /** - * Jersey Packages Init Param Value. - */ - protected static final String JERSEY_INIT_PACKAGES_PARAM_VALUE = "com.fasterxml.jackson.jaxrs.json"; - - /** - * Jersey Classes Init Param Name. - */ - protected static final String JERSEY_INIT_CLASSNAMES_PARAM_NAME = "jersey.config.server.provider.classnames"; - - /** * Jersey Jackson Classes Init Param Value. */ protected static final String JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE = @@ -99,15 +90,20 @@ public class JettyJerseyServer extends JettyServletServer { protected String swaggerId = null; /** + * The serialization provider to be used when classes are added to the service. + */ + private String classProvider = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE; + + /** * Constructor. - * + * * @param name name * @param https enable https? * @param host host server host * @param port port server port * @param swagger support swagger? * @param contextPath context path - * + * * @throws IllegalArgumentException in invalid arguments are provided */ public JettyJerseyServer(String name, boolean https, String host, int port, String contextPath, boolean swagger) { @@ -145,10 +141,10 @@ public class JettyJerseyServer extends JettyServletServer { /** * Retrieves cached server based on servlet path. - * + * * @param servletPath servlet path * @return the jetty servlet holder - * + * * @throws IllegalArgumentException if invalid arguments are provided */ protected synchronized ServletHolder getServlet(String servletPath) { @@ -176,27 +172,17 @@ public class JettyJerseyServer extends JettyServletServer { ServletHolder jerseyServlet = this.getServlet(servPath); - String initClasses = jerseyServlet.getInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME); - if (initClasses != null && !initClasses.isEmpty()) { - logger.warn("Both packages and classes are used in Jetty+Jersey Configuration: {}", restPackage); - } + initStandardParams(jerseyServlet); - String initPackages = jerseyServlet.getInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME); + String initPackages = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_PACKAGES); if (initPackages == null) { - if (this.swaggerId != null) { - initPackages = - JERSEY_INIT_PACKAGES_PARAM_VALUE + "," + SWAGGER_INIT_PACKAGES_PARAM_VALUE + "," + restPackage; - - jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId); - jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId); - } else { - initPackages = JERSEY_INIT_PACKAGES_PARAM_VALUE + "," + restPackage; - } + initPackages = restPackage; + } else { - initPackages = initPackages + "," + restPackage; + initPackages += "," + restPackage; } - jerseyServlet.setInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME, initPackages); + jerseyServlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES, initPackages); if (logger.isDebugEnabled()) { logger.debug("{}: added REST package: {}", this, jerseyServlet.dump()); @@ -216,33 +202,59 @@ public class JettyJerseyServer extends JettyServletServer { ServletHolder jerseyServlet = this.getServlet(servletPath); - String initPackages = jerseyServlet.getInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME); - if (initPackages != null && !initPackages.isEmpty()) { - logger.warn("Both classes and packages are used in Jetty+Jersey Configuration: {}", restClass); - } + initStandardParams(jerseyServlet); - String initClasses = jerseyServlet.getInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME); + String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES); if (initClasses == null) { - if (this.swaggerId != null) { - initClasses = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE + "," + SWAGGER_INIT_CLASSNAMES_PARAM_VALUE - + "," + restClass; - - jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId); - jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId); - } else { - initClasses = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE + "," + restClass; - } + initClasses = restClass; + } else { - initClasses = initClasses + "," + restClass; + initClasses += "," + restClass; } - jerseyServlet.setInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME, initClasses); + jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses); if (logger.isDebugEnabled()) { logger.debug("{}: added REST class: {}", this, jerseyServlet.dump()); } } + /** + * Adds "standard" parameters to the initParameter set. Sets swagger parameters, if + * specified, and sets the class provider property. This can be invoked multiple + * times, but only the first actually causes any changes to the parameter set. + * + * @param jerseyServlet servlet into which parameters should be added + */ + private void initStandardParams(ServletHolder jerseyServlet) { + String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES); + if (initClasses != null) { + return; + } + + initClasses = classProvider; + + if (this.swaggerId != null) { + initClasses += "," + SWAGGER_INIT_CLASSNAMES_PARAM_VALUE; + + jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId); + jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId); + } + + jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses); + + jerseyServlet.setInitParameter(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true"); + } + + /** + * Note: this must be invoked <i>before</i> {@link #addServletClass(String, String)} + * or {@link #addServletPackage(String, String)}. + */ + @Override + public void setSerializationProvider(String provider) { + classProvider = provider; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/properties/PolicyEndPointProperties.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/properties/PolicyEndPointProperties.java index 883ba7d2..2b1a9a3f 100644 --- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/properties/PolicyEndPointProperties.java +++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/properties/PolicyEndPointProperties.java @@ -94,6 +94,8 @@ public interface PolicyEndPointProperties { String PROPERTY_HTTP_HTTPS_SUFFIX = ".https"; String PROPERTY_HTTP_SWAGGER_SUFFIX = ".swagger"; + String PROPERTY_HTTP_SERIALIZATION_PROVIDER = ".serialization.provider"; + /* HTTP Client Properties */ String PROPERTY_HTTP_CLIENT_SERVICES = "http.client.services"; diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/GsonMessageBodyHandlerTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/GsonMessageBodyHandlerTest.java new file mode 100644 index 00000000..9c6ec80d --- /dev/null +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/GsonMessageBodyHandlerTest.java @@ -0,0 +1,156 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.endpoints.http.server.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import javax.ws.rs.core.MediaType; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.endpoints.http.server.internal.GsonMessageBodyHandler; + +public class GsonMessageBodyHandlerTest { + private static final String GEN_TYPE = "some-type"; + private static final String[] subtypes = {"json", "jSoN", "hello+json", "javascript", "x-javascript", "x-json"}; + + @SuppressWarnings("rawtypes") + private static final Class GEN_CLASS = MyObject.class; + + @SuppressWarnings("unchecked") + private static final Class<Object> CLASS_OBJ = GEN_CLASS; + + private GsonMessageBodyHandler hdlr; + + @Before + public void setUp() { + hdlr = new GsonMessageBodyHandler(); + } + + @Test + public void testIsWriteable() { + // null media type + assertTrue(hdlr.isWriteable(null, null, null, null)); + + for (String subtype : subtypes) { + assertTrue("writeable " + subtype, hdlr.isWriteable(null, null, null, new MediaType(GEN_TYPE, subtype))); + + } + + // the remaining should be FALSE + + // null subtype + assertFalse(hdlr.isWriteable(null, null, null, new MediaType(GEN_TYPE, null))); + + // text subtype + assertFalse(hdlr.isWriteable(null, null, null, MediaType.TEXT_HTML_TYPE)); + } + + @Test + public void testGetSize() { + assertEquals(-1, hdlr.getSize(null, null, null, null, null)); + } + + @Test + public void testWriteTo_testReadFrom() throws Exception { + ByteArrayOutputStream outstr = new ByteArrayOutputStream(); + MyObject obj1 = new MyObject(10); + hdlr.writeTo(obj1, obj1.getClass(), CLASS_OBJ, null, null, null, outstr); + + Object obj2 = hdlr.readFrom(CLASS_OBJ, CLASS_OBJ, null, null, null, + new ByteArrayInputStream(outstr.toByteArray())); + assertEquals(obj1.toString(), obj2.toString()); + } + + @Test + public void testWriteTo_DifferentTypes() throws Exception { + ByteArrayOutputStream outstr = new ByteArrayOutputStream(); + + // use a derived type, but specify the base type when writing + MyObject obj1 = new MyObject(10) {}; + hdlr.writeTo(obj1, obj1.getClass(), CLASS_OBJ, null, null, null, outstr); + + Object obj2 = hdlr.readFrom(CLASS_OBJ, CLASS_OBJ, null, null, null, + new ByteArrayInputStream(outstr.toByteArray())); + assertEquals(obj1.toString(), obj2.toString()); + } + + @Test + public void testIsReadable() { + // null media type + assertTrue(hdlr.isReadable(null, null, null, null)); + + // null subtype + assertFalse(hdlr.isReadable(null, null, null, new MediaType(GEN_TYPE, null))); + + for (String subtype : subtypes) { + assertTrue("readable " + subtype, hdlr.isReadable(null, null, null, new MediaType(GEN_TYPE, subtype))); + + } + + // the remaining should be FALSE + + // null subtype + assertFalse(hdlr.isReadable(null, null, null, new MediaType(GEN_TYPE, null))); + + // text subtype + assertFalse(hdlr.isReadable(null, null, null, MediaType.TEXT_HTML_TYPE)); + } + + @Test + public void testReadFrom_DifferentTypes() throws Exception { + ByteArrayOutputStream outstr = new ByteArrayOutputStream(); + MyObject obj1 = new MyObject(10); + hdlr.writeTo(obj1, obj1.getClass(), CLASS_OBJ, null, null, null, outstr); + + // use a derived type, but specify the base type when reading + @SuppressWarnings("rawtypes") + Class clazz = new MyObject() {}.getClass(); + + @SuppressWarnings("unchecked") + Class<Object> objclazz = clazz; + + Object obj2 = hdlr.readFrom(objclazz, CLASS_OBJ, null, null, null, + new ByteArrayInputStream(outstr.toByteArray())); + assertEquals(obj1.toString(), obj2.toString()); + } + + public static class MyObject { + private int id; + + public MyObject() { + super(); + } + + public MyObject(int id) { + this.id = id; + } + + @Override + public String toString() { + return "MyObject [id=" + id + "]"; + } + } + +} diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java index f15d68e9..1f1f117e 100644 --- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java @@ -22,6 +22,8 @@ package org.onap.policy.common.endpoints.http.server.test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.security.KeyManagementException; @@ -34,6 +36,7 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams; @@ -53,7 +56,7 @@ public class HttpClientTest { * @throws IOException can have an IO exception */ @BeforeClass - public static void setUp() throws InterruptedException, IOException { + public static void setUpBeforeClass() throws InterruptedException, IOException { /* echo server - http + no auth */ final HttpServletServer echoServerNoAuth = @@ -113,10 +116,21 @@ public class HttpClientTest { } /** + * Clear https clients and reset providers. + */ + @Before + public void setUp() { + HttpClient.factory.destroy(); + + MyGsonProvider.resetSome(); + MyJacksonProvider.resetSome(); + } + + /** * After the class is created method. */ @AfterClass - public static void tearDown() { + public static void tearDownAfterClass() { HttpServletServer.factory.destroy(); HttpClient.factory.destroy(); @@ -227,6 +241,44 @@ public class HttpClientTest { } @Test + public void testHttpPutAuthClient_JacksonProvider() throws Exception { + final HttpClient client = HttpClient.factory.build(BusTopicParams.builder().clientName("testHttpAuthClient") + .useHttps(true).allowSelfSignedCerts(true).hostname("localhost").port(6667) + .basePath("junit/echo").userName("x").password("y").managed(true) + .serializationProvider(MyJacksonProvider.class.getCanonicalName()).build()); + + Entity<MyEntity> entity = Entity.entity(new MyEntity("myValue"), MediaType.APPLICATION_JSON); + final Response response = client.put("hello", entity, Collections.emptyMap()); + final String body = HttpClient.getBody(response, String.class); + + assertEquals(200, response.getStatus()); + assertEquals("PUT:hello:{myParameter=myValue}", body); + + assertTrue(MyJacksonProvider.hasWrittenSome()); + + assertFalse(MyGsonProvider.hasWrittenSome()); + } + + @Test + public void testHttpPutAuthClient_GsonProvider() throws Exception { + final HttpClient client = HttpClient.factory.build(BusTopicParams.builder().clientName("testHttpAuthClient") + .useHttps(true).allowSelfSignedCerts(true).hostname("localhost").port(6667) + .basePath("junit/echo").userName("x").password("y").managed(true) + .serializationProvider(MyGsonProvider.class.getCanonicalName()).build()); + + Entity<MyEntity> entity = Entity.entity(new MyEntity("myValue"), MediaType.APPLICATION_JSON); + final Response response = client.put("hello", entity, Collections.emptyMap()); + final String body = HttpClient.getBody(response, String.class); + + assertEquals(200, response.getStatus()); + assertEquals("PUT:hello:{myParameter=myValue}", body); + + assertTrue(MyGsonProvider.hasWrittenSome()); + + assertFalse(MyJacksonProvider.hasWrittenSome()); + } + + @Test public void testHttpAuthClient401() throws Exception { final HttpClient client = getNoAuthHttpClient("testHttpAuthClient401", true, 6667); @@ -321,16 +373,89 @@ public class HttpClientTest { final HttpClient clientPdp = HttpClient.factory.get("PDP"); final Response response2 = clientPdp.get("test"); assertEquals(500, response2.getStatus()); + + assertFalse(MyJacksonProvider.hasWrittenSome()); + assertFalse(MyGsonProvider.hasWrittenSome()); + } + + @Test + public void testHttpAuthClientProps_MixedProviders() throws Exception { + final Properties httpProperties = new Properties(); + + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES, "GSON,JACKSON"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "GSON" + + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX, "localhost"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "GSON" + + PolicyEndPointProperties.PROPERTY_HTTP_PORT_SUFFIX, "6666"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "GSON" + + PolicyEndPointProperties.PROPERTY_HTTP_URL_SUFFIX, "junit/echo"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "GSON" + + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX, "false"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "GSON" + + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "true"); + httpProperties.setProperty( + PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "GSON" + + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER, + MyGsonProvider.class.getCanonicalName()); + + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "JACKSON" + + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX, "localhost"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "JACKSON" + + PolicyEndPointProperties.PROPERTY_HTTP_PORT_SUFFIX, "6666"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "JACKSON" + + PolicyEndPointProperties.PROPERTY_HTTP_URL_SUFFIX, "junit/echo"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "JACKSON" + + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX, "false"); + httpProperties.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "JACKSON" + + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "true"); + httpProperties.setProperty( + PolicyEndPointProperties.PROPERTY_HTTP_CLIENT_SERVICES + "." + "JACKSON" + + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER, + MyJacksonProvider.class.getCanonicalName()); + + final List<HttpClient> clients = HttpClient.factory.build(httpProperties); + assertEquals(2, clients.size()); + + Entity<MyEntity> entity = Entity.entity(new MyEntity("myValue"), MediaType.APPLICATION_JSON); + + // use gson client + MyGsonProvider.resetSome(); + MyJacksonProvider.resetSome(); + HttpClient client = HttpClient.factory.get("GSON"); + + Response response = client.put("hello", entity, Collections.emptyMap()); + String body = HttpClient.getBody(response, String.class); + + assertEquals(200, response.getStatus()); + assertEquals("PUT:hello:{myParameter=myValue}", body); + + assertTrue(MyGsonProvider.hasWrittenSome()); + assertFalse(MyJacksonProvider.hasWrittenSome()); + + // use jackson client + MyGsonProvider.resetSome(); + MyJacksonProvider.resetSome(); + client = HttpClient.factory.get("JACKSON"); + + response = client.put("hello", entity, Collections.emptyMap()); + body = HttpClient.getBody(response, String.class); + + assertEquals(200, response.getStatus()); + assertEquals("PUT:hello:{myParameter=myValue}", body); + + assertTrue(MyJacksonProvider.hasWrittenSome()); + assertFalse(MyGsonProvider.hasWrittenSome()); } - private HttpClient getAuthHttpClient() throws KeyManagementException, NoSuchAlgorithmException { + private HttpClient getAuthHttpClient() + throws KeyManagementException, NoSuchAlgorithmException, ClassNotFoundException { return HttpClient.factory.build(BusTopicParams.builder().clientName("testHttpAuthClient") .useHttps(true).allowSelfSignedCerts(true).hostname("localhost").port(6667).basePath("junit/echo") .userName("x").password("y").managed(true).build()); } private HttpClient getNoAuthHttpClient(String clientName, boolean https, int port) - throws KeyManagementException, NoSuchAlgorithmException { + throws KeyManagementException, NoSuchAlgorithmException, ClassNotFoundException { return HttpClient.factory.build(BusTopicParams.builder().clientName(clientName) .useHttps(https).allowSelfSignedCerts(https).hostname("localhost").port(port).basePath("junit/echo") .userName(null).password(null).managed(true).build()); diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java index 084847ce..3d80793e 100644 --- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java @@ -2,14 +2,14 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed 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. @@ -24,14 +24,19 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import com.google.gson.Gson; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ConnectException; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; import java.util.UUID; - +import org.apache.commons.io.IOUtils; +import org.junit.AfterClass; +import org.junit.Before; import org.junit.Test; import org.onap.policy.common.endpoints.http.server.HttpServletServer; import org.slf4j.Logger; @@ -47,69 +52,251 @@ public class HttpServerTest { */ private static Logger logger = LoggerFactory.getLogger(HttpServerTest.class); + private static final String LOCALHOST_PREFIX = "http://localhost:"; + + private static final Gson gson = new Gson(); + + /** + * Server port. Incremented by 10 with each test. + */ + private static int port = 5608; + + private String portUrl; + + /** + * Increments the port number, clears the servers, and resets the providers. + */ + @Before + public void setUp() { + port += 10; + portUrl = LOCALHOST_PREFIX + port; + + HttpServletServer.factory.destroy(); + + MyJacksonProvider.resetSome(); + MyGsonProvider.resetSome(); + } + + @AfterClass + public static void tearDownAfterClass() { + HttpServletServer.factory.destroy(); + } + + @Test + public void testDefaultPackageServer() throws Exception { + logger.info("-- testDefaultPackageServer() --"); + + HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", port, "/", false, true); + server.addServletPackage("/*", this.getClass().getPackage().getName()); + server.addFilterClass("/*", TestFilter.class.getCanonicalName()); + server.waitedStart(5000); + + assertTrue(HttpServletServer.factory.get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText("some text"); + String reqText = gson.toJson(request); + + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/full/request", reqText); + assertEquals(reqText, response); + } + + @Test + public void testJacksonPackageServer() throws Exception { + logger.info("-- testJacksonPackageServer() --"); + + HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", port, "/", false, true); + + server.setSerializationProvider(MyJacksonProvider.class.getCanonicalName()); + server.addServletPackage("/*", this.getClass().getPackage().getName()); + server.addFilterClass("/*", TestFilter.class.getCanonicalName()); + server.waitedStart(5000); + + assertTrue(HttpServletServer.factory.get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText("some text"); + String reqText = gson.toJson(request); + + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/full/request", reqText); + assertEquals(reqText, response); + + assertTrue(MyJacksonProvider.hasReadSome()); + assertTrue(MyJacksonProvider.hasWrittenSome()); + + assertFalse(MyGsonProvider.hasReadSome()); + assertFalse(MyGsonProvider.hasWrittenSome()); + } + + @Test + public void testGsonPackageServer() throws Exception { + logger.info("-- testGsonPackageServer() --"); + + HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", port, "/", false, true); + + server.setSerializationProvider(MyGsonProvider.class.getCanonicalName()); + server.addServletPackage("/*", this.getClass().getPackage().getName()); + server.addFilterClass("/*", TestFilter.class.getCanonicalName()); + server.waitedStart(5000); + + assertTrue(HttpServletServer.factory.get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText("some text"); + String reqText = gson.toJson(request); + + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/full/request", reqText); + assertEquals(reqText, response); + + assertTrue(MyGsonProvider.hasReadSome()); + assertTrue(MyGsonProvider.hasWrittenSome()); + + assertFalse(MyJacksonProvider.hasReadSome()); + assertFalse(MyJacksonProvider.hasWrittenSome()); + } + + @Test + public void testDefaultClassServer() throws Exception { + logger.info("-- testDefaultClassServer() --"); + + HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", port, "/", false, true); + server.addServletClass("/*", RestEchoService.class.getCanonicalName()); + server.addFilterClass("/*", TestFilter.class.getCanonicalName()); + server.waitedStart(5000); + + assertTrue(HttpServletServer.factory.get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText("some text"); + String reqText = gson.toJson(request); + + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/full/request", reqText); + assertEquals(reqText, response); + } + + @Test + public void testJacksonClassServer() throws Exception { + logger.info("-- testJacksonClassServer() --"); + + HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", port, "/", false, true); + server.setSerializationProvider(MyJacksonProvider.class.getCanonicalName()); + server.addServletClass("/*", RestEchoService.class.getCanonicalName()); + server.addFilterClass("/*", TestFilter.class.getCanonicalName()); + server.waitedStart(5000); + + assertTrue(HttpServletServer.factory.get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText("some text"); + String reqText = gson.toJson(request); + + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/full/request", reqText); + assertEquals(reqText, response); + + assertTrue(MyJacksonProvider.hasReadSome()); + assertTrue(MyJacksonProvider.hasWrittenSome()); + + assertFalse(MyGsonProvider.hasReadSome()); + assertFalse(MyGsonProvider.hasWrittenSome()); + } + + @Test + public void testGsonClassServer() throws Exception { + logger.info("-- testGsonClassServer() --"); + + HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", port, "/", false, true); + server.setSerializationProvider(MyGsonProvider.class.getCanonicalName()); + server.addServletClass("/*", RestEchoService.class.getCanonicalName()); + server.addFilterClass("/*", TestFilter.class.getCanonicalName()); + server.waitedStart(5000); + + assertTrue(HttpServletServer.factory.get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText("some text"); + String reqText = gson.toJson(request); + + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/full/request", reqText); + assertEquals(reqText, response); + + assertTrue(MyGsonProvider.hasReadSome()); + assertTrue(MyGsonProvider.hasWrittenSome()); + + assertFalse(MyJacksonProvider.hasReadSome()); + assertFalse(MyJacksonProvider.hasWrittenSome()); + } + @Test public void testSingleServer() throws Exception { logger.info("-- testSingleServer() --"); - HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", 5678, "/", false, true); + HttpServletServer server = HttpServletServer.factory.build("echo", "localhost", port, "/", false, true); server.addServletPackage("/*", this.getClass().getPackage().getName()); server.addFilterClass("/*", TestFilter.class.getCanonicalName()); server.waitedStart(5000); - assertTrue(HttpServletServer.factory.get(5678).isAlive()); - assertFalse(HttpServletServer.factory.get(5678).isAaf()); + assertTrue(HttpServletServer.factory.get(port).isAlive()); + assertFalse(HttpServletServer.factory.get(port).isAaf()); - String response = http(HttpServletServer.factory.get(5678), "http://localhost:5678/junit/echo/hello"); + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/hello"); assertTrue("hello".equals(response)); response = null; try { - response = http(HttpServletServer.factory.get(5678), "http://localhost:5678/swagger.json"); + response = http(HttpServletServer.factory.get(port), portUrl + "/swagger.json"); } catch (IOException e) { // Expected } assertTrue(response == null); - response = http(HttpServletServer.factory.get(5678), "http://localhost:5678/junit/echo/hello?block=true"); + response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/hello?block=true"); assertEquals("FILTERED", response); - assertTrue(HttpServletServer.factory.get(5678).isAlive()); - assertTrue(HttpServletServer.factory.inventory().size() == 1); + assertTrue(HttpServletServer.factory.get(port).isAlive()); + assertEquals(1, HttpServletServer.factory.inventory().size()); server.setAafAuthentication("/*"); - assertTrue(HttpServletServer.factory.get(5678).isAaf()); + assertTrue(HttpServletServer.factory.get(port).isAaf()); - HttpServletServer.factory.destroy(5678); - assertTrue(HttpServletServer.factory.inventory().size() == 0); + HttpServletServer.factory.destroy(port); + assertEquals(0, HttpServletServer.factory.inventory().size()); } @Test public void testMultipleServers() throws Exception { logger.info("-- testMultipleServers() --"); - HttpServletServer server1 = HttpServletServer.factory.build("echo-1", false,"localhost", 5688, "/", true, true); + HttpServletServer server1 = HttpServletServer.factory.build("echo-1", false,"localhost", port, "/", true, true); server1.addServletPackage("/*", this.getClass().getPackage().getName()); server1.waitedStart(5000); - HttpServletServer server2 = HttpServletServer.factory.build("echo-2", "localhost", 5689, "/", false, true); + int port2 = port + 1; + + HttpServletServer server2 = HttpServletServer.factory.build("echo-2", "localhost", port2, "/", false, true); server2.addServletPackage("/*", this.getClass().getPackage().getName()); server2.waitedStart(5000); - assertTrue(HttpServletServer.factory.get(5688).isAlive()); - assertTrue(HttpServletServer.factory.get(5689).isAlive()); + assertTrue(HttpServletServer.factory.get(port).isAlive()); + assertTrue(HttpServletServer.factory.get(port2).isAlive()); - String response = http(HttpServletServer.factory.get(5688), "http://localhost:5688/junit/echo/hello"); + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/hello"); assertTrue("hello".equals(response)); - response = http(HttpServletServer.factory.get(5688), "http://localhost:5688/swagger.json"); + response = http(HttpServletServer.factory.get(port), portUrl + "/swagger.json"); assertTrue(response != null); - response = http(HttpServletServer.factory.get(5689), "http://localhost:5689/junit/echo/hello"); + response = http(HttpServletServer.factory.get(port2), LOCALHOST_PREFIX + port2 + "/junit/echo/hello"); assertTrue("hello".equals(response)); response = null; try { - response = http(HttpServletServer.factory.get(5689), "http://localhost:5689/swagger.json"); + response = http(HttpServletServer.factory.get(port2), LOCALHOST_PREFIX + port2 + "/swagger.json"); } catch (IOException e) { // Expected } @@ -125,16 +312,16 @@ public class HttpServerTest { String randomName = UUID.randomUUID().toString(); - HttpServletServer server = HttpServletServer.factory.build(randomName, "localhost", 5668, "/", false, true); + HttpServletServer server = HttpServletServer.factory.build(randomName, "localhost", port, "/", false, true); server.addServletPackage("/*", this.getClass().getPackage().getName()); server.waitedStart(5000); - assertTrue(HttpServletServer.factory.get(5668).isAlive()); + assertTrue(HttpServletServer.factory.get(port).isAlive()); - String response = http(HttpServletServer.factory.get(5668), "http://localhost:5668/junit/echo/hello"); + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/hello"); assertTrue("hello".equals(response)); - response = http(HttpServletServer.factory.get(5668), "http://localhost:5668/junit/endpoints/http/servers"); + response = http(HttpServletServer.factory.get(port), portUrl + "/junit/endpoints/http/servers"); assertTrue(response.contains(randomName)); HttpServletServer.factory.destroy(); @@ -146,13 +333,13 @@ public class HttpServerTest { logger.info("-- testServiceClass() --"); String randomName = UUID.randomUUID().toString(); - HttpServletServer server = HttpServletServer.factory.build(randomName, "localhost", 5658, "/", false, true); + HttpServletServer server = HttpServletServer.factory.build(randomName, "localhost", port, "/", false, true); server.addServletClass("/*", RestEchoService.class.getCanonicalName()); server.waitedStart(5000); - assertTrue(HttpServletServer.factory.get(5658).isAlive()); + assertTrue(HttpServletServer.factory.get(port).isAlive()); - String response = http(HttpServletServer.factory.get(5658), "http://localhost:5658/junit/echo/hello"); + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/hello"); assertTrue("hello".equals(response)); HttpServletServer.factory.destroy(); @@ -165,17 +352,17 @@ public class HttpServerTest { String randomName = UUID.randomUUID().toString(); - HttpServletServer server = HttpServletServer.factory.build(randomName, "localhost", 5648, "/", false, true); + HttpServletServer server = HttpServletServer.factory.build(randomName, "localhost", port, "/", false, true); server.addServletClass("/*", RestEchoService.class.getCanonicalName()); server.addServletClass("/*", RestEndpoints.class.getCanonicalName()); server.waitedStart(5000); - assertTrue(HttpServletServer.factory.get(5648).isAlive()); + assertTrue(HttpServletServer.factory.get(port).isAlive()); - String response = http(HttpServletServer.factory.get(5648), "http://localhost:5648/junit/echo/hello"); + String response = http(HttpServletServer.factory.get(port), portUrl + "/junit/echo/hello"); assertTrue("hello".equals(response)); - response = http(HttpServletServer.factory.get(5648), "http://localhost:5648/junit/endpoints/http/servers"); + response = http(HttpServletServer.factory.get(port), portUrl + "/junit/endpoints/http/servers"); assertTrue(response.contains(randomName)); HttpServletServer.factory.destroy(); @@ -184,7 +371,7 @@ public class HttpServerTest { /** * performs an http request. - * + * * @throws MalformedURLException make sure URL is good * @throws IOException thrown is IO exception occurs * @throws InterruptedException thrown if thread interrupted occurs @@ -197,7 +384,8 @@ public class HttpServerTest { int maxNumberRetries = 5; while (numRetries <= maxNumberRetries) { try { - response = response(url); + URLConnection conn = url.openConnection(); + response = response(conn); break; } catch (ConnectException e) { logger.warn("http server {} @ {} ({}) - cannot connect yet ..", server, urlString, numRetries, e); @@ -212,15 +400,50 @@ public class HttpServerTest { } /** + * Performs an http request. + * + * @throws MalformedURLException make sure URL is good + * @throws IOException thrown is IO exception occurs + * @throws InterruptedException thrown if thread interrupted occurs + */ + protected String http(HttpServletServer server, String urlString, String post) + throws MalformedURLException, IOException, InterruptedException { + URL url = new URL(urlString); + String response = null; + int numRetries = 1; + int maxNumberRetries = 5; + while (numRetries <= maxNumberRetries) { + try { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", "application/json"); + IOUtils.write(post, conn.getOutputStream()); + response = response(conn); + break; + } catch (ConnectException e) { + logger.warn("http server {} @ {} ({}) - cannot connect yet ..", server, urlString, numRetries, e); + numRetries++; + Thread.sleep(10000L); + } catch (Exception e) { + logger.error("http error", e); + throw e; + } + } + + return response; + } + + /** * gets http response. - * - * @param url url - * + * + * @param conn connection from which to read + * * @throws IOException if an I/O error occurs */ - protected String response(URL url) throws IOException { + protected String response(URLConnection conn) throws IOException { String response = ""; - try (BufferedReader ioReader = new BufferedReader(new InputStreamReader(url.openStream()))) { + try (BufferedReader ioReader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { String line; while ((line = ioReader.readLine()) != null) { response += line; @@ -229,6 +452,4 @@ public class HttpServerTest { return response; } - - } diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyGsonProvider.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyGsonProvider.java new file mode 100644 index 00000000..037f6c6f --- /dev/null +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyGsonProvider.java @@ -0,0 +1,76 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.endpoints.http.server.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import org.onap.policy.common.endpoints.http.server.internal.GsonMessageBodyHandler; + +/** + * GsonMessageBodyHandler that tracks activities. + */ +public class MyGsonProvider extends GsonMessageBodyHandler { + private static boolean readSome = false; + private static boolean wroteSome = false; + + /** + * Constructs the object and resets the variables to indicate that no activity has + * occurred yet. + */ + public MyGsonProvider() { + super(); + } + + @Override + public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException { + + readSome = true; + return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream); + } + + @Override + public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException { + + wroteSome = true; + super.writeTo(object, type, genericType, annotations, mediaType, httpHeaders, entityStream); + } + + public static boolean hasReadSome() { + return readSome; + } + + public static boolean hasWrittenSome() { + return wroteSome; + } + + public static void resetSome() { + MyGsonProvider.readSome = false; + MyGsonProvider.wroteSome = false; + } + +} diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyJacksonProvider.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyJacksonProvider.java new file mode 100644 index 00000000..07062451 --- /dev/null +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyJacksonProvider.java @@ -0,0 +1,76 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.endpoints.http.server.test; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; + +/** + * JacksonJsonProvider that tracks activities. + */ +public class MyJacksonProvider extends JacksonJsonProvider { + private static boolean readSome = false; + private static boolean wroteSome = false; + + /** + * Constructs the object and resets the variables to indicate that no activity has + * occurred yet. + */ + public MyJacksonProvider() { + super(); + } + + @Override + public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException { + + readSome = true; + return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream); + } + + @Override + public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException { + + wroteSome = true; + super.writeTo(object, type, genericType, annotations, mediaType, httpHeaders, entityStream); + } + + public static boolean hasReadSome() { + return readSome; + } + + public static boolean hasWrittenSome() { + return wroteSome; + } + + public static void resetSome() { + MyJacksonProvider.readSome = false; + MyJacksonProvider.wroteSome = false; + } + +} diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoReqResp.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoReqResp.java new file mode 100644 index 00000000..5778eeeb --- /dev/null +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoReqResp.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.endpoints.http.server.test; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; + +/** + * "ECHO" request and response supporting serialization and de-serialization via + * both jackson and gson. + */ +public class RestEchoReqResp { + @JsonProperty("reqId") + @SerializedName("reqId") + private int requestId; + + @JsonProperty("textValue") + @SerializedName("textValue") + private String text; + + public int getRequestId() { + return requestId; + } + + public void setRequestId(int requestId) { + this.requestId = requestId; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + @Override + public String toString() { + return "RestEchoReqResp [requestId=" + requestId + ", text=" + text + "]"; + } +} diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java index 5d9b14d3..9db1053f 100644 --- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java @@ -22,7 +22,6 @@ package org.onap.policy.common.endpoints.http.server.test; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; - import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -31,6 +30,8 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; @Api(value = "echo") @@ -54,6 +55,14 @@ public class RestEchoService { } @POST + @Path("/full/request") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "echoes back the request structure", response = RestEchoReqResp.class) + public Response echoFullyPost(RestEchoReqResp reqResp) { + return Response.status(Status.OK).entity(reqResp).build(); + } + + @POST @Path("{word}") @Produces(MediaType.TEXT_PLAIN) @ApiOperation(value = "echoes back whatever received") |