aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/JsonExceptionMapper.java56
-rw-r--r--policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/RestServer.java2
-rw-r--r--policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/JsonExceptionMapperTest.java50
-rw-r--r--policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java101
4 files changed, 207 insertions, 2 deletions
diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/JsonExceptionMapper.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/JsonExceptionMapper.java
new file mode 100644
index 00000000..9ee72f03
--- /dev/null
+++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/JsonExceptionMapper.java
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.endpoints.http.server;
+
+import com.google.gson.JsonSyntaxException;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import lombok.Getter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Catches JSON exceptions when decoding a REST request and converts them from an HTTP 500
+ * error code to an HTTP 400 error code.
+ */
+@Provider
+@Produces(MediaType.APPLICATION_JSON)
+public class JsonExceptionMapper implements ExceptionMapper<JsonSyntaxException> {
+ private static Logger logger = LoggerFactory.getLogger(JsonExceptionMapper.class);
+
+ @Override
+ public Response toResponse(JsonSyntaxException exception) {
+ logger.warn("invalid JSON request", exception);
+ return Response.status(Response.Status.BAD_REQUEST).entity(new SimpleResponse("Invalid JSON request")).build();
+ }
+
+ @Getter
+ private static class SimpleResponse {
+ private String errorDetails;
+
+ public SimpleResponse(String errorDetails) {
+ this.errorDetails = errorDetails;
+ }
+ }
+}
diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/RestServer.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/RestServer.java
index 597375bf..2368c0b8 100644
--- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/RestServer.java
+++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/RestServer.java
@@ -99,7 +99,7 @@ public class RestServer extends ServiceManagerContainer {
props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_AAF_SUFFIX,
String.valueOf(restServerParameters.isAaf()));
props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER,
- GsonMessageBodyHandler.class.getName());
+ String.join(",", GsonMessageBodyHandler.class.getName(), JsonExceptionMapper.class.getName()));
return props;
}
diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/JsonExceptionMapperTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/JsonExceptionMapperTest.java
new file mode 100644
index 00000000..3efbf85f
--- /dev/null
+++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/JsonExceptionMapperTest.java
@@ -0,0 +1,50 @@
+/*-
+ * ============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 com.google.gson.JsonSyntaxException;
+import javax.ws.rs.core.Response;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.endpoints.http.server.JsonExceptionMapper;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+
+public class JsonExceptionMapperTest {
+ private JsonExceptionMapper mapper;
+
+ @Before
+ public void setUp() {
+ mapper = new JsonExceptionMapper();
+ }
+
+ @Test
+ public void testToResponse() throws CoderException {
+ JsonSyntaxException ex = new JsonSyntaxException("expected exception");
+ Response resp = mapper.toResponse(ex);
+
+ assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), resp.getStatus());
+ assertEquals("{'errorDetails':'Invalid JSON request'}".replace('\'', '"'),
+ new StandardCoder().encode(resp.getEntity()));
+ }
+}
diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java
index 3f671734..fd9b59f7 100644
--- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java
+++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java
@@ -23,15 +23,29 @@ package org.onap.policy.common.endpoints.http.server.test;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
import java.util.Arrays;
+import java.util.Base64;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.Getter;
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -39,12 +53,15 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.onap.policy.common.endpoints.http.server.HttpServletServer;
import org.onap.policy.common.endpoints.http.server.HttpServletServerFactory;
+import org.onap.policy.common.endpoints.http.server.JsonExceptionMapper;
import org.onap.policy.common.endpoints.http.server.RestServer;
import org.onap.policy.common.endpoints.http.server.RestServer.Factory;
import org.onap.policy.common.endpoints.http.server.aaf.AafAuthFilter;
import org.onap.policy.common.endpoints.parameters.RestServerParameters;
import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
import org.onap.policy.common.gson.GsonMessageBodyHandler;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.network.NetworkUtil;
import org.powermock.reflect.Whitebox;
public class RestServerTest {
@@ -58,6 +75,7 @@ public class RestServerTest {
private static final String USER = "my-user";
private static Factory saveFactory;
+ private RestServer realRest;
private RestServer rest;
private HttpServletServer server1;
private HttpServletServer server2;
@@ -101,6 +119,18 @@ public class RestServerTest {
when(params.isHttps()).thenReturn(true);
Whitebox.setInternalState(RestServer.class, FACTORY_FIELD, factory);
+
+ realRest = null;
+ }
+
+ /**
+ * Stops the rest server.
+ */
+ @After
+ public void tearDown() {
+ if (realRest != null) {
+ realRest.stop();
+ }
}
@Test
@@ -181,11 +211,59 @@ public class RestServerTest {
assertEquals(PASS, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_AUTH_PASSWORD_SUFFIX));
assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX));
assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_AAF_SUFFIX));
- assertEquals(GsonMessageBodyHandler.class.getName(),
+ assertEquals(String.join(",", GsonMessageBodyHandler.class.getName(), JsonExceptionMapper.class.getName()),
props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER));
}
@Test
+ public void testInvalidJson() throws Exception {
+ when(params.getHost()).thenReturn("localhost");
+ when(params.getPort()).thenReturn(NetworkUtil.allocPort());
+ when(params.isHttps()).thenReturn(false);
+ when(params.isAaf()).thenReturn(false);
+
+ // use real factory
+ Whitebox.setInternalState(RestServer.class, FACTORY_FIELD, saveFactory);
+
+ realRest = new RestServer(params, null, RealProvider.class) {
+ @Override
+ protected Properties getServerProperties(RestServerParameters restServerParameters, String names) {
+ Properties props = super.getServerProperties(restServerParameters, names);
+
+ String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "."
+ + restServerParameters.getName();
+ props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, "false");
+
+ return props;
+ }
+ };
+
+ realRest.start();
+ assertTrue(NetworkUtil.isTcpPortOpen(params.getHost(), params.getPort(), 100, 100));
+
+ assertEquals(200, roundTrip(new StandardCoder().encode(new MyRequest())));
+ assertEquals(400, roundTrip("{'bogus-json'"));
+ }
+
+ private int roundTrip(String request) throws IOException {
+ URL url = new URL("http://" + params.getHost() + ":" + params.getPort() + "/request");
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setDoInput(true);
+ conn.setDoOutput(true);
+ conn.setRequestMethod("POST");
+ String auth = params.getUserName() + ":" + params.getPassword();
+ conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(auth.getBytes()));
+ conn.setRequestProperty("Content-type", MediaType.APPLICATION_JSON);
+ conn.connect();
+
+ try (PrintWriter wtr = new PrintWriter(conn.getOutputStream())) {
+ wtr.write(request);
+ }
+
+ return conn.getResponseCode();
+ }
+
+ @Test
public void testToString() {
rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
assertNotNull(rest.toString());
@@ -220,4 +298,25 @@ public class RestServerTest {
// do nothing
}
}
+
+ @Path("/")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public static class RealProvider {
+ @POST
+ @Path("/request")
+ public Response decision(MyRequest body) {
+ return Response.status(Response.Status.OK).entity(new MyResponse()).build();
+ }
+ }
+
+ @Getter
+ public static class MyRequest {
+ private String data;
+ }
+
+ @Getter
+ public static class MyResponse {
+ private String text = "hello";
+ }
}