[ofbiz-plugins] branch trunk updated: Added support to read children attributes of the service for rendering openapi spec (#40)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[ofbiz-plugins] branch trunk updated: Added support to read children attributes of the service for rendering openapi spec (#40)

grv-2
This is an automated email from the ASF dual-hosted git repository.

grv pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-plugins.git


The following commit(s) were added to refs/heads/trunk by this push:
     new dce5c97  Added support to read children attributes of the service for rendering openapi spec (#40)
dce5c97 is described below

commit dce5c976f7b1e509bc8d2f4046b2c370ca0adc45
Author: girishvasmatkar <[hidden email]>
AuthorDate: Sun Aug 23 11:58:19 2020 +0530

    Added support to read children attributes of the service for rendering openapi spec (#40)
---
 .../ofbiz/ws/rs/openapi/OFBizOpenApiReader.java    |  48 +-----
 .../ws/rs/resources/AuthenticationResource.java    |   8 +-
 .../ws/rs/resources/OFBizServiceResource.java      |   5 +-
 .../org/apache/ofbiz/ws/rs/util/OpenApiUtil.java   | 169 ++++++++++++++++++++-
 4 files changed, 177 insertions(+), 53 deletions(-)

diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/openapi/OFBizOpenApiReader.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/openapi/OFBizOpenApiReader.java
index de1c9e8..20b9301 100644
--- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/openapi/OFBizOpenApiReader.java
+++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/openapi/OFBizOpenApiReader.java
@@ -44,13 +44,9 @@ import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.Operation;
 import io.swagger.v3.oas.models.PathItem;
 import io.swagger.v3.oas.models.Paths;
-import io.swagger.v3.oas.models.media.ArraySchema;
 import io.swagger.v3.oas.models.media.Content;
-import io.swagger.v3.oas.models.media.IntegerSchema;
 import io.swagger.v3.oas.models.media.MediaType;
-import io.swagger.v3.oas.models.media.ObjectSchema;
 import io.swagger.v3.oas.models.media.Schema;
-import io.swagger.v3.oas.models.media.StringSchema;
 import io.swagger.v3.oas.models.parameters.QueryParameter;
 import io.swagger.v3.oas.models.parameters.RequestBody;
 import io.swagger.v3.oas.models.responses.ApiResponse;
@@ -159,7 +155,6 @@ public final class OFBizOpenApiReader extends Reader implements OpenApiReader {
 
         openApi.setPaths(paths);
         openApi.setComponents(components);
-
         return openApi;
     }
 
@@ -193,50 +188,11 @@ public final class OFBizOpenApiReader extends Reader implements OpenApiReader {
     }
 
     private void setOutSchemaForService(ModelService service) {
-        Schema<Object> parentSchema = new Schema<Object>();
-        parentSchema.setDescription("Out Schema for service: " + service.getName() + " response");
-        parentSchema.setType("object");
-        parentSchema.addProperties("statusCode", new IntegerSchema().description("HTTP Status Code"));
-        parentSchema.addProperties("statusDescription", new StringSchema().description("HTTP Status Code Description"));
-        parentSchema.addProperties("successMessage", new StringSchema().description("Success Message"));
-        ObjectSchema dataSchema = new ObjectSchema();
-        parentSchema.addProperties("data", dataSchema);
-        service.getOutParamNamesMap().forEach((name, type) -> {
-            Schema<?> schema = null;
-            Class<?> schemaClass = OpenApiUtil.getOpenApiSchema(type);
-            if (schemaClass == null) {
-                return;
-            }
-            try {
-                schema = (Schema<?>) schemaClass.newInstance();
-            } catch (InstantiationException | IllegalAccessException e) {
-            }
-            if (schema instanceof ArraySchema) {
-                ArraySchema arraySchema = (ArraySchema) schema;
-                arraySchema.items(new StringSchema());
-            }
-            dataSchema.addProperties(name, schema.description(name));
-        });
-        schemas.put(service.getName() + "Response", parentSchema);
+        schemas.put(service.getName() + "Response", OpenApiUtil.getOutSchema(service));
     }
 
     private void setInSchemaForService(ModelService service) {
-        Schema<Object> parentSchema = new Schema<Object>();
-        parentSchema.setDescription("In Schema for service: " + service.getName() + " request");
-        parentSchema.setType("object");
-        service.getInParamNamesMap().forEach((name, type) -> {
-            Schema<?> schema = null;
-            Class<?> schemaClass = OpenApiUtil.getOpenApiSchema(type);
-            if (schemaClass == null) {
-                return;
-            }
-            try {
-                schema = (Schema<?>) schemaClass.newInstance();
-            } catch (InstantiationException | IllegalAccessException e) {
-            }
-            parentSchema.addProperties(name, schema.description(name));
-        });
-        schemas.put(service.getName() + "Request", parentSchema);
+        schemas.put(service.getName() + "Request", OpenApiUtil.getInSchema(service));
     }
 
 }
diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/AuthenticationResource.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/AuthenticationResource.java
index c675e7d..b2a0671 100644
--- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/AuthenticationResource.java
+++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/AuthenticationResource.java
@@ -22,10 +22,12 @@ import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.Provider;
@@ -38,6 +40,8 @@ import org.apache.ofbiz.ws.rs.security.AuthToken;
 import org.apache.ofbiz.ws.rs.util.RestApiUtil;
 
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.tags.Tag;
 
@@ -61,7 +65,9 @@ public class AuthenticationResource extends OFBizResource {
     @AuthToken
     @Operation(security = @SecurityRequirement(name = "basicAuth"),
             operationId = "getAuthToken", description = "Generates JWT token for subsequent API calles.")
-    public Response getAuthToken() {
+    public Response getAuthToken(@Parameter(in = ParameterIn.HEADER, name = "Authorization",
+            description = "Authorization header using Basic Authentication", example = HttpHeaders.AUTHORIZATION + ": Basic YWRtaW46b2ZiaXo=")
+            @HeaderParam(HttpHeaders.AUTHORIZATION) String creds) {
         httpRequest.setAttribute("delegator", getDelegator());
         httpRequest.setAttribute("dispatcher", getDispatcher());
         GenericValue userLogin = (GenericValue) httpRequest.getAttribute("userLogin");
diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java
index 0a3a9c5..c51887c 100644
--- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java
+++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java
@@ -81,7 +81,8 @@ public class OFBizServiceResource extends OFBizResource {
                 Map<String, Object> serviceMap = new LinkedHashMap<String, Object>();
                 serviceMap.put("name", service.getName());
                 serviceMap.put("description", service.getDescription());
-                Link selfLink = Link.fromUriBuilder(uriInfo.getAbsolutePathBuilder().path(service.getName())).type(service.getAction()).rel("self").build();
+                Link selfLink = Link.fromUriBuilder(uriInfo.getAbsolutePathBuilder().path(service.getName()))
+                        .type(service.getAction()).rel("self").build();
                 serviceMap.put("link", selfLink);
                 serviceList.add(serviceMap);
             }
@@ -108,7 +109,6 @@ public class OFBizServiceResource extends OFBizResource {
         return processor.process(
                 UtilMisc.toMap("serviceName", serviceName, "httpVerb", HttpMethod.GET, "requestMap", serviceRequest.getInParams(), "dispatcher",
                         getDispatcher(), "request", httpRequest));
-
     }
 
     /**
@@ -128,6 +128,5 @@ public class OFBizServiceResource extends OFBizResource {
         return processor.process(
                 UtilMisc.toMap("serviceName", serviceName, "httpVerb", HttpMethod.POST, "requestMap", serviceInParams, "dispatcher", getDispatcher(),
                         "request", httpRequest));
-
     }
 }
diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/OpenApiUtil.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/OpenApiUtil.java
index 7e32226..c8d98f2 100644
--- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/OpenApiUtil.java
+++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/OpenApiUtil.java
@@ -19,24 +19,40 @@
 package org.apache.ofbiz.ws.rs.util;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.entity.Delegator;
+import org.apache.ofbiz.entity.model.ModelEntity;
+import org.apache.ofbiz.entity.model.ModelField;
+import org.apache.ofbiz.service.ModelParam;
+import org.apache.ofbiz.service.ModelService;
+import org.apache.ofbiz.webapp.WebAppUtil;
+import org.apache.ofbiz.ws.rs.listener.ApiContextListener;
+
 import io.swagger.v3.oas.models.media.ArraySchema;
 import io.swagger.v3.oas.models.media.BooleanSchema;
 import io.swagger.v3.oas.models.media.DateSchema;
 import io.swagger.v3.oas.models.media.IntegerSchema;
 import io.swagger.v3.oas.models.media.MapSchema;
 import io.swagger.v3.oas.models.media.NumberSchema;
+import io.swagger.v3.oas.models.media.ObjectSchema;
+import io.swagger.v3.oas.models.media.Schema;
 import io.swagger.v3.oas.models.media.StringSchema;
 
 public final class OpenApiUtil {
 
+    private static final String MODULE = OpenApiUtil.class.getName();
+
     private OpenApiUtil() {
 
     }
 
     private static final Map<String, String> CLASS_ALIAS = new HashMap<>();
     private static final Map<String, Class<?>> JAVA_OPEN_API_MAP = new HashMap<>();
+    private static final Map<String, String> FIELD_TYPE_MAP = new HashMap<String, String>();
 
     static {
         CLASS_ALIAS.put("String", "String");
@@ -50,7 +66,7 @@ public final class OpenApiUtil {
         CLASS_ALIAS.put("Timestamp", "Timestamp");
         CLASS_ALIAS.put("java.sql.Timestamp", "Timestamp");
         CLASS_ALIAS.put("Integer", "Integer");
-        CLASS_ALIAS.put("java.lang.Integer", "Int");
+        CLASS_ALIAS.put("java.lang.Integer", "Integer");
         CLASS_ALIAS.put("Long", "Long");
         CLASS_ALIAS.put("java.lang.Long", "Long");
         CLASS_ALIAS.put("BigInteger", "BigInteger");
@@ -98,10 +114,157 @@ public final class OpenApiUtil {
         JAVA_OPEN_API_MAP.put("BigInteger", IntegerSchema.class);
         JAVA_OPEN_API_MAP.put("Timestamp", DateSchema.class);
 
+        FIELD_TYPE_MAP.put("id", "String");
+        FIELD_TYPE_MAP.put("indicator", "String");
+        FIELD_TYPE_MAP.put("date", "String");
+        FIELD_TYPE_MAP.put("id-vlong", "String");
+        FIELD_TYPE_MAP.put("description", "String");
+        FIELD_TYPE_MAP.put("numeric", "Int"); //
+        FIELD_TYPE_MAP.put("long-varchar", "String");
+        FIELD_TYPE_MAP.put("id-long", "String");
+        FIELD_TYPE_MAP.put("currency-amount", "BigDecimal");
+        FIELD_TYPE_MAP.put("value", "value");
+        FIELD_TYPE_MAP.put("email", "String");
+        FIELD_TYPE_MAP.put("currency-precise", "BigDecimal");
+        FIELD_TYPE_MAP.put("very-short", "String");
+        FIELD_TYPE_MAP.put("date-time", "Timestamp");
+        FIELD_TYPE_MAP.put("credit-card-date", "String");
+        FIELD_TYPE_MAP.put("url", "String");
+        FIELD_TYPE_MAP.put("credit-card-number", "String");
+        FIELD_TYPE_MAP.put("fixed-point", "BigDecimal");
+        FIELD_TYPE_MAP.put("name", "String");
+        FIELD_TYPE_MAP.put("short-varchar", "String");
+        FIELD_TYPE_MAP.put("comment", "String");
+        FIELD_TYPE_MAP.put("time", "String");
+        FIELD_TYPE_MAP.put("very-long", "String");
+        FIELD_TYPE_MAP.put("floating-point", "Float");
+        FIELD_TYPE_MAP.put("object", "Byte");
+        FIELD_TYPE_MAP.put("byte-array", "Byte");
+        FIELD_TYPE_MAP.put("blob", "Byte");
+
+    }
+
+    public static Class<?> getOpenApiTypeForAttributeType(String attributeType) {
+        return JAVA_OPEN_API_MAP.get(CLASS_ALIAS.get(attributeType));
+    }
+
+    public static Class<?> getOpenApiTypeForFieldType(String fieldType) {
+        return JAVA_OPEN_API_MAP.get(FIELD_TYPE_MAP.get(fieldType));
+    }
+
+    public static Schema<Object> getInSchema(ModelService service) {
+        Schema<Object> parentSchema = new Schema<Object>();
+        parentSchema.setDescription("In Schema for service: " + service.getName() + " request");
+        parentSchema.setType("object");
+        service.getInParamNamesMap().forEach((name, type) -> {
+            Schema<?> attrSchema = getAttributeSchema(service, service.getParam(name));
+            if (attrSchema != null) {
+                parentSchema.addProperties(name, getAttributeSchema(service, service.getParam(name)));
+            }
+        });
+        return parentSchema;
     }
 
+    private static Schema<?> getAttributeSchema(ModelService service, ModelParam param) {
+        Schema<?> schema = null;
+        Class<?> schemaClass = getOpenApiTypeForAttributeType(param.getType());
+        if (schemaClass == null) {
+            Debug.logWarning("Attribute '" + param.getName() + "' ignored as it is declared as '" + param.getType()
+                    + "' and corresponding OpenApi Type Mapping not found.", MODULE);
+            return null;
+        }
+        try {
+            schema = (Schema<?>) schemaClass.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            e.printStackTrace();
+        }
+
+        List<ModelParam> children = param.getChildren();
+        Delegator delegator = WebAppUtil.getDelegator(ApiContextListener.getApplicationCntx());
+        if (schema instanceof ArraySchema) {
+            ((ArraySchema) schema).setItems(getAttributeSchema(service, children.get(0)));
+        } else if (schema instanceof MapSchema) {
+            if (isTypeGenericEntityOrGenericValue(param.getType())) {
+                if (UtilValidate.isEmpty(param.getEntityName())) {
+                    Debug.logWarning(
+                            "Attribute '" + param.getName() + "' ignored as it is declared as '" + param.getType() + "' but does not have "
+                            + "entity-name defined.",
+                            MODULE);
+                    return null;
+                } else {
+                    schema = getSchemaForEntity(delegator.getModelEntity(param.getEntityName()));
+                }
+            } else if (UtilValidate.isEmpty(param.getChildren())) {
+                Debug.logWarning(
+                        "Attribute '" + param.getName() + "' ignored as it is declared as '" + param.getType() + "' but does not have "
+                        + "any child attributes.",
+                        MODULE);
+                return null;
+            } else {
+                for (ModelParam childParam : children) {
+                    schema.addProperties(childParam.getName(), getAttributeSchema(service, childParam));
+                }
+
+            }
+
+        }
+        return schema;
+    }
+
+    public static Schema<Object> getOutSchema(ModelService service) {
+        Schema<Object> parentSchema = new Schema<Object>();
+        parentSchema.setDescription("Out Schema for service: " + service.getName() + " response");
+        parentSchema.setType("object");
+        parentSchema.addProperties("statusCode", new IntegerSchema().description("HTTP Status Code"));
+        parentSchema.addProperties("statusDescription", new StringSchema().description("HTTP Status Code Description"));
+        parentSchema.addProperties("successMessage", new StringSchema().description("Success Message"));
+        ObjectSchema dataSchema = new ObjectSchema();
+        parentSchema.addProperties("data", dataSchema);
+        service.getOutParamNamesMap().forEach((name, type) -> {
+            Schema<?> schema = null;
+            Class<?> schemaClass = getOpenApiTypeForAttributeType(type);
+            if (schemaClass == null) {
+                return;
+            }
+            try {
+                schema = (Schema<?>) schemaClass.newInstance();
+            } catch (InstantiationException | IllegalAccessException e) {
+                e.printStackTrace();
+            }
+            if (schema instanceof ArraySchema) {
+                ArraySchema arraySchema = (ArraySchema) schema;
+                arraySchema.items(new StringSchema());
+            }
+            dataSchema.addProperties(name, schema.description(name));
+        });
+        return parentSchema;
+    }
+
+    private static boolean isTypeGenericEntityOrGenericValue(String type) {
+        if (type == null) {
+            return false;
+        }
+        return type.matches("org.apache.ofbiz.entity.GenericValue|GenericValue|org.apache.ofbiz.entity.GenericEntity|GenericEntity");
+    }
 
-    public static Class<?> getOpenApiSchema(String type) {
-        return JAVA_OPEN_API_MAP.get(CLASS_ALIAS.get(type));
+    private static Schema<?> getSchemaForEntity(ModelEntity entity) {
+        Schema<?> dataSchema = new Schema<>();
+        dataSchema.setType("object");
+        List<String> fields = entity.getAllFieldNames();
+        for (String fieldNm : fields) {
+            ModelField field = entity.getField(fieldNm);
+            Schema<?> schema = null;
+            Class<?> schemaClass = getOpenApiTypeForFieldType(field.getType());
+            if (schemaClass == null) {
+                continue;
+            }
+            try {
+                schema = (Schema<?>) schemaClass.newInstance();
+            } catch (InstantiationException | IllegalAccessException e) {
+                e.printStackTrace();
+            }
+            dataSchema.addProperties(fieldNm, schema.description(fieldNm));
+        }
+        return dataSchema;
     }
 }