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) {