From dee6c34b3e5d3b40bc74fc73fafc1d116126c7fc Mon Sep 17 00:00:00 2001 From: "Bansal, Nitin (nb121v)" Date: Wed, 7 Nov 2018 10:36:38 -0500 Subject: [PATCH] Add swagger docs for gizmo APIs Improve the way node type is resolved from OXM jaxbContext. Issue-ID: AAI-1882 Change-Id: Ia72fea0ac286dc96bb3b29d117b241b58b7eece7 Signed-off-by: Bansal, Nitin (nb121v) --- pom.xml | 18 ++ src/main/java/org/onap/crud/CrudApplication.java | 23 ++ .../java/org/onap/crud/config/JerseyConfig.java | 30 +++ src/main/java/org/onap/crud/entity/Vertex.java | 5 +- .../org/onap/crud/service/CrudRestService.java | 292 ++++++++++++++++++--- .../onap/crud/util/CombinedResourceProvider.java | 50 ++++ src/main/java/org/onap/schema/OxmModelLoader.java | 66 +++++ .../onap/schema/validation/OxmModelValidator.java | 26 +- .../org/onap/crud/service/CrudRestServiceTest.java | 2 +- 9 files changed, 460 insertions(+), 52 deletions(-) create mode 100644 src/main/java/org/onap/crud/util/CombinedResourceProvider.java diff --git a/pom.xml b/pom.xml index 12ff45b..51441e8 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,24 @@ limitations under the License. cxf-rt-frontend-jaxrs 3.2.5 + + + + io.swagger + swagger-jersey2-jaxrs + 1.5.8 + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + diff --git a/src/main/java/org/onap/crud/CrudApplication.java b/src/main/java/org/onap/crud/CrudApplication.java index 008ff3f..a1531f1 100644 --- a/src/main/java/org/onap/crud/CrudApplication.java +++ b/src/main/java/org/onap/crud/CrudApplication.java @@ -22,7 +22,10 @@ package org.onap.crud; import java.util.HashMap; import java.util.Map; +import java.util.Collections; + import javax.annotation.PostConstruct; + import org.eclipse.jetty.util.security.Password; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -31,10 +34,19 @@ import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.ImportResource; import org.springframework.core.env.Environment; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + /** * Crud application class - SpringApplication.run */ @SpringBootApplication +@EnableSwagger2 @ImportResource({"file:${SERVICE_BEANS}/*.xml"}) public class CrudApplication extends SpringBootServletInitializer{// NOSONAR @Autowired @@ -67,4 +79,15 @@ public class CrudApplication extends SpringBootServletInitializer{// NOSONAR } } } + public static final Contact DEFAULT_CONTACT = new Contact("Amdocs", "http://www.amdocs.com", "noreply@amdocs.com"); + + public static final ApiInfo DEFAULT_API_INFO = new ApiInfo("AAI NCSO Adapter Service", "AAI NCSO Adapter Service.", + "1.0", "urn:tos", DEFAULT_CONTACT, "Apache 2.0", "API license URL", Collections.emptyList()); + + + + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2).apiInfo(DEFAULT_API_INFO).select().paths(PathSelectors.any()) + .apis(RequestHandlerSelectors.basePackage("org.onap.crud")).build(); + } } diff --git a/src/main/java/org/onap/crud/config/JerseyConfig.java b/src/main/java/org/onap/crud/config/JerseyConfig.java index 654ff81..60167d5 100644 --- a/src/main/java/org/onap/crud/config/JerseyConfig.java +++ b/src/main/java/org/onap/crud/config/JerseyConfig.java @@ -20,14 +20,23 @@ */ package org.onap.crud.config; +import javax.annotation.PostConstruct; +import javax.ws.rs.ApplicationPath; + import org.glassfish.jersey.server.ResourceConfig; import org.onap.crud.service.CrudRestService; import org.onap.crud.service.JaxrsEchoService; import org.springframework.stereotype.Component; +import io.swagger.jaxrs.config.BeanConfig; +import io.swagger.jaxrs.listing.ApiListingResource; +import io.swagger.jaxrs.listing.SwaggerSerializers; + /** * Registers Crud Rest interface as JAX-RS endpoints. */ + +@ApplicationPath("/services") @Component public class JerseyConfig extends ResourceConfig { @@ -35,5 +44,26 @@ public class JerseyConfig extends ResourceConfig { register(crudRestService); register(jaxrsEchoService); } + + @PostConstruct + public void init() { + // Register components where DI is needed + this.SwaggerConfig(); + } + private void SwaggerConfig() { + this.register(ApiListingResource.class); + this.register(SwaggerSerializers.class); + + BeanConfig swaggerConfigBean = new BeanConfig(); + swaggerConfigBean.setConfigId("Gizmo"); + swaggerConfigBean.setTitle("Gizmo Rest API "); + swaggerConfigBean.setVersion("v1"); + swaggerConfigBean.setContact("Amdocs Inc."); + swaggerConfigBean.setSchemes(new String[] { "https" }); + swaggerConfigBean.setBasePath("/services"); + swaggerConfigBean.setResourcePackage("org.onap.crud"); + swaggerConfigBean.setPrettyPrint(true); + swaggerConfigBean.setScan(true); + } } diff --git a/src/main/java/org/onap/crud/entity/Vertex.java b/src/main/java/org/onap/crud/entity/Vertex.java index fd03827..a70253e 100644 --- a/src/main/java/org/onap/crud/entity/Vertex.java +++ b/src/main/java/org/onap/crud/entity/Vertex.java @@ -113,9 +113,8 @@ public class Vertex { type = OxmModelValidator.resolveCollectionType(version, type); DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); - String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type)); - - final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass); + + final DynamicType modelObjectType = OxmModelLoader.getDynamicTypeForVersion(version, type); final DynamicType reservedType = jaxbContext.getDynamicType("ReservedPropNames"); diff --git a/src/main/java/org/onap/crud/service/CrudRestService.java b/src/main/java/org/onap/crud/service/CrudRestService.java index 7bf4ca4..f975347 100644 --- a/src/main/java/org/onap/crud/service/CrudRestService.java +++ b/src/main/java/org/onap/crud/service/CrudRestService.java @@ -20,7 +20,6 @@ */ package org.onap.crud.service; -import com.google.gson.JsonElement; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; @@ -28,6 +27,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; + import javax.security.auth.x500.X500Principal; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; @@ -47,6 +47,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; + import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.cxf.jaxrs.ext.PATCH; import org.onap.aai.cl.api.Logger; @@ -63,7 +64,16 @@ import org.onap.crud.util.CrudServiceConstants; import org.onap.crud.util.CrudServiceUtil; import org.slf4j.MDC; -@Path("/services/inventory") +import com.google.gson.JsonElement; + +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +@Path("/inventory") public class CrudRestService { private AbstractGraphDataService graphDataService; @@ -93,13 +103,23 @@ public class CrudRestService { public void startup() { } - + + @ApiOperation(value = "Get Vertex" , notes="For example : https://:9520/services/inventory/v11/pserver/") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @GET @Path("/{version}/{type}/{id}") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response getVertex(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response getVertex(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -130,12 +150,22 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Get Vertices" , notes="For example : https://:9520/services/inventory/v11/pserver/") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @GET @Path("/{version}/{type}/") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response getVertices(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, + public Response getVertices(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -175,12 +205,22 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Get Edge" , notes="For example : https://:9520/services/inventory/relationships/v11/tosca.relationships.HostedOn/") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @GET @Path("/relationships/{version}/{type}/{id}") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response getEdge(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response getEdge(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -211,12 +251,22 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Get Edges" , notes="For example : https://:9520/services/inventory/relationships/v11/tosca.relationships.HostedOn/") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @GET @Path("/relationships/{version}/{type}/") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response getEdges(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, + public Response getEdges(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -246,12 +296,29 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Update Edge" , notes = "# Payload \n" + + "{ \r\n" + + " \"properties\":{ \r\n" + + " \"prop1\" : \"value\",\r\n" + + " \"prop2\" :\"value\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @PUT @Path("/relationships/{version}/{type}/{id}") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response updateEdge(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response updateEdge(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -296,12 +363,29 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Patch Edge" , notes = "# Payload \n" + + "{ \r\n" + + " \"properties\":{ \r\n" + + " \"prop1\" : \"value\",\r\n" + + " \"prop2\" :\"value\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @PATCH @Path("/relationships/{version}/{type}/{id}") @Consumes({"application/merge-patch+json"}) @Produces({MediaType.APPLICATION_JSON}) - public Response patchEdge(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response patchEdge(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -338,12 +422,30 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Update Vertex" , notes = "# Payload \n" + + "{\r\n" + + " \"type\" :\"vertex type from oxm like comcast.nodes.sdwan.vpn\",\r\n" + + " \"properties\": {\r\n" + + " \"prop1\" : \"value\",\r\n" + + " \"prop2\" :\"value\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @PUT @Path("/{version}/{type}/{id}") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response updateVertex(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response updateVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -392,12 +494,30 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Patch Vertex" , notes = "# Payload \n" + + "{\r\n" + + " \"type\" :\"vertex type from oxm like comcast.nodes.sdwan.vpn\",\r\n" + + " \"properties\": {\r\n" + + " \"prop1\" : \"true\",\r\n" + + " \"prop2\" :\"name1\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @PATCH @Path("/{version}/{type}/{id}") @Consumes({"application/merge-patch+json"}) @Produces({MediaType.APPLICATION_JSON}) - public Response patchVertex(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response patchVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -437,12 +557,29 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Create Vertex" , notes = "# Payload \n" + + "{\r\n" + + " \"properties\": {\r\n" + + " \"prop1\" : \"value\",\r\n" + + " \"prop2\" :\"value\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 201, message = "Created"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @POST @Path("/{version}/{type}/") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response addVertex(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, + public Response addVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -586,12 +723,23 @@ public class CrudRestService { } + @ApiOperation(value = "Bulk API" , notes="For example : https://:9520/services/inventory/v11/bulk") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @POST @Path("/{version}/bulk/") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response addBulk(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, + public Response addBulk(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, + @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -627,12 +775,30 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Create Vertex (typeless endpoint)" , nickname="addVertex-typeless",notes = "# Payload \n" + + "{\r\n" + + " \"type\" :\"vertex type from oxm like comcast.nodes.sdwan.vpn\",\r\n" + + " \"properties\": {\r\n" + + " \"prop1\" : \"value\",\r\n" + + " \"prop2\" :\"value\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 201, message = "Created"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @POST @Path("/{version}/") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response addVertex(String content, @PathParam("version") String version, - @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, + public Response addVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, + @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -677,12 +843,32 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Create Edge" , notes = "# Payload \n" + + "{ \r\n" + + " \"source\":\"source vertex like : services/inventory/v11/vserver/0\",\r\n" + + " \"target\":\"target vertex like : services/inventory/v11/pserver/7\",\r\n" + + " \"properties\":{ \r\n" + + " \"prop1\" : \"value\",\r\n" + + " \"prop2\" :\"value\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 201, message = "Created"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @POST @Path("/relationships/{version}/{type}/") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response addEdge(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, + public Response addEdge(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -722,11 +908,31 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Create Edge (typeless endpoint)" , nickname="addEdge-typeless",notes = "# Payload \n" + + "{ \r\n" + + " \"type\":\"edge type like : tosca.relationships.HostedOn\",\r\n" + + " \"source\":\"source vertex like : services/inventory/v11/vserver/0\",\r\n" + + " \"target\":\"target vertex like : services/inventory/v11/pserver/7\",\r\n" + + " \"properties\":{ \r\n" + + " \"prop1\" : \"value\",\r\n" + + " \"prop2\" :\"value\",\r\n" + + " ..}\r\n" + + " }") + @ApiResponses({ + @ApiResponse(code = 201, message = "Created"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @POST @Path("/relationships/{version}/") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response addEdge(String content, @PathParam("version") String version, @PathParam("uri") @Encoded String uri, + public Response addEdge(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -767,12 +973,23 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Delete Vertex" , notes="For example : https://:9520/services/inventory/v11/pserver/") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @DELETE @Path("/{version}/{type}/{id}") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response deleteVertex(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response deleteVertex(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); @@ -800,12 +1017,23 @@ public class CrudRestService { return response; } + @ApiOperation(value = "Delete Edge" , notes="For example : https://:9520/services/inventory/v11/pserver/") + @ApiResponses({ + @ApiResponse(code = 200, message = "Success"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 400, message = "Bad Request"), + @ApiResponse(code = 404, message = "Not Found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + @ApiImplicitParams({ + @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"), + @ApiImplicitParam(name = "X-TransactionId", required = true, dataType = "string", paramType = "header"), + }) @DELETE @Path("/relationships/{version}/{type}/{id}") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response deleteEdge(String content, @PathParam("version") String version, @PathParam("type") String type, - @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + public Response deleteEdge(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); diff --git a/src/main/java/org/onap/crud/util/CombinedResourceProvider.java b/src/main/java/org/onap/crud/util/CombinedResourceProvider.java new file mode 100644 index 0000000..483ac5e --- /dev/null +++ b/src/main/java/org/onap/crud/util/CombinedResourceProvider.java @@ -0,0 +1,50 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * 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.crud.util; + +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider; +import springfox.documentation.swagger.web.SwaggerResource; +import springfox.documentation.swagger.web.SwaggerResourcesProvider; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +@Component +@Primary +public class CombinedResourceProvider implements SwaggerResourcesProvider { + + + public List get() { + + SwaggerResource jerseySwaggerResource = new SwaggerResource(); + jerseySwaggerResource.setLocation("/services/swagger.json"); + jerseySwaggerResource.setSwaggerVersion("2.0"); + jerseySwaggerResource.setName("Jersey"); + + return Stream.of(jerseySwaggerResource).collect(Collectors.toList()); + } + +} \ No newline at end of file diff --git a/src/main/java/org/onap/schema/OxmModelLoader.java b/src/main/java/org/onap/schema/OxmModelLoader.java index 8f55602..948914c 100644 --- a/src/main/java/org/onap/schema/OxmModelLoader.java +++ b/src/main/java/org/onap/schema/OxmModelLoader.java @@ -22,12 +22,18 @@ package org.onap.schema; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; + import javax.ws.rs.core.Response.Status; + +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.internal.oxm.mappings.Descriptor; import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; import org.onap.aai.cl.eelf.LoggerFactory; import org.onap.aai.nodes.NodeIngestor; @@ -38,10 +44,14 @@ import org.onap.crud.exception.CrudException; import org.onap.crud.logging.CrudServiceMsgs; import org.onap.schema.util.SchemaIngestPropertyReader; +import com.google.common.base.CaseFormat; + public class OxmModelLoader { private static Map versionContextMap = new ConcurrentHashMap<>(); + + private static Map> xmlElementLookup = new ConcurrentHashMap>(); static final Pattern p = Pattern.compile("aai_oxm_(.*).xml"); static final Pattern versionPattern = Pattern.compile("V(\\d*)"); @@ -82,6 +92,7 @@ public class OxmModelLoader { private static synchronized void loadModel(String oxmVersion, DynamicJAXBContext jaxbContext) { versionContextMap.put(oxmVersion, jaxbContext); + loadXmlLookupMap(oxmVersion, jaxbContext); logger.info(CrudServiceMsgs.LOADED_OXM_FILE, oxmVersion); } @@ -192,4 +203,59 @@ public class OxmModelLoader { public static void setVersionContextMap(Map versionContextMap) { OxmModelLoader.versionContextMap = versionContextMap; } + + + public static void loadXmlLookupMap(String version, DynamicJAXBContext jaxbContext ) { + + @SuppressWarnings("rawtypes") + List descriptorsList = jaxbContext.getXMLContext().getDescriptors(); + HashMap types = new HashMap(); + + for (@SuppressWarnings("rawtypes") + Descriptor desc : descriptorsList) { + + DynamicType entity = jaxbContext.getDynamicType(desc.getAlias()); + String entityName = desc.getDefaultRootElement(); + types.put(entityName, entity); + } + xmlElementLookup.put(version, types); + } + + + public static DynamicType getDynamicTypeForVersion(String version, String type) throws CrudException { + + DynamicType dynamicType; + // If we haven't already loaded in the available OXM models, then do so now. + if (versionContextMap == null || versionContextMap.isEmpty()) { + loadModels(); + } else if (!versionContextMap.containsKey(version)) { + logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, "Error loading oxm model: " + version); + throw new CrudException("Error loading oxm model: " + version, Status.INTERNAL_SERVER_ERROR); + } + + // First try to match the Java-type based on hyphen to camel case translation + String javaTypeName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type); + dynamicType = versionContextMap.get(version).getDynamicType(javaTypeName); + + //Attempt to lookup in xml elements + if (xmlElementLookup.containsKey(version)) { + if (dynamicType == null) { + // Try to lookup by xml root element by exact match + dynamicType = xmlElementLookup.get(version).get(type); + } + + if (dynamicType == null) { + // Try to lookup by xml root element by lowercase + dynamicType = xmlElementLookup.get(version).get(type.toLowerCase()); + } + + if (dynamicType == null) { + // Direct lookup as java-type name + dynamicType = versionContextMap.get(version).getDynamicType(type); + } + } + + return dynamicType; + + } } diff --git a/src/main/java/org/onap/schema/validation/OxmModelValidator.java b/src/main/java/org/onap/schema/validation/OxmModelValidator.java index d317678..9da835e 100644 --- a/src/main/java/org/onap/schema/validation/OxmModelValidator.java +++ b/src/main/java/org/onap/schema/validation/OxmModelValidator.java @@ -88,8 +88,7 @@ public class OxmModelValidator { logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, OXM_LOAD_ERROR + ": " + version); throw new CrudException(OXM_LOAD_ERROR + ": " + version, Status.NOT_FOUND); } - final DynamicType modelObjectType = jaxbContext.getDynamicType( - CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type))); + final DynamicType modelObjectType = OxmModelLoader.getDynamicTypeForVersion(version, type); final DynamicType reservedObjectType = jaxbContext.getDynamicType("ReservedPropNames"); for (String key : filter.keySet()) { @@ -137,8 +136,7 @@ public class OxmModelValidator { } // Determine if the Object part is a collection type in the model // definition - final DynamicType modelObjectType = jaxbContext.getDynamicType( - CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type))); + final DynamicType modelObjectType = OxmModelLoader.getDynamicTypeForVersion(version, type); if (modelObjectType == null) { logger.error(CrudServiceMsgs.INVALID_OXM_FILE, "Object of collection type not found: " + type); @@ -168,10 +166,8 @@ public class OxmModelValidator { try { type = resolveCollectionType(version, type); DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); - String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, - CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type)); - final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass); + final DynamicType modelObjectType = OxmModelLoader.getDynamicTypeForVersion(version, type); final DynamicType reservedType = jaxbContext.getDynamicType("ReservedPropNames"); Set> payloadEntriesSet = properties.getAsJsonObject().entrySet(); @@ -252,10 +248,8 @@ public class OxmModelValidator { try { type = resolveCollectionType(version, type); DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); - String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, - CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type)); - - final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass); + + final DynamicType modelObjectType = OxmModelLoader.getDynamicTypeForVersion(version, type); final DynamicType reservedType = jaxbContext.getDynamicType("ReservedPropNames"); Set> payloadEntriesSet = properties.getAsJsonObject().entrySet(); @@ -326,11 +320,11 @@ public class OxmModelValidator { try { DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); - String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, - CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, - vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()) != null - ? vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()).toString() : vertex.getType())); - final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass); + + final DynamicType modelObjectType = OxmModelLoader.getDynamicTypeForVersion(version, + vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()) != null + ? vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()).toString() + : vertex.getType()); final DynamicType reservedObjectType = jaxbContext.getDynamicType("ReservedPropNames"); for (String key : vertex.getProperties().keySet()) { diff --git a/src/test/java/org/onap/crud/service/CrudRestServiceTest.java b/src/test/java/org/onap/crud/service/CrudRestServiceTest.java index 1098284..bc70a36 100644 --- a/src/test/java/org/onap/crud/service/CrudRestServiceTest.java +++ b/src/test/java/org/onap/crud/service/CrudRestServiceTest.java @@ -333,7 +333,7 @@ public class CrudRestServiceTest { String payloadStr = readFileToString(bulkFile); System.out.println(payloadStr); - response = mockService.addBulk(payloadStr, "v9", "", + response = mockService.addBulk(payloadStr, "v9", "services/inventory/v9", new TestHeaders(), null, new TestRequest()); System.out.println("Bulk Response: " + response); System.out.println("Response Entity: " + response.getEntity().toString()); -- 2.16.6