You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2015/12/10 09:00:09 UTC

[4/4] isis git commit: ISIS-1237: object paths and object action paths.

ISIS-1237: object paths and object action paths.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/53ead490
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/53ead490
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/53ead490

Branch: refs/heads/ISIS-1237
Commit: 53ead490bbcbbcc6c378132356cbe79cef6c2561
Parents: 6daa442
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Thu Dec 10 07:59:33 2015 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Thu Dec 10 07:59:33 2015 +0000

----------------------------------------------------------------------
 .../swagger/internal/SwaggerSpecGenerator.java  | 293 +++++++++++++++----
 1 file changed, 240 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/53ead490/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/SwaggerSpecGenerator.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/SwaggerSpecGenerator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/SwaggerSpecGenerator.java
index bfb1489..896d4f0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/SwaggerSpecGenerator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/SwaggerSpecGenerator.java
@@ -30,7 +30,9 @@ import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.filter.Filters;
 import org.apache.isis.applib.services.swagger.SwaggerService;
 import org.apache.isis.core.commons.factory.InstanceUtil;
+import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
 import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet;
+import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 import org.apache.isis.core.metamodel.services.ServiceUtil;
 import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -46,6 +48,7 @@ import io.swagger.models.Path;
 import io.swagger.models.Response;
 import io.swagger.models.Swagger;
 import io.swagger.models.parameters.BodyParameter;
+import io.swagger.models.parameters.PathParameter;
 import io.swagger.models.parameters.QueryParameter;
 import io.swagger.models.properties.ArrayProperty;
 import io.swagger.models.properties.IntegerProperty;
@@ -76,30 +79,65 @@ public class SwaggerSpecGenerator {
         appendLinkDefinitions(swagger);
 
         final Collection<ObjectSpecification> allSpecs = specificationLoader.allSpecifications();
-        for (ObjectSpecification serviceSpec : allSpecs) {
+        for (final ObjectSpecification serviceSpec :  allSpecs) {
+
             final DomainServiceFacet domainServiceFacet = serviceSpec.getFacet(DomainServiceFacet.class);
             if (domainServiceFacet == null) {
                 continue;
             }
-            if (!isVisible(visibility, domainServiceFacet)) {
+            if (visibility.isPublic() &&
+                domainServiceFacet.getNatureOfService() != NatureOfService.VIEW_REST_ONLY) {
+                continue;
+            }
+            if (domainServiceFacet.getNatureOfService() != NatureOfService.VIEW_MENU_ONLY &&
+                domainServiceFacet.getNatureOfService() != NatureOfService.VIEW) {
                 continue;
             }
 
-            List<ActionType> actionTypes = actionTypesFor(visibility);
-            List<ObjectAction> serviceActions = serviceSpec.getObjectActions(
+            final List<ActionType> actionTypes = actionTypesFor(visibility);
+            final List<ObjectAction> serviceActions = serviceSpec.getObjectActions(
                     actionTypes, Contributed.EXCLUDED, Filters.<ObjectAction>any());
-            if(serviceActions.isEmpty()) {
+            if (serviceActions.isEmpty()) {
                 continue;
             }
 
-            final String serviceId = serviceIdFor(serviceSpec);
-
-            final ObjectProperty serviceMembers = appendServicePath(swagger, serviceId);
+            final ObjectProperty serviceMembers = appendServicePath(swagger, serviceSpec);
 
             for (final ObjectAction serviceAction : serviceActions) {
+                if (visibility.isPublic() && !isVisibleForPublic(serviceAction)) {
+                    continue;
+                }
                 appendActionTo(serviceMembers, serviceAction);
+                appendServiceActionInvokePath(swagger, serviceAction);
+            }
+        }
+
+        for (final ObjectSpecification objectSpec : allSpecs) {
+
+            final DomainServiceFacet domainServiceFacet = objectSpec.getFacet(DomainServiceFacet.class);
+            if (domainServiceFacet != null) {
+                continue;
+            }
+
+            if(objectSpec.isAbstract()) {
+                continue;
+            }
+
+            final List<ActionType> actionTypes = actionTypesFor(visibility);
+            final List<ObjectAction> objectActions = objectSpec.getObjectActions(
+                    actionTypes, Contributed.INCLUDED, Filters.<ObjectAction>any());
+            if (objectActions.isEmpty()) {
+                continue;
+            }
+
+            final ObjectProperty objectMembers = appendObjectPath(swagger, objectSpec);
 
-                appendInvokePath(swagger, serviceAction);
+            for (final ObjectAction objectAction : objectActions) {
+                if (visibility.isPublic() && !isVisibleForPublic(objectAction)) {
+                    continue;
+                }
+                appendActionTo(objectMembers, objectAction);
+                appendObjectActionInvokePath(swagger, objectAction);
             }
         }
 
@@ -241,6 +279,77 @@ public class SwaggerSpecGenerator {
         );
     }
 
+    ObjectProperty appendServicePath(final Swagger swagger, final ObjectSpecification objectSpec) {
+
+        final String serviceId = serviceIdFor(objectSpec);
+
+        final Path path = new Path();
+        swagger.path(String.format("/services/%s", serviceId), path);
+
+        path.get(
+                new Operation()
+                        .tag(serviceId)
+                        .description(roSpec("15.1"))
+                        .produces("application/json")
+                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/object")
+                        .response(200,
+                                newResponse(Caching.TRANSACTIONAL)
+                                        .description("OK")
+                                        .schema(new RefProperty("#/definitions/service-" + serviceId)))
+        );
+
+        final ObjectProperty serviceMembers = new ObjectProperty();
+        final ModelImpl serviceRepr =
+                newModel(roSpec("15.1.2") + ": representation of " + serviceId)
+                        .property("title", stringProperty())
+                        .property("serviceId", stringProperty()._default(serviceId))
+                        .property("members", serviceMembers);
+
+        swagger.addDefinition("service-" + serviceId, serviceRepr);
+        return serviceMembers;
+    }
+
+    ObjectProperty appendObjectPath(final Swagger swagger, final ObjectSpecification objectSpec) {
+
+        final String objectType = objectTypeFor(objectSpec);
+
+        final Path path = new Path();
+        swagger.path(String.format("/objects/%s/{objectId}", objectType), path);
+
+        path.get(
+                new Operation()
+                        .tag(objectType)
+                        .description(roSpec("14.1"))
+                        .parameter(
+                                new PathParameter()
+                                        .name("objectId")
+                                        .type("string"))
+                        .produces("application/json")
+                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/object")
+                        .produces("application/json;profile=urn:org.apache.isis/v1")
+                        .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
+                        .response(200,
+                                newResponse(Caching.TRANSACTIONAL)
+                                        .description("OK")
+                                        .schema(new RefProperty("#/definitions/object-" + objectType)))
+        );
+
+        final ObjectProperty serviceMembers = new ObjectProperty();
+        final ModelImpl serviceRepr =
+                newModel(roSpec("14.4") + ": representation of " + objectType)
+                        .property("title", stringProperty())
+                        .property("domainType", stringProperty()._default(objectType))
+                        .property("instanceId", stringProperty())
+                        .property("members", serviceMembers);
+
+        swagger.addDefinition("object-" + objectType, serviceRepr);
+        return serviceMembers;
+    }
+
+    private String objectTypeFor(final ObjectSpecification objectSpec) {
+        return objectSpec.getFacet(ObjectSpecIdFacet.class).value().asString();
+    }
+
     void appendActionTo(final ObjectProperty serviceMembers, final ObjectAction serviceAction) {
         String serviceActionId = serviceAction.getId();
 
@@ -261,64 +370,118 @@ public class SwaggerSpecGenerator {
         );
     }
 
-    ObjectProperty appendServicePath(
+    void appendServiceActionInvokePath(
             final Swagger swagger,
-            final String serviceId) {
+            final ObjectAction serviceAction) {
 
-        final String serviceDefinitionId = "service-" + serviceId;
-        final String servicePathStr = "/services/" + serviceId;
+        final ObjectSpecification serviceSpec = serviceAction.getOnType();
+        final String serviceId = serviceIdFor(serviceSpec);
+        final String actionId = serviceAction.getId();
 
-        final Path servicePath = new Path();
-        swagger.path(servicePathStr, servicePath);
+        final List<ObjectActionParameter> parameters = serviceAction.getParameters();
+        final Path path = new Path();
+        swagger.path(String.format("/services/%s/actions/%s/invoke", serviceId, actionId), path);
 
-        servicePath.get(
+        final Operation invokeOperation =
                 new Operation()
                         .tag(serviceId)
-                        .description(roSpec("15.1"))
+                        .description(roSpec("19.1") + ": (invoke) resource of " + serviceId + "#" + actionId)
                         .produces("application/json")
-                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/object")
-                        .response(200,
-                                newResponse(Caching.TRANSACTIONAL)
-                                        .description("OK")
-                                        .schema(new RefProperty("#/definitions/"
-                                                + serviceDefinitionId)))
-        );
+                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result")
+                        .produces("application/json;profile=urn:org.apache.isis/v1")
+                        .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true");
 
-        final ObjectProperty serviceMembers = new ObjectProperty();
-        ModelImpl serviceRepr =
-                newModel(roSpec("15.1.2") + ": representation of " + serviceId)
-                        .property("title", stringProperty())
-                        .property("serviceId", stringProperty()._default(serviceId))
-                        .property("members", serviceMembers);
+        final ActionSemantics.Of semantics = serviceAction.getSemantics();
+        if(semantics.isSafeInNature()) {
+            path.get(invokeOperation);
 
-        swagger.addDefinition(serviceDefinitionId, serviceRepr);
-        return serviceMembers;
+            for (final ObjectActionParameter parameter : parameters) {
+                invokeOperation
+                        .parameter(
+                                new QueryParameter()
+                                        .name(parameter.getId())
+                                        .description(roSpec("2.9.1") + (!Strings.isNullOrEmpty(parameter.getDescription())? (": " + parameter.getDescription()) : ""))
+                                        .required(false)
+                                        .type("string")
+                        );
+            }
+            if(!parameters.isEmpty()) {
+                invokeOperation.parameter(new QueryParameter()
+                        .name("x-isis-querystring")
+                        .description(roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
+                        .required(false)
+                        .type("string"));
+            }
+
+        } else {
+            if (semantics.isIdempotentInNature()) {
+                path.put(invokeOperation);
+            } else {
+                path.post(invokeOperation);
+            }
+
+            final ModelImpl bodyParam =
+                    new ModelImpl()
+                            .type("object");
+            for (final ObjectActionParameter parameter : parameters) {
+
+                final Property valueProperty;
+                // TODO: need to switch on parameter's type and create appropriate impl of valueProperty
+                // if(parameter.getSpecification().isValue()) ...
+                valueProperty = stringProperty();
+
+                bodyParam
+                        .property(parameter.getId(),
+                                new ObjectProperty()
+                                        .property("value", valueProperty)
+                        );
+            }
+
+            invokeOperation
+                    .consumes("application/json")
+                    .parameter(
+                            new BodyParameter()
+                                    .name("body")
+                                    .schema(bodyParam));
+
+        }
+
+        invokeOperation
+                .response(
+                        200, new Response()
+                                .description(roSpecForResponseOf(serviceAction) + ": (invoke) representation of " + serviceId + "#" + actionId)
+                                .schema(new ObjectProperty())
+                );
     }
 
-    void appendInvokePath(
+    void appendObjectActionInvokePath(
             final Swagger swagger,
-            final ObjectAction serviceAction) {
+            final ObjectAction objectAction) {
 
-        final ObjectSpecification serviceSpec = serviceAction.getOnType();
-        final String serviceId = serviceIdFor(serviceSpec);
-        final String serviceActionId = serviceAction.getId();
+        final ObjectSpecification objectSpec = objectAction.getOnType();
+        final String objectType = objectTypeFor(objectSpec);
+        final String actionId = objectAction.getId();
 
-        final List<ObjectActionParameter> parameters = serviceAction.getParameters();
-        final Path serviceActionInvokePath = new Path();
-        swagger.path(String.format("/services/%s/actions/%s/invoke", serviceId, serviceActionId), serviceActionInvokePath);
+        final List<ObjectActionParameter> parameters = objectAction.getParameters();
+        final Path path = new Path();
+        swagger.path(String.format("/objects/%s/{objectId}/actions/%s/invoke", objectType, actionId), path);
 
         final Operation invokeOperation =
                 new Operation()
-                        .tag(serviceId)
-                        .description(roSpec("19.1") + ": (invoke) resource of " + serviceId + "#" + serviceActionId)
+                        .tag(objectType)
+                        .description(roSpec("19.1") + ": (invoke) resource of " + objectType + "#" + actionId)
+                        .parameter(
+                                new PathParameter()
+                                        .name("objectId")
+                                        .type("string"))
                         .produces("application/json")
                         .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result")
                         .produces("application/json;profile=urn:org.apache.isis/v1")
                         .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true");
 
-        final ActionSemantics.Of semantics = serviceAction.getSemantics();
+        final ActionSemantics.Of semantics = objectAction.getSemantics();
         if(semantics.isSafeInNature()) {
-            serviceActionInvokePath.get(invokeOperation);
+            path.get(invokeOperation);
 
             for (final ObjectActionParameter parameter : parameters) {
                 invokeOperation
@@ -340,9 +503,9 @@ public class SwaggerSpecGenerator {
 
         } else {
             if (semantics.isIdempotentInNature()) {
-                serviceActionInvokePath.put(invokeOperation);
+                path.put(invokeOperation);
             } else {
-                serviceActionInvokePath.post(invokeOperation);
+                path.post(invokeOperation);
             }
 
             final ModelImpl bodyParam =
@@ -374,7 +537,7 @@ public class SwaggerSpecGenerator {
         invokeOperation
                 .response(
                         200, new Response()
-                                .description(roSpecForResponseOf(serviceAction) + ": (invoke) representation of " + serviceId + "#" + serviceActionId)
+                                .description(roSpecForResponseOf(objectAction) + ": (invoke) representation of " + objectType + "#" + actionId)
                                 .schema(new ObjectProperty())
                 );
     }
@@ -394,15 +557,39 @@ public class SwaggerSpecGenerator {
         }
     }
 
-    boolean isVisible(final SwaggerService.Visibility visibility, final DomainServiceFacet domainServiceFacet) {
-        if (domainServiceFacet.getNatureOfService() == NatureOfService.VIEW_REST_ONLY) {
+    private boolean isVisibleForPublic(final ObjectAction objectAction) {
+        final ObjectSpecification specification = objectAction.getReturnType();
+        boolean visible = isVisibleForPublic(specification);
+        if(!visible) {
+            return false;
+        }
+        List<ObjectSpecification> parameterTypes = objectAction.getParameterTypes();
+        for (ObjectSpecification parameterType : parameterTypes) {
+            boolean paramVisible = isVisibleForPublic(parameterType);
+            if(!paramVisible) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean isVisibleForPublic(final ObjectSpecification specification) {
+        if (specification == null) {
             return true;
         }
-        if (visibility.isPublic()) {
-            return false;
+        if(specification.isViewModel()) {
+            return true;
+        }
+        if(specification.isValue()) {
+            return true;
+        }
+        if(specification.isParentedOrFreeCollection()) {
+            TypeOfFacet typeOfFacet = specification.getFacet(TypeOfFacet.class);
+            ObjectSpecification elementSpec = typeOfFacet.valueSpec();
+            return isVisibleForPublic(elementSpec);
         }
-        return domainServiceFacet.getNatureOfService() == NatureOfService.VIEW_MENU_ONLY ||
-               domainServiceFacet.getNatureOfService() == NatureOfService.VIEW;
+        final Class<?> correspondingClass = specification.getCorrespondingClass();
+        return correspondingClass == void.class || correspondingClass == Void.class;
     }
 
     private ModelImpl newModel(final String description) {