Skip to content

Commit

Permalink
added support for an endpoint content-type for all services. possible…
Browse files Browse the repository at this point in the history
… values are json, xml. the purpose is so that we can respond with either XML or JSON as appropriate when we detect a policy failure
  • Loading branch information
EricWittmann committed Nov 16, 2015
1 parent fd56922 commit 0c57589
Show file tree
Hide file tree
Showing 32 changed files with 389 additions and 37 deletions.
Expand Up @@ -364,6 +364,7 @@
<column name="definition_type" type="VARCHAR(255)"/>
<column name="endpoint" type="VARCHAR(255)"/>
<column name="endpoint_type" type="VARCHAR(255)"/>
<column name="endpoint_ct" type="VARCHAR(255)"/>
<column name="modified_by" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
Expand Down
Expand Up @@ -62,7 +62,7 @@ CREATE TABLE roles (id VARCHAR(255) NOT NULL, auto_grant BOOLEAN, created_by VAR
CREATE TABLE service_defs (id BIGINT NOT NULL, data BLOB, service_version_id BIGINT);

-- Changeset c:/Users/ewittman/git/apiman/apiman/distro/ddl/src/main/liquibase/current/010-apiman-manager-api.db.tables.changelog.xml::1436469846462-18::apiman (generated)
CREATE TABLE service_versions (id BIGINT NOT NULL, created_by VARCHAR(255) NOT NULL, created_on TIMESTAMP NOT NULL, definition_type VARCHAR(255), endpoint VARCHAR(255), endpoint_type VARCHAR(255), modified_by VARCHAR(255) NOT NULL, modified_on TIMESTAMP NOT NULL, public_service BOOLEAN NOT NULL, published_on TIMESTAMP, retired_on TIMESTAMP, status VARCHAR(255) NOT NULL, version VARCHAR(255), service_id VARCHAR(255), service_org_id VARCHAR(255));
CREATE TABLE service_versions (id BIGINT NOT NULL, created_by VARCHAR(255) NOT NULL, created_on TIMESTAMP NOT NULL, definition_type VARCHAR(255), endpoint VARCHAR(255), endpoint_type VARCHAR(255), endpoint_ct VARCHAR(255), modified_by VARCHAR(255) NOT NULL, modified_on TIMESTAMP NOT NULL, public_service BOOLEAN NOT NULL, published_on TIMESTAMP, retired_on TIMESTAMP, status VARCHAR(255) NOT NULL, version VARCHAR(255), service_id VARCHAR(255), service_org_id VARCHAR(255));

-- Changeset c:/Users/ewittman/git/apiman/apiman/distro/ddl/src/main/liquibase/current/010-apiman-manager-api.db.tables.changelog.xml::1436469846462-19::apiman (generated)
CREATE TABLE services (id VARCHAR(255) NOT NULL, created_by VARCHAR(255) NOT NULL, created_on TIMESTAMP NOT NULL, description VARCHAR(512), name VARCHAR(255) NOT NULL, organization_id VARCHAR(255) NOT NULL, num_published INT);
Expand Down
Expand Up @@ -64,7 +64,7 @@ CREATE TABLE roles (id VARCHAR(255) NOT NULL, auto_grant BIT(1) NULL, created_by
CREATE TABLE service_defs (id BIGINT NOT NULL, data LONGBLOB NULL, service_version_id BIGINT NULL);

-- Changeset c:/Users/ewittman/git/apiman/apiman/distro/ddl/src/main/liquibase/current/010-apiman-manager-api.db.tables.changelog.xml::1436469846462-18::apiman (generated)
CREATE TABLE service_versions (id BIGINT NOT NULL, created_by VARCHAR(255) NOT NULL, created_on datetime NOT NULL, definition_type VARCHAR(255) NULL, endpoint VARCHAR(255) NULL, endpoint_type VARCHAR(255) NULL, modified_by VARCHAR(255) NOT NULL, modified_on datetime NOT NULL, public_service BIT(1) NOT NULL, published_on datetime NULL, retired_on datetime NULL, status VARCHAR(255) NOT NULL, version VARCHAR(255) NULL, service_id VARCHAR(255) NULL, service_org_id VARCHAR(255) NULL);
CREATE TABLE service_versions (id BIGINT NOT NULL, created_by VARCHAR(255) NOT NULL, created_on timestamp NOT NULL, definition_type VARCHAR(255) NULL, endpoint VARCHAR(255) NULL, endpoint_type VARCHAR(255) NULL, endpoint_ct VARCHAR(255) NULL, modified_by VARCHAR(255) NOT NULL, modified_on timestamp NOT NULL, public_service BIT(1) NOT NULL, published_on timestamp NULL, retired_on timestamp NULL, status VARCHAR(255) NOT NULL, version VARCHAR(255) NULL, service_id VARCHAR(255) NULL, service_org_id VARCHAR(255) NULL);

-- Changeset c:/Users/ewittman/git/apiman/apiman/distro/ddl/src/main/liquibase/current/010-apiman-manager-api.db.tables.changelog.xml::1436469846462-19::apiman (generated)
CREATE TABLE services (id VARCHAR(255) NOT NULL, created_by VARCHAR(255) NOT NULL, created_on timestamp NOT NULL, description VARCHAR(512) NULL, name VARCHAR(255) NOT NULL, organization_id VARCHAR(255) NOT NULL, num_published INT NULL);
Expand Down
Expand Up @@ -62,7 +62,7 @@ CREATE TABLE roles (id VARCHAR(255) NOT NULL, auto_grant BOOLEAN, created_by VAR
CREATE TABLE service_defs (id BIGINT NOT NULL, data OID, service_version_id BIGINT);

-- Changeset c:/Users/ewittman/git/apiman/apiman/distro/ddl/src/main/liquibase/current/010-apiman-manager-api.db.tables.changelog.xml::1436469846462-18::apiman (generated)
CREATE TABLE service_versions (id BIGINT NOT NULL, created_by VARCHAR(255) NOT NULL, created_on TIMESTAMP WITHOUT TIME ZONE NOT NULL, definition_type VARCHAR(255), endpoint VARCHAR(255), endpoint_type VARCHAR(255), modified_by VARCHAR(255) NOT NULL, modified_on TIMESTAMP WITHOUT TIME ZONE NOT NULL, public_service BOOLEAN NOT NULL, published_on TIMESTAMP WITHOUT TIME ZONE, retired_on TIMESTAMP WITHOUT TIME ZONE, status VARCHAR(255) NOT NULL, version VARCHAR(255), service_id VARCHAR(255), service_org_id VARCHAR(255));
CREATE TABLE service_versions (id BIGINT NOT NULL, created_by VARCHAR(255) NOT NULL, created_on TIMESTAMP WITHOUT TIME ZONE NOT NULL, definition_type VARCHAR(255), endpoint VARCHAR(255), endpoint_type VARCHAR(255), endpoint_ct VARCHAR(255), modified_by VARCHAR(255) NOT NULL, modified_on TIMESTAMP WITHOUT TIME ZONE NOT NULL, public_service BOOLEAN NOT NULL, published_on TIMESTAMP WITHOUT TIME ZONE, retired_on TIMESTAMP WITHOUT TIME ZONE, status VARCHAR(255) NOT NULL, version VARCHAR(255), service_id VARCHAR(255), service_org_id VARCHAR(255));

-- Changeset c:/Users/ewittman/git/apiman/apiman/distro/ddl/src/main/liquibase/current/010-apiman-manager-api.db.tables.changelog.xml::1436469846462-19::apiman (generated)
CREATE TABLE services (id VARCHAR(255) NOT NULL, created_by VARCHAR(255) NOT NULL, created_on TIMESTAMP WITHOUT TIME ZONE NOT NULL, description VARCHAR(512), name VARCHAR(255) NOT NULL, organization_id VARCHAR(255) NOT NULL, num_published INT);
Expand Down
Expand Up @@ -19,11 +19,14 @@
import java.io.Serializable;
import java.io.StringWriter;

import javax.xml.bind.annotation.XmlRootElement;

/**
* Models an error from the engine.
*
* @author Marc Savy <msavy@redhat.com>
*/
@XmlRootElement
public class EngineErrorResponse implements Serializable {

private static final long serialVersionUID = 8881390951647532958L;
Expand Down
Expand Up @@ -19,11 +19,14 @@
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.XmlRootElement;

/**
* Models a policy failure.
*
* @author Marc Savy <msavy@redhat.com>
*/
@XmlRootElement
public class PolicyFailure implements Serializable {

private static final long serialVersionUID = -4698896399383125062L;
Expand Down
Expand Up @@ -36,8 +36,9 @@ public class Service implements Serializable {
private String organizationId;
private String serviceId;
private String version;
private String endpointType;
private String endpoint;
private String endpointType;
private String endpointContentType;
private Map<String, String> endpointProperties = new HashMap<>();
private List<Policy> servicePolicies = new ArrayList<>();

Expand Down Expand Up @@ -89,6 +90,20 @@ public void setEndpointType(String endpointType) {
this.endpointType = endpointType;
}

/**
* @return the endpointContentType
*/
public String getEndpointContentType() {
return endpointContentType;
}

/**
* @param endpointContentType the endpointContentType to set
*/
public void setEndpointContentType(String endpointContentType) {
this.endpointContentType = endpointContentType;
}

/**
* @return the endpoint
*/
Expand Down
Expand Up @@ -60,6 +60,7 @@ protected static void marshallInto(Service bean, XContentBuilder builder) throws
builder.startObject()
.field("endpoint", bean.getEndpoint())
.field("endpointType", bean.getEndpointType())
.field("endpointContentType", bean.getEndpointContentType())
.field("publicService", bean.isPublicService())
.field("organizationId", bean.getOrganizationId())
.field("serviceId", bean.getServiceId())
Expand Down Expand Up @@ -102,6 +103,7 @@ public static Service unmarshallService(Map<String, Object> source) {
bean.setEndpoint(asString(source.get("endpoint")));
bean.setEndpointProperties(asStringMap(source.get("endpointProperties")));
bean.setEndpointType(asString(source.get("endpointType")));
bean.setEndpointContentType(asString(source.get("endpointContentType")));
bean.setOrganizationId(asString(source.get("organizationId")));
bean.setPublicService(asBoolean(source.get("publicService")));
bean.setServiceId(asString(source.get("serviceId")));
Expand Down
Expand Up @@ -44,6 +44,7 @@ public void testMarshall_Service() throws Exception {
Service service = new Service();
service.setEndpoint("http://host/path/to/svc");
service.setEndpointType("REST");
service.setEndpointContentType("xml");
service.setOrganizationId("test-org");
service.setPublicService(true);
service.setServiceId("service-id");
Expand All @@ -52,6 +53,7 @@ public void testMarshall_Service() throws Exception {
Assert.assertEquals("{"
+ "\"endpoint\":\"http://host/path/to/svc\","
+ "\"endpointType\":\"REST\","
+ "\"endpointContentType\":\"xml\","
+ "\"publicService\":true,"
+ "\"organizationId\":\"test-org\","
+ "\"serviceId\":\"service-id\","
Expand All @@ -67,6 +69,7 @@ public void testMarshall_Service() throws Exception {
Assert.assertEquals("{"
+ "\"endpoint\":\"http://host/path/to/svc\","
+ "\"endpointType\":\"REST\","
+ "\"endpointContentType\":\"xml\","
+ "\"publicService\":true,"
+ "\"organizationId\":\"test-org\","
+ "\"serviceId\":\"service-id\","
Expand All @@ -88,6 +91,7 @@ public void testMarshall_Service() throws Exception {
Assert.assertEquals("{"
+ "\"endpoint\":\"http://host/path/to/svc\","
+ "\"endpointType\":\"REST\","
+ "\"endpointContentType\":\"xml\","
+ "\"publicService\":true,"
+ "\"organizationId\":\"test-org\","
+ "\"serviceId\":\"service-id\","
Expand Down Expand Up @@ -197,6 +201,7 @@ public void testMarshall_ServiceContract() throws Exception {
service.setServicePolicies(null);
service.setEndpoint("http://host/path/to/svc");
service.setEndpointType("REST");
service.setEndpointContentType("json");
service.setOrganizationId("test-org");
service.setPublicService(true);
service.setServiceId("service-id");
Expand Down Expand Up @@ -231,6 +236,7 @@ public void testMarshall_ServiceContract() throws Exception {
+ "\"service\":{"
+ "\"endpoint\":\"http://host/path/to/svc\","
+ "\"endpointType\":\"REST\","
+ "\"endpointContentType\":\"json\","
+ "\"publicService\":true,"
+ "\"organizationId\":\"test-org\","
+ "\"serviceId\":\"service-id\","
Expand Down Expand Up @@ -258,6 +264,7 @@ public void testUnmarshall_Service() throws Exception {
Map<String, Object> data = new HashMap<>();
data.put("endpoint", "http://host:port/blah");
data.put("endpointType", "REST");
data.put("endpointContentType", "xml");
data.put("organizationId", "test-org");
data.put("publicService", Boolean.TRUE);
data.put("serviceId", "test-service");
Expand All @@ -266,6 +273,7 @@ public void testUnmarshall_Service() throws Exception {

Assert.assertEquals("http://host:port/blah", service.getEndpoint());
Assert.assertEquals("REST", service.getEndpointType());
Assert.assertEquals("xml", service.getEndpointContentType());
Assert.assertEquals("test-org", service.getOrganizationId());
Assert.assertEquals("test-service", service.getServiceId());
Assert.assertEquals("1.2", service.getVersion());
Expand Down
Expand Up @@ -48,6 +48,9 @@
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.map.ObjectMapper;
Expand All @@ -65,6 +68,14 @@ public abstract class GatewayServlet extends HttpServlet {

private static final long serialVersionUID = 958726685958622333L;
private static final ObjectMapper mapper = new ObjectMapper();
private static JAXBContext jaxbContext;
static {
try {
jaxbContext = JAXBContext.newInstance(EngineErrorResponse.class, PolicyFailure.class);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}

/**
* Constructor.
Expand Down Expand Up @@ -149,11 +160,12 @@ protected void doAction(final HttpServletRequest req, final HttpServletResponse
srequest = readRequest(req);
srequest.setType(action);
} catch (Exception e) {
writeError(resp, e);
writeError(null, resp, e);
return;
}

final CountDownLatch latch = new CountDownLatch(1);
final ServiceRequest finalRequest = srequest;

// Now execute the request via the apiman engine
IServiceRequestExecutor executor = getEngine().executor(srequest, new IAsyncResultHandler<IEngineResult>() {
Expand Down Expand Up @@ -205,11 +217,11 @@ public void handle(Void result) {
throw new RuntimeException(e);
}
} else {
writeFailure(resp, engineResult.getPolicyFailure());
writeFailure(finalRequest, resp, engineResult.getPolicyFailure());
latch.countDown();
}
} else {
writeError(resp, asyncResult.getError());
writeError(finalRequest, resp, asyncResult.getError());
latch.countDown();
}
}
Expand Down Expand Up @@ -331,11 +343,12 @@ protected void writeResponse(HttpServletResponse response, ServiceResponse sresp

/**
* Writes a policy failure to the http response.
* @param request
* @param resp
* @param policyFailure
*/
private void writeFailure(HttpServletResponse resp, PolicyFailure policyFailure) {
resp.setContentType("application/json"); //$NON-NLS-1$
protected void writeFailure(ServiceRequest request, HttpServletResponse resp, PolicyFailure policyFailure) {
String rtype = request.getService().getEndpointContentType();
resp.setHeader("X-Policy-Failure-Type", String.valueOf(policyFailure.getType())); //$NON-NLS-1$
resp.setHeader("X-Policy-Failure-Message", policyFailure.getMessage()); //$NON-NLS-1$
resp.setHeader("X-Policy-Failure-Code", String.valueOf(policyFailure.getFailureCode())); //$NON-NLS-1$
Expand All @@ -357,35 +370,64 @@ private void writeFailure(HttpServletResponse resp, PolicyFailure policyFailure)

resp.setStatus(errorCode);

try {
mapper.writer().writeValue(resp.getOutputStream(), policyFailure);
IOUtils.closeQuietly(resp.getOutputStream());
} catch (Exception e) {
writeError(resp, e);
} finally {
if ("xml".equals(rtype)) { //$NON-NLS-1$
resp.setContentType("application/xml"); //$NON-NLS-1$
try {
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(policyFailure, resp.getOutputStream());
IOUtils.closeQuietly(resp.getOutputStream());
} catch (Exception e) {
writeError(request, resp, e);
}
} else {
resp.setContentType("application/json"); //$NON-NLS-1$
try {
mapper.writer().writeValue(resp.getOutputStream(), policyFailure);
IOUtils.closeQuietly(resp.getOutputStream());
} catch (Exception e) {
writeError(request, resp, e);
}
}
}

/**
* Writes an error to the servlet response object.
* @param request
* @param resp
* @param error
*/
protected void writeError(HttpServletResponse resp, Throwable error) {
protected void writeError(ServiceRequest request, HttpServletResponse resp, Throwable error) {
boolean isXml = false;
if (request.getService() != null && "xml".equals(request.getService().getEndpointContentType())) { //$NON-NLS-1$
isXml = true;
}

resp.setHeader("X-Gateway-Error", error.getMessage()); //$NON-NLS-1$
resp.setContentType("application/json"); //$NON-NLS-1$
resp.setStatus(500);

EngineErrorResponse response = new EngineErrorResponse();
response.setResponseCode(500);
response.setMessage(error.getMessage());
response.setTrace(error);

try {
mapper.writer().writeValue(resp.getOutputStream(), response);
IOUtils.closeQuietly(resp.getOutputStream());
} catch (Exception e) {
e.printStackTrace();

if (isXml) {
resp.setContentType("application/xml"); //$NON-NLS-1$
try {
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(response, resp.getOutputStream());
IOUtils.closeQuietly(resp.getOutputStream());
} catch (Exception e) {
writeError(request, resp, e);
}
} else {
resp.setContentType("application/json"); //$NON-NLS-1$
try {
mapper.writer().writeValue(resp.getOutputStream(), response);
IOUtils.closeQuietly(resp.getOutputStream());
} catch (Exception e) {
writeError(request, resp, e);
}
}
}

Expand Down
Expand Up @@ -21,12 +21,11 @@
import org.junit.runner.RunWith;

/**
* Make sure the Ignored Resources policy works.
*
* @author rubenrm1@gmail.com
* Make sure the Ignored Resources policy works when the endpoint content-type
* is set to XML.
*/
@RunWith(GatewayRestTester.class)
@GatewayRestTestPlan("test-plans/policies/ignored-resources-testPlan.xml")
@GatewayRestTestPlan("test-plans/policies/ignored-resources-xml-testPlan.xml")
public class Policy_IgnoredResourcesTest {

}
@@ -0,0 +1,32 @@
/*
* Copyright 2014 JBoss Inc
*
* 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.
*/
package io.apiman.gateway.test;

import io.apiman.gateway.test.junit.GatewayRestTestPlan;
import io.apiman.gateway.test.junit.GatewayRestTester;

import org.junit.runner.RunWith;

/**
* Make sure the Ignored Resources policy works.
*
* @author rubenrm1@gmail.com
*/
@RunWith(GatewayRestTester.class)
@GatewayRestTestPlan("test-plans/policies/ignored-resources-xml-testPlan.xml")
public class Policy_IgnoredResourcesXmlTest {

}
@@ -0,0 +1,13 @@
PUT /services admin/admin
Content-Type: application/json

{
"organizationId" : "Policy_IgnoredResourcesXmlTest",
"serviceId" : "echo",
"version" : "1.0.0",
"endpointType" : "rest",
"endpointContentType" : "xml",
"endpoint" : "${apiman-gateway-test.endpoints.echo}/"
}
----
204

0 comments on commit 0c57589

Please sign in to comment.