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/11 11:28:16 UTC

[08/11] isis git commit: ISIS-1237: renamed api-docs/index.html to swagger-ui/index.htm; updated about/index.html; refactoring and extending the main service

ISIS-1237: renamed api-docs/index.html to swagger-ui/index.htm; updated about/index.html; refactoring and extending the main service


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

Branch: refs/heads/master
Commit: 3d9f8fe035822d8cb0ad81bca1b5d7538fbdcb76
Parents: 53ead49
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Thu Dec 10 14:30:24 2015 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Thu Dec 10 14:30:24 2015 +0000

----------------------------------------------------------------------
 .../isis/applib/annotation/NatureOfService.java |  22 +-
 .../services/i18n/TranslatableString.java       |   1 +
 .../services/swagger/SwaggerServiceDefault.java |  24 +-
 .../services/swagger/internal/Caching.java      |  48 ++
 .../swagger/internal/SwaggerSpecGenerator.java  | 472 ++++++++---------
 .../services/swagger/internal/Util.java         | 164 ++++++
 .../services/swagger/internal/example.json      | 515 -------------------
 .../webapp/src/main/webapp/about/index.html     |  13 +-
 .../webapp/src/main/webapp/api-docs/index.html  | 122 -----
 .../src/main/webapp/swagger-ui/index.html       | 122 +++++
 10 files changed, 592 insertions(+), 911 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/core/applib/src/main/java/org/apache/isis/applib/annotation/NatureOfService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/NatureOfService.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/NatureOfService.java
index b37c2bc..0502d80 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/NatureOfService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/NatureOfService.java
@@ -56,6 +56,26 @@ public enum NatureOfService {
      * Equivalent to annotating all actions with both (the now deprecated) {@link org.apache.isis.applib.annotation.NotInServiceMenu} and {@link org.apache.isis.applib.annotation.NotContributed} annotations).
      * </p>
      */
-    DOMAIN
+    DOMAIN;
+
+    boolean isViewRestOnly() {
+        return this == VIEW_REST_ONLY;
+    }
+    boolean isView() {
+        return this == VIEW;
+    }
+    boolean isViewMenuOnly() {
+        return this == VIEW_MENU_ONLY;
+    }
+    boolean isViewContributionsOnly() {
+        return this == VIEW_CONTRIBUTIONS_ONLY;
+    }
+    boolean isDomain() {
+        return this == DOMAIN;
+    }
+
+    boolean isViewOrViewMenuOnly() {
+        return isView() || isViewMenuOnly();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/core/applib/src/main/java/org/apache/isis/applib/services/i18n/TranslatableString.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/i18n/TranslatableString.java b/core/applib/src/main/java/org/apache/isis/applib/services/i18n/TranslatableString.java
index 5509eb5..515a2b7 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/i18n/TranslatableString.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/i18n/TranslatableString.java
@@ -200,6 +200,7 @@ public final class TranslatableString {
      *     {@link Exception#getMessage() message} when only a translatable message has been provided.
      * </p>
      */
+    @Programmatic
     public String getPattern() {
         return !isPluralForm() || number == 1 ? getSingularText() : getPluralText();
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
index c447788..c6ac0e8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
@@ -18,6 +18,10 @@
  */
 package org.apache.isis.core.metamodel.services.swagger;
 
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,13 +40,31 @@ public class SwaggerServiceDefault implements SwaggerService, SpecificationLoade
     @SuppressWarnings("unused")
     private final static Logger LOG = LoggerFactory.getLogger(SwaggerServiceDefault.class);
 
+    public static final String KEY_RESTFUL_BASE_PATH = "isis.services.swagger.restfulBasePath";
+    public static final String KEY_RESTFUL_BASE_PATH_DEFAULT = "/restful";
+
+    private String basePath;
+
+    @PostConstruct
+    public void init(final Map<String,String> properties) {
+        this.basePath = getPropertyElse(properties, KEY_RESTFUL_BASE_PATH, KEY_RESTFUL_BASE_PATH_DEFAULT);
+    }
+
+    static String getPropertyElse(final Map<String, String> properties, final String key, final String dflt) {
+        String basePath = properties.get(key);
+        if(basePath == null) {
+            basePath = dflt;
+        }
+        return basePath;
+    }
+
     @Override
     public String generateSwaggerSpec(
             final Visibility visibility,
             final Format format) {
 
         final SwaggerSpecGenerator swaggerSpecGenerator = new SwaggerSpecGenerator(specificationLoader);
-        final String swaggerSpec = swaggerSpecGenerator.generate(visibility, format);
+        final String swaggerSpec = swaggerSpecGenerator.generate(basePath, visibility, format);
         return swaggerSpec;
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Caching.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Caching.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Caching.java
new file mode 100644
index 0000000..55eb624
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Caching.java
@@ -0,0 +1,48 @@
+package org.apache.isis.core.metamodel.services.swagger.internal;
+
+import io.swagger.models.Response;
+import io.swagger.models.properties.IntegerProperty;
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ */
+enum Caching {
+    TRANSACTIONAL {
+        @Override public void withHeaders(final Response response) {
+
+        }
+    },
+    USER_INFO {
+        @Override public void withHeaders(final Response response) {
+            response
+                    .header("Cache-Control",
+                            new IntegerProperty()
+                                    ._default(3600));
+        }
+    },
+    NON_EXPIRING {
+        @Override public void withHeaders(final Response response) {
+            response
+                    .header("Cache-Control",
+                            new IntegerProperty()
+                                    ._default(86400).description(Util.roSpec("2.13")));
+        }
+    };
+
+    public abstract void withHeaders(final Response response);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/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 896d4f0..f1ca3e5 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
@@ -27,19 +27,18 @@ import com.google.common.base.Strings;
 
 import org.apache.isis.applib.annotation.ActionSemantics;
 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.mixin.MixinFacet;
 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;
 import org.apache.isis.core.metamodel.spec.SpecificationLoader;
-import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 import io.swagger.models.Info;
 import io.swagger.models.ModelImpl;
@@ -51,7 +50,6 @@ 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;
 import io.swagger.models.properties.MapProperty;
 import io.swagger.models.properties.ObjectProperty;
 import io.swagger.models.properties.Property;
@@ -68,16 +66,39 @@ public class SwaggerSpecGenerator {
         this.specificationLoader = specificationLoader;
     }
 
-    public String generate(final SwaggerService.Visibility visibility, final SwaggerService.Format format) {
+    public String generate(
+            final String basePath,
+            final SwaggerService.Visibility visibility,
+            final SwaggerService.Format format) {
+
         final Swagger swagger = new Swagger();
-        swagger.basePath("/restful");
+        swagger.basePath(basePath);
         swagger.info(new Info()
-                        .version("1.0.0")
-                        .title("Restful Objects"));
+                        //.version("1.0.0") // TODO: provide some way of passing the name, version etc (some sort of SPI service?)
+                        .title(visibility.name() + " API")
+        );
+
+        appendRestfulObjectsSupportingPathsAndDefinitions(swagger);
+        appendLinkModelDefinition(swagger);
 
-        appendBoilerplate(swagger);
-        appendLinkDefinitions(swagger);
+        appendServicePathsAndDefinitions(swagger, visibility);
+        appendObjectPathsAndDefinitions(swagger, visibility);
+
+        switch (format) {
+            case JSON:
+                return Json.pretty(swagger);
+            case YAML:
+                try {
+                    return Yaml.pretty().writeValueAsString(swagger);
+                } catch (JsonProcessingException e) {
+                    throw new RuntimeException(e);
+                }
+            default:
+                throw new IllegalArgumentException("Unrecognized format: " + format);
+        }
+    }
 
+    void appendServicePathsAndDefinitions(final Swagger swagger, final SwaggerService.Visibility visibility) {
         final Collection<ObjectSpecification> allSpecs = specificationLoader.allSpecifications();
         for (final ObjectSpecification serviceSpec :  allSpecs) {
 
@@ -94,146 +115,131 @@ public class SwaggerSpecGenerator {
                 continue;
             }
 
-            final List<ActionType> actionTypes = actionTypesFor(visibility);
-            final List<ObjectAction> serviceActions = serviceSpec.getObjectActions(
-                    actionTypes, Contributed.EXCLUDED, Filters.<ObjectAction>any());
-            if (serviceActions.isEmpty()) {
+            final List<ObjectAction> serviceActions = Util.actionsOf(serviceSpec, visibility);
+            if(serviceActions.isEmpty()) {
                 continue;
             }
-
-            final ObjectProperty serviceMembers = appendServicePath(swagger, serviceSpec);
+            appendServicePath(swagger, serviceSpec);
 
             for (final ObjectAction serviceAction : serviceActions) {
-                if (visibility.isPublic() && !isVisibleForPublic(serviceAction)) {
-                    continue;
-                }
-                appendActionTo(serviceMembers, serviceAction);
                 appendServiceActionInvokePath(swagger, serviceAction);
             }
         }
+    }
 
+    void appendObjectPathsAndDefinitions(final Swagger swagger, final SwaggerService.Visibility visibility) {
+        final Collection<ObjectSpecification> allSpecs = specificationLoader.allSpecifications();
         for (final ObjectSpecification objectSpec : allSpecs) {
 
             final DomainServiceFacet domainServiceFacet = objectSpec.getFacet(DomainServiceFacet.class);
             if (domainServiceFacet != null) {
                 continue;
             }
-
+            final MixinFacet mixinFacet = objectSpec.getFacet(MixinFacet.class);
+            if (mixinFacet != null) {
+                continue;
+            }
+            if(visibility.isPublic() && !Util.isVisibleForPublic(objectSpec)) {
+                continue;
+            }
             if(objectSpec.isAbstract()) {
                 continue;
             }
+            if(objectSpec.isValue()) {
+                continue;
+            }
+
+            final List<OneToOneAssociation> objectProperties = Util.propertiesOf(objectSpec, visibility);
+            final List<OneToManyAssociation> objectCollections = Util.collectionsOf(objectSpec, visibility);
+            final List<ObjectAction> objectActions = Util.actionsOf(objectSpec, visibility);
 
-            final List<ActionType> actionTypes = actionTypesFor(visibility);
-            final List<ObjectAction> objectActions = objectSpec.getObjectActions(
-                    actionTypes, Contributed.INCLUDED, Filters.<ObjectAction>any());
-            if (objectActions.isEmpty()) {
+            if(objectProperties.isEmpty() && objectCollections.isEmpty()) {
                 continue;
             }
+            final ModelImpl isisModel = appendObjectPathAndModelDefinitions(swagger, objectSpec);
+            appendObjectModel(isisModel, objectProperties, objectCollections);
 
-            final ObjectProperty objectMembers = appendObjectPath(swagger, objectSpec);
+            for (final OneToManyAssociation objectCollection : objectCollections) {
+                appendCollectionTo(swagger, objectCollection);
+            }
 
             for (final ObjectAction objectAction : objectActions) {
-                if (visibility.isPublic() && !isVisibleForPublic(objectAction)) {
-                    continue;
-                }
-                appendActionTo(objectMembers, objectAction);
                 appendObjectActionInvokePath(swagger, objectAction);
             }
         }
-
-        switch (format) {
-            case JSON:
-                return Json.pretty(swagger);
-            case YAML:
-                try {
-                    return Yaml.pretty().writeValueAsString(swagger);
-                } catch (JsonProcessingException e) {
-                    throw new RuntimeException(e);
-                }
-            default:
-                throw new IllegalArgumentException("Unrecognized format: " + format);
-        }
     }
 
-    void appendBoilerplate(final Swagger swagger) {
-        appendBoilerplatePaths(swagger);
-        appendBoilerplateDefinitions(swagger);
-    }
+    void appendRestfulObjectsSupportingPathsAndDefinitions(final Swagger swagger) {
+
+        final String tag = "> restful objects supporting resources";
 
-    void appendBoilerplatePaths(final Swagger swagger) {
         swagger.path("/",
                 new Path()
                         .get(new Operation()
-                                .tag("boilerplate")
-                                .description(roSpec("5.1"))
+                                .tag(tag)
+                                .description(Util.roSpec("5.1"))
                                 .produces("application/json")
                                 .produces("application/json;profile=urn:org.restfulobjects:repr-types/home-page")
                                 .response(200,
                                         newResponse(Caching.NON_EXPIRING)
                                                 .description("OK")
-                                                .schema(new RefProperty("#/definitions/home-page"))
-                                )))
-                .path("/user",
-                        new Path()
-                                .get(new Operation()
-                                        .tag("boilerplate")
-                                        .description(roSpec("6.1"))
-                                        .produces("application/json")
-                                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/user")
-                                        .response(200,
-                                                newResponse(Caching.USER_INFO)
-                                                        .description("OK")
-                                                        .schema(new RefProperty("#/definitions/user"))
-                                        )))
-                .path("/services",
+                                                .schema(new RefProperty("#/definitions/RestfulObjectsSupportingHomePageModel"))
+                                )));
+        swagger.addDefinition("RestfulObjectsSupportingHomePageModel",
+                newModel(Util.roSpec("5.2")));
+
+        swagger.path("/user",
+                    new Path()
+                            .get(new Operation()
+                                    .tag(tag)
+                                    .description(Util.roSpec("6.1"))
+                                    .produces("application/json")
+                                    .produces("application/json;profile=urn:org.restfulobjects:repr-types/user")
+                                    .response(200,
+                                            newResponse(Caching.USER_INFO)
+                                                    .description("OK")
+                                                    .schema(new RefProperty("#/definitions/RestfulObjectsSupportingUserModel"))
+                                    )));
+        swagger.addDefinition("RestfulObjectsSupportingUserModel",
+                newModel(Util.roSpec("6.2"))
+                        .property("userName", stringProperty())
+                        .property("roles", arrayOfStrings())
+                        .property("links", arrayOfLinks())
+                        .required("userName")
+                        .required("roles"));
+
+        swagger.path("/services",
                         new Path()
                                 .get(new Operation()
-                                        .tag("boilerplate")
-                                        .description(roSpec("7.1"))
+                                        .tag(tag)
+                                        .description(Util.roSpec("7.1"))
                                         .produces("application/json")
                                         .produces("application/json;profile=urn:org.restfulobjects:repr-types/services")
                                         .response(200,
                                                 newResponse(Caching.USER_INFO)
                                                         .description("OK")
-                                                        .schema(new RefProperty("#/definitions/services"))
-                                        )))
+                                                        .schema(new RefProperty("#/definitions/RestfulObjectsSupportingServicesModel"))
+                                        )));
+        swagger.addDefinition("RestfulObjectsSupportingServicesModel",
+                newModel(Util.roSpec("7.2"))
+                        .property("value", arrayOfLinks())
+                        .required("userName")
+                        .required("roles"));
 
-                .path("/version",
+        swagger.path("/version",
                         new Path()
                                 .get(new Operation()
-                                        .tag("boilerplate")
-                                        .description(roSpec("8.1"))
+                                        .tag(tag)
+                                        .description(Util.roSpec("8.1"))
                                         .produces("application/json")
-                                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/version")
+                                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/RestfulObjectsSupportingServicesModel")
                                         .response(200,
                                                 newResponse(Caching.NON_EXPIRING)
                                                         .description("OK")
-                                                        .schema(new RefProperty("#/definitions/version"))
+                                                        .schema(new ObjectProperty())
                                         )));
-    }
-
-    void appendBoilerplateDefinitions(final Swagger swagger) {
-        swagger.addDefinition("home-page",
-                newModel(roSpec("5.2")));
-
-        swagger.addDefinition("user",
-                newModel(roSpec("6.2"))
-                        .property("userName", stringProperty())
-                        .property("roles", arrayOfStrings())
-                        .property("links", arrayOfLinksGetOnly())
-                        .required("userName")
-                        .required("roles")
-        );
-
-        swagger.addDefinition("services",
-                newModel(roSpec("7.2"))
-                        .property("value", arrayOfLinksGetOnly())
-                        .required("userName")
-                        .required("roles")
-        );
-
-        swagger.addDefinition("version",
-                newModel(roSpec("8.2"))
+        swagger.addDefinition("RestfulObjectsSupportingServicesModel",
+                newModel(Util.roSpec("8.2"))
                         .property("specVersion", stringProperty())
                         .property("implVersion", stringProperty())
                         .property("optionalCapabilities",
@@ -245,13 +251,11 @@ public class SwaggerSpecGenerator {
                                         .property("protoPersistentObjects", stringProperty())
                         )
                         .required("userName")
-                        .required("roles")
-        );
+                        .required("roles"));
     }
 
-    void appendLinkDefinitions(final Swagger swagger) {
-
-        swagger.addDefinition("link",
+    void appendLinkModelDefinition(final Swagger swagger) {
+        swagger.addDefinition("LinkModel",
                 new ModelImpl()
                     .type("object")
                     .property("rel", stringProperty())
@@ -265,105 +269,109 @@ public class SwaggerSpecGenerator {
                     .required("method")
         );
 
-        swagger.addDefinition("link-get-only",
-                new ModelImpl()
-                    .type("object")
-                    .property("rel", stringProperty())
-                    .property("href", stringProperty())
-                    .property("title", stringProperty())
-                    .property("method", stringPropertyEnum("GET"))
-                    .property("type", stringProperty())
-                    .required("rel")
-                    .required("href")
-                    .required("method")
-        );
     }
 
-    ObjectProperty appendServicePath(final Swagger swagger, final ObjectSpecification objectSpec) {
+    void 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);
 
+        final String serviceModelDefinition = serviceId + "Model";
         path.get(
                 new Operation()
                         .tag(serviceId)
-                        .description(roSpec("15.1"))
+                        .description(Util.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)))
+                                        .schema(new RefProperty("#/definitions/" + serviceModelDefinition)))
         );
 
-        final ObjectProperty serviceMembers = new ObjectProperty();
-        final ModelImpl serviceRepr =
-                newModel(roSpec("15.1.2") + ": representation of " + serviceId)
+        final ModelImpl model =
+                newModel(Util.roSpec("15.1.2") + ": representation of " + serviceId)
                         .property("title", stringProperty())
                         .property("serviceId", stringProperty()._default(serviceId))
-                        .property("members", serviceMembers);
+                        .property("members", new ObjectProperty());
 
-        swagger.addDefinition("service-" + serviceId, serviceRepr);
-        return serviceMembers;
+        swagger.addDefinition(serviceModelDefinition, model);
     }
 
-    ObjectProperty appendObjectPath(final Swagger swagger, final ObjectSpecification objectSpec) {
+    ModelImpl appendObjectPathAndModelDefinitions(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);
 
+        final String isisModelDefinition = objectType + "Model";
+        final String restfulObjectsModelDefinition = objectType + "RestfulObjectsModel";
+        final String tag = objectType.startsWith("org.apache.isis")? "> apache isis internals": objectType;
+        final Operation operation = new Operation();
         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)))
-        );
+                operation);
+        operation
+                .tag(tag)
+                .description(Util.roSpec("14.1"))
+                .parameter(
+                    new PathParameter()
+                        .name("objectId")
+                        .type("string"))
+                .produces("application/json;profile=urn:org.apache.isis/v1")
+                .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
+                .produces("application/json;profile=urn:org.restfulobjects:repr-types/object");
+
+
+        // per https://github.com/swagger-api/swagger-spec/issues/146, swagger 2.0 doesn't support multiple
+        // modelled representations per path and response code;
+        // in particular cannot associate representation/model with Accept header ('produces(...) method)
+        if (false) {
+            operation.response(200,
+                    newResponse(Caching.TRANSACTIONAL)
+                            .description("if Accept: application/json;profile=urn:org.restfulobjects:repr-types/object")
+                            .schema(new RefProperty("#/definitions/" + restfulObjectsModelDefinition)));
+
+            final ModelImpl roSpecModel =
+                    newModel(Util.roSpec("14.4") + ": representation of " + objectType)
+                            .property("title", stringProperty())
+                            .property("domainType", stringProperty()._default(objectType))
+                            .property("instanceId", stringProperty())
+                            .property("members", new ObjectProperty());
+            swagger.addDefinition(restfulObjectsModelDefinition, roSpecModel);
+        }
 
-        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);
+        operation
+                .response(200,
+                        newResponse(Caching.TRANSACTIONAL)
+                                .description("if Accept: application/json;profile=urn:org.apache.isis/v1")
+                                .schema(new RefProperty("#/definitions/"
+                                        + isisModelDefinition)));
 
-        swagger.addDefinition("object-" + objectType, serviceRepr);
-        return serviceMembers;
-    }
 
-    private String objectTypeFor(final ObjectSpecification objectSpec) {
-        return objectSpec.getFacet(ObjectSpecIdFacet.class).value().asString();
+        final ModelImpl isisModel = new ModelImpl();
+        swagger.addDefinition(isisModelDefinition, isisModel);
+
+        // return so can be appended to
+        return isisModel;
     }
 
-    void appendActionTo(final ObjectProperty serviceMembers, final ObjectAction serviceAction) {
-        String serviceActionId = serviceAction.getId();
+    // UNUSED
+    void appendServiceActionPromptTo(final ObjectProperty serviceMembers, final ObjectAction action) {
+        String actionId = action.getId();
 
-        // within the services representation itself
-        serviceMembers.property(serviceActionId,
+        serviceMembers.property(actionId,
                 new ObjectProperty()
-                        .property("id", stringPropertyEnum(serviceActionId))
+                        .property("id", stringPropertyEnum(actionId))
                         .property("memberType", stringPropertyEnum("action"))
                         .property("links",
                                 new ObjectProperty()
                                         .property("rel", stringPropertyEnum( String.format(
-                                                "urn:org.restfulobjects:rels/details;action=%s", serviceActionId)))
+                                                "urn:org.restfulobjects:rels/details;action=%s", actionId)))
                                         .property("href", stringPropertyEnum(String.format(
-                                                "actions/%s", serviceActionId))))
+                                                "actions/%s", actionId))))
                         .property("method", stringPropertyEnum("GET"))
                         .property("type", stringPropertyEnum(
                                 "application/json;profile=urn:org.restfulobjects:repr-types/object-action"))
@@ -385,11 +393,11 @@ public class SwaggerSpecGenerator {
         final Operation invokeOperation =
                 new Operation()
                         .tag(serviceId)
-                        .description(roSpec("19.1") + ": (invoke) resource of " + serviceId + "#" + actionId)
-                        .produces("application/json")
-                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result")
+                        .description(Util.roSpec("19.1") + ": (invoke) resource of " + serviceId + "#" + actionId)
                         .produces("application/json;profile=urn:org.apache.isis/v1")
-                        .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true");
+                        .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
+                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result")
+                ;
 
         final ActionSemantics.Of semantics = serviceAction.getSemantics();
         if(semantics.isSafeInNature()) {
@@ -400,7 +408,7 @@ public class SwaggerSpecGenerator {
                         .parameter(
                                 new QueryParameter()
                                         .name(parameter.getId())
-                                        .description(roSpec("2.9.1") + (!Strings.isNullOrEmpty(parameter.getDescription())? (": " + parameter.getDescription()) : ""))
+                                        .description(Util.roSpec("2.9.1") + (!Strings.isNullOrEmpty(parameter.getDescription())? (": " + parameter.getDescription()) : ""))
                                         .required(false)
                                         .type("string")
                         );
@@ -408,7 +416,7 @@ public class SwaggerSpecGenerator {
             if(!parameters.isEmpty()) {
                 invokeOperation.parameter(new QueryParameter()
                         .name("x-isis-querystring")
-                        .description(roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
+                        .description(Util.roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
                         .required(false)
                         .type("string"));
             }
@@ -469,15 +477,14 @@ public class SwaggerSpecGenerator {
         final Operation invokeOperation =
                 new Operation()
                         .tag(objectType)
-                        .description(roSpec("19.1") + ": (invoke) resource of " + objectType + "#" + actionId)
+                        .description(Util.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");
+                        .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
+                        .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result");
 
         final ActionSemantics.Of semantics = objectAction.getSemantics();
         if(semantics.isSafeInNature()) {
@@ -488,7 +495,7 @@ public class SwaggerSpecGenerator {
                         .parameter(
                                 new QueryParameter()
                                         .name(parameter.getId())
-                                        .description(roSpec("2.9.1") + (!Strings.isNullOrEmpty(parameter.getDescription())? (": " + parameter.getDescription()) : ""))
+                                        .description(Util.roSpec("2.9.1") + (!Strings.isNullOrEmpty(parameter.getDescription())? (": " + parameter.getDescription()) : ""))
                                         .required(false)
                                         .type("string")
                         );
@@ -496,7 +503,7 @@ public class SwaggerSpecGenerator {
             if(!parameters.isEmpty()) {
                 invokeOperation.parameter(new QueryParameter()
                         .name("x-isis-querystring")
-                        .description(roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
+                        .description(Util.roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
                         .required(false)
                         .type("string"));
             }
@@ -542,8 +549,17 @@ public class SwaggerSpecGenerator {
                 );
     }
 
+    void appendCollectionTo(final Swagger members, final OneToManyAssociation serviceAction) {
 
-    private String roSpecForResponseOf(final ObjectAction action) {
+    }
+
+    void appendObjectModel(
+            final ModelImpl swagger,
+            final List<OneToOneAssociation> objectProperties, final List<OneToManyAssociation> objectCollections) {
+
+    }
+
+    static String roSpecForResponseOf(final ObjectAction action) {
         final ActionSemantics.Of semantics = action.getSemantics();
         switch (semantics) {
             case SAFE_AND_REQUEST_CACHEABLE:
@@ -557,62 +573,31 @@ public class SwaggerSpecGenerator {
         }
     }
 
-    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(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);
-        }
-        final Class<?> correspondingClass = specification.getCorrespondingClass();
-        return correspondingClass == void.class || correspondingClass == Void.class;
-    }
-
-    private ModelImpl newModel(final String description) {
+    static ModelImpl newModel(final String description) {
         return new ModelImpl()
                 .description(description)
                 .type("object")
-                .property("links", arrayOfLinksGetOnly())
+                .property("links", arrayOfLinks())
                 .property("extensions", new MapProperty())
                 .required("links")
                 .required("extensions");
     }
 
     // TODO: this is horrid, there ought to be a facet we can call instead...
-    String serviceIdFor(final ObjectSpecification serviceSpec) {
+    static String serviceIdFor(final ObjectSpecification serviceSpec) {
         Object tempServiceInstance = InstanceUtil.createInstance(serviceSpec.getCorrespondingClass());
         return ServiceUtil.id(tempServiceInstance);
     }
 
-    StringProperty stringProperty() {
+    static String objectTypeFor(final ObjectSpecification objectSpec) {
+        return objectSpec.getFacet(ObjectSpecIdFacet.class).value().asString();
+    }
+
+    static StringProperty stringProperty() {
         return new StringProperty();
     }
 
-    StringProperty stringPropertyEnum(String... enumValues) {
+    static StringProperty stringPropertyEnum(String... enumValues) {
         StringProperty stringProperty = stringProperty();
         stringProperty._enum(Arrays.asList(enumValues));
         if(enumValues.length >= 1) {
@@ -621,66 +606,17 @@ public class SwaggerSpecGenerator {
         return stringProperty;
     }
 
-    ArrayProperty arrayOfLinksGetOnly() {
+    static ArrayProperty arrayOfLinks() {
         return new ArrayProperty()
-                .items(new RefProperty("#/definitions/link-get-only"));
+                .items(new RefProperty("#/definitions/LinkModel"));
     }
 
-    ArrayProperty arrayOfStrings() {
+    static ArrayProperty arrayOfStrings() {
         return new ArrayProperty().items(stringProperty());
     }
 
-    private Response newResponse(final Caching caching) {
-        return withCachingHeaders(new Response(), caching);
+    static Response newResponse(final Caching caching) {
+        return Util.withCachingHeaders(new Response(), caching);
     }
 
-    enum Caching {
-        TRANSACTIONAL {
-            @Override public void withHeaders(final Response response) {
-
-            }
-        },
-        USER_INFO {
-            @Override public void withHeaders(final Response response) {
-                response
-                        .header("Cache-Control",
-                                new IntegerProperty()
-                                        ._default(3600));
-            }
-        },
-        NON_EXPIRING {
-            @Override public void withHeaders(final Response response) {
-                response
-                        .header("Cache-Control",
-                                new IntegerProperty()
-                                        ._default(86400).description(roSpec("2.13")));
-            }
-        };
-
-        public abstract void withHeaders(final Response response);
-    }
-
-    private static String roSpec(final String section) {
-        return "RO Spec v1.0, section " + section;
-    }
-
-    private Response withCachingHeaders(final Response response, final Caching caching) {
-        caching.withHeaders(response);
-
-        return response;
-    }
-
-    private List<ActionType> actionTypesFor(final SwaggerService.Visibility visibility) {
-        switch (visibility) {
-        case PUBLIC:
-            return Arrays.asList(ActionType.USER);
-        case PRIVATE:
-            return Arrays.asList(ActionType.USER);
-        case PRIVATE_WITH_PROTOTYPING:
-            return Arrays.asList(ActionType.USER, ActionType.EXPLORATION, ActionType.PROTOTYPE, ActionType.DEBUG);
-        }
-        throw new IllegalArgumentException("Unrecognized type '" + visibility + "'");
-    }
-
-
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Util.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Util.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Util.java
new file mode 100644
index 0000000..4ab66e2
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Util.java
@@ -0,0 +1,164 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.services.swagger.internal;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.filter.Filters;
+import org.apache.isis.applib.services.swagger.SwaggerService;
+import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+
+import io.swagger.models.Response;
+
+public final class Util {
+
+    private Util(){}
+
+    static 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;
+    }
+
+    static boolean isVisibleForPublic(final ObjectAssociation objectAssociation) {
+        final ObjectSpecification specification = objectAssociation.getSpecification();
+        return isVisibleForPublic(specification);
+    }
+
+    static boolean isVisibleForPublic(final ObjectSpecification specification) {
+        if (specification == null) {
+            return true;
+        }
+        if(specification.isViewModel()) {
+            return true;
+        }
+        if(specification.isValue()) {
+            return true;
+        }
+        if(specification.isParentedOrFreeCollection()) {
+            TypeOfFacet typeOfFacet = specification.getFacet(TypeOfFacet.class);
+            if(typeOfFacet != null) {
+                ObjectSpecification elementSpec = typeOfFacet.valueSpec();
+                return isVisibleForPublic(elementSpec);
+            }
+        }
+
+        final Class<?> correspondingClass = specification.getCorrespondingClass();
+        return  Collection.class.isAssignableFrom(correspondingClass) ||
+                correspondingClass.isArray() ||
+                correspondingClass == void.class ||
+                correspondingClass == Void.class;
+    }
+
+    static Filter<ObjectAssociation> associationsWith(final SwaggerService.Visibility visibility) {
+        return new Filter<ObjectAssociation>() {
+          @Override
+          public boolean accept(final ObjectAssociation objectAssociation) {
+              return !visibility.isPublic() || isVisibleForPublic(objectAssociation);
+          }
+      };
+    }
+
+    static List<OneToOneAssociation> propertiesOf(
+            final ObjectSpecification objectSpecification,
+            final SwaggerService.Visibility visibility) {
+        return associationsOf(objectSpecification, ObjectAssociation.Filters.PROPERTIES, visibility);
+    }
+
+    static List<OneToManyAssociation> collectionsOf(
+            final ObjectSpecification objectSpecification,
+            final SwaggerService.Visibility visibility) {
+        return associationsOf(objectSpecification, ObjectAssociation.Filters.COLLECTIONS, visibility);
+    }
+
+    static <T extends ObjectAssociation> List<T> associationsOf(
+            final ObjectSpecification objectSpecification,
+            final Filter<ObjectAssociation> associationFilter, final SwaggerService.Visibility visibility) {
+        @SuppressWarnings("rawtypes")
+        final List<ObjectAssociation> list =
+                objectSpecification.getAssociations(
+                        Contributed.INCLUDED,
+                        Filters.and(
+                                associationFilter,
+                                associationsWith(visibility)
+                        ));
+
+        return cast(list);
+    }
+
+    @SuppressWarnings("unchecked")
+    static <T> List<T> cast(final List list) {
+        return list;
+    }
+
+    static List<ObjectAction> actionsOf(
+            final ObjectSpecification objectSpec,
+            final SwaggerService.Visibility visibility) {
+        final List<ActionType> actionTypes = actionTypesFor(visibility);
+
+        return objectSpec.getObjectActions(actionTypes, Contributed.INCLUDED, new Filter<ObjectAction>() {
+            @Override
+            public boolean accept(final ObjectAction objectAction) {
+                return !visibility.isPublic() || isVisibleForPublic(objectAction);
+            }
+        });
+    }
+
+    static String roSpec(final String section) {
+        return "RO Spec v1.0, section " + section;
+    }
+
+    static Response withCachingHeaders(final Response response, final Caching caching) {
+        caching.withHeaders(response);
+
+        return response;
+    }
+
+    static List<ActionType> actionTypesFor(final SwaggerService.Visibility visibility) {
+        switch (visibility) {
+        case PUBLIC:
+            return Arrays.asList(ActionType.USER);
+        case PRIVATE:
+            return Arrays.asList(ActionType.USER);
+        case PRIVATE_WITH_PROTOTYPING:
+            return Arrays.asList(ActionType.USER, ActionType.EXPLORATION, ActionType.PROTOTYPE, ActionType.DEBUG);
+        }
+        throw new IllegalArgumentException("Unrecognized type '" + visibility + "'");
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/example.json
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/example.json b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/example.json
deleted file mode 100644
index 7036c06..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/example.json
+++ /dev/null
@@ -1,515 +0,0 @@
-{
-  "swagger": "2.0",
-  "info": {
-    "version": "1.0.0",
-    "title": "Restful Objects"
-  },
-  "paths": {
-    "/": {
-      "get": {
-        "description": "Home page",
-        "produces": [
-          "application/json"
-        ],
-        "responses": {
-          "200": {
-            "description": "OK",
-            "schema": {
-              "type": "object",
-              "required": [
-                "links"
-              ],
-              "properties": {
-                "links": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/definitions/LinkRepresentation"
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    },
-    "/services": {
-      "get": {
-        "description": "Services",
-        "produces": [
-          "application/json"
-        ],
-        "responses": {
-          "200": {
-            "description": "OK",
-            "schema": {
-              "type": "object",
-              "required": [
-                "value",
-                "links"
-              ],
-              "properties": {
-                "value": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/definitions/LinkRepresentation"
-                  }
-                },
-                "links": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/definitions/LinkRepresentation"
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    },
-    "/services/SimpleObjects": {
-      "get": {
-        "description": "SimpleObjects service",
-        "produces": [
-          "application/json"
-        ],
-        "responses": {
-          "200": {
-            "description": "OK",
-            "schema": {
-              "$ref": "#/definitions/ServiceRepresentation"
-            }
-          }
-        }
-      }
-    },
-    "/services/SimpleObjects/actions/findByName": {
-      "get": {
-        "description": "SimpleObjects findByName action",
-        "produces": [
-          "application/json"
-        ],
-        "responses": {
-          "200": {
-            "description": "OK",
-            "schema": {
-              "$ref": "#/definitions/ActionPromptRepresentation"
-            }
-          }
-        }
-      }
-    },
-    "/services/SimpleObjects/actions/findByName/invoke": {
-      "get": {
-        "description": "SimpleObjects findByName invocation result",
-        "consumes": [
-          "application/json"
-        ],
-        "produces": [
-          "application/json;profile=\"urn:org.restfulobjects/repr-types/action-result\"",
-          "application/json;profile=\"urn:org.apache.isis/v1\"",
-          "application/json;profile=\"urn:org.apache.isis/v1\";suppress=\"true\""
-        ],
-        "responses": {
-          "200": {
-            "description": "All objects matching name",
-            "schema": {
-              "$ref": "#/definitions/ActionInvocationRepresentationOfList"
-            }
-          }
-        }
-      }
-    },
-    "/objects/simple.SimpleObject/{id}": {
-      "get": {
-        "description": "representation of simple.SimpleObject",
-        "parameters": [
-          {
-            "in": "path",
-            "name": "id",
-            "required": true,
-            "type": "string"
-          }
-        ],
-        "produces": [
-          "application/json;profile=\"urn:org.restfulobjects/repr-types/object\"",
-          "application/json;profile=\"urn:org.apache.isis/v1\";repr-type=\"object\""
-        ],
-        "responses": {
-          "200": {
-            "description": "OK",
-            "schema": {
-              "$ref": "#/definitions/ObjectRepresentation"
-            }
-          }
-        }
-      }
-    }
-  },
-  "definitions": {
-    "ServiceRepresentation": {
-      "type": "object",
-      "required": [
-        "links",
-        "extensions",
-        "title",
-        "serviceId"
-      ],
-      "properties": {
-        "links": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/LinkRepresentation"
-          }
-        },
-        "extensions": {
-          "$ref": "#/definitions/ServiceOrObjectExtensionsRepresentation"
-        },
-        "title": {
-          "type": "string"
-        },
-        "serviceId": {
-          "type": "string"
-        },
-        "members": {
-          "type": "object",
-          "required": [
-            "listAll",
-            "findByName",
-            "create"
-          ],
-          "properties": {
-            "listAll": {
-              "$ref": "#/definitions/ActionRepresentation"
-            },
-            "findByName": {
-              "$ref": "#/definitions/ActionRepresentation"
-            },
-            "create": {
-              "$ref": "#/definitions/ActionRepresentation"
-            }
-          }
-        }
-      }
-    },
-    "ObjectRepresentation": {
-      "type": "object",
-      "required": [
-        "links",
-        "extensions",
-        "title",
-        "domainType",
-        "instanceId",
-        "members"
-      ],
-      "properties": {
-        "links": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/LinkRepresentation"
-          }
-        },
-        "extensions": {
-          "$ref": "#/definitions/ServiceOrObjectExtensionsRepresentation"
-        },
-        "title": {
-          "type": "string"
-        },
-        "domainType": {
-          "type": "string"
-        },
-        "instanceId": {
-          "type": "string"
-        },
-        "members": {
-          "type": "object",
-          "required": [
-            "name",
-            "versionSequence",
-            "downloadJdoMetadata",
-            "updateName"
-          ],
-          "properties": {
-            "name": {
-              "type": "object",
-              "required": [
-                "id",
-                "memberType",
-                "links",
-                "value",
-                "extensions"
-              ],
-              "properties": {
-                "id": {
-                  "type": "string"
-                },
-                "memberType": {
-                  "type": "string",
-                  "default": "property"
-                },
-                "links": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/definitions/LinkRepresentation"
-                  }
-                },
-                "value": {
-                  "type": "string"
-                },
-                "disabledReason": {
-                  "type": "string"
-                },
-                "extensions": {
-                  "type": "object"
-                }
-              }
-            },
-            "versionSequence": {
-              "type": "object",
-              "required": [
-                "id",
-                "memberType",
-                "links",
-                "value",
-                "format",
-                "extensions"
-              ],
-              "properties": {
-                "id": {
-                  "type": "string"
-                },
-                "memberType": {
-                  "type": "string",
-                  "default": "property"
-                },
-                "links": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/definitions/LinkRepresentation"
-                  }
-                },
-                "value": {
-                  "type": "integer"
-                },
-                "format": {
-                  "type": "string"
-                },
-                "disabledReason": {
-                  "type": "string"
-                },
-                "extensions": {
-                  "type": "object"
-                }
-              }
-            },
-            "downloadJdoMetadata": {
-              "$ref": "#/definitions/ActionRepresentation"
-            },
-            "updateName": {
-              "$ref": "#/definitions/ActionRepresentation"
-            }
-          }
-        }
-      }
-    },
-    "ActionPromptRepresentation": {
-      "type": "object",
-      "required": [
-        "id",
-        "memberType",
-        "links",
-        "extensions",
-        "parameters"
-      ],
-      "properties": {
-        "id": {
-          "type": "string"
-        },
-        "memberType": {
-          "type": "string"
-        },
-        "links": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/LinkRepresentation"
-          }
-        },
-        "extensions": {
-          "type": "object",
-          "required": [
-            "actionType",
-            "actionSemantics"
-          ],
-          "properties": {
-            "actionType": {
-              "type": "string"
-            },
-            "actionSemantics": {
-              "type": "string",
-              "enum": [
-                "safe",
-                "idempotent",
-                "non_idempotent"
-              ]
-            }
-          }
-        },
-        "parameters": {
-          "type": "object",
-          "required": [
-            "name"
-          ],
-          "properties": {
-            "name": {
-              "$ref": "#/definitions/ActionParameterRepresentation"
-            }
-          }
-        }
-      }
-    },
-    "ServiceOrObjectExtensionsRepresentation": {
-      "type": "object",
-      "required": [
-        "oid",
-        "isService",
-        "isPersistent"
-      ],
-      "properties": {
-        "oid": {
-          "type": "string"
-        },
-        "isService": {
-          "type": "boolean"
-        },
-        "isPersistent": {
-          "type": "boolean"
-        }
-      }
-    },
-    "ActionRepresentation": {
-      "type": "object",
-      "required": [
-        "id",
-        "memberType",
-        "links"
-      ],
-      "properties": {
-        "id": {
-          "type": "string"
-        },
-        "memberType": {
-          "type": "string",
-          "default": "action"
-        },
-        "links": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/LinkRepresentation"
-          }
-        }
-      }
-    },
-    "ActionParameterRepresentation": {
-      "type": "object",
-      "required": [
-        "num",
-        "id",
-        "name",
-        "description"
-      ],
-      "properties": {
-        "num": {
-          "type": "integer"
-        },
-        "id": {
-          "type": "string"
-        },
-        "name": {
-          "type": "string"
-        },
-        "description": {
-          "type": "string"
-        }
-      }
-    },
-    "ActionInvocationRepresentationOfList": {
-      "type": "object",
-      "required": [
-        "links",
-        "resulttype",
-        "result"
-      ],
-      "properties": {
-        "links": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/LinkRepresentation"
-          }
-        },
-        "resulttype": {
-          "type": "string",
-          "default": "list"
-        },
-        "result": {
-          "type": "object",
-          "required": [
-            "value",
-            "links",
-            "extensions"
-          ],
-          "properties": {
-            "value": {
-              "type": "array",
-              "items": {
-                "$ref": "#/definitions/LinkRepresentation"
-              }
-            },
-            "links": {
-              "type": "array",
-              "items": {
-                "$ref": "#/definitions/LinkRepresentation"
-              }
-            },
-            "extensions": {
-              "type": "object"
-            }
-          }
-        }
-      }
-    },
-    "LinkRepresentation": {
-      "type": "object",
-      "required": [
-        "rel",
-        "href",
-        "method"
-      ],
-      "properties": {
-        "rel": {
-          "type": "string",
-          "description": "relationship of this Link"
-        },
-        "href": {
-          "type": "string"
-        },
-        "title": {
-          "type": "string"
-        },
-        "method": {
-          "type": "string",
-          "enum": [
-            "GET",
-            "POST",
-            "PUT",
-            "DELETE"
-          ]
-        },
-        "type": {
-          "type": "string"
-        },
-        "arguments": {
-          "type": "object"
-        }
-      }
-    }
-  }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/example/application/simpleapp/webapp/src/main/webapp/about/index.html
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/webapp/src/main/webapp/about/index.html b/example/application/simpleapp/webapp/src/main/webapp/about/index.html
index 070651a..b14a4b3 100644
--- a/example/application/simpleapp/webapp/src/main/webapp/about/index.html
+++ b/example/application/simpleapp/webapp/src/main/webapp/about/index.html
@@ -81,13 +81,18 @@ th, td {
                 <li>
                     <p>
                         <b>
-                            <a href="restful/">restful/</a>
+                            <a href="swagger-ui/index.html">swagger-ui/</a>
                         </b>
                     </p>
                     <p>
-                        provides access to a RESTful API conformant with the
-                        <a href="http://restfulobjects.org">Restful Objects</a> spec</td>.  This is part of Apache Isis Core.  The
-                        implementation technology is JBoss RestEasy.
+                        provides the Swagger UI access to RESTful API, consuming dynamically generated Swagger
+                        specification files.  There are three versions of this API: <a href="restful/swagger/public">public</a> (third-party) use, for <a href="restful/swagger/private">private</a> (internal) use, and extended version of the private API
+                        that includes <a href="restful/swagger/prototyping">prototyping</a> actions.
+                    </p>
+                    <p>The RESTful API can return both simple representations (suitable for use within custom apps),
+                        and also a richer hypermedia API conformant with the
+                        <a href="http://restfulobjects.org">Restful Objects</a> spec.  The HTTP <code>Accept</code> header
+                        is used to select which representation is required.
                     </p>
                 </li>
             </ul>

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/example/application/simpleapp/webapp/src/main/webapp/api-docs/index.html
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/webapp/src/main/webapp/api-docs/index.html b/example/application/simpleapp/webapp/src/main/webapp/api-docs/index.html
deleted file mode 100644
index 7ecbcb1..0000000
--- a/example/application/simpleapp/webapp/src/main/webapp/api-docs/index.html
+++ /dev/null
@@ -1,122 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="UTF-8">
-    <base href="../webjars/swagger-ui/2.1.3/"/>
-    <title>Swagger UI</title>
-    <link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
-    <link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
-    <link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
-    <link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
-    <link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
-    <link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
-    <link href='css/print.css' media='print' rel='stylesheet' type='text/css'/>
-    <script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
-    <script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
-    <script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
-    <script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
-    <script src='lib/handlebars-2.0.0.js' type='text/javascript'></script>
-    <script src='lib/underscore-min.js' type='text/javascript'></script>
-    <script src='lib/backbone-min.js' type='text/javascript'></script>
-    <script src='swagger-ui.js' type='text/javascript'></script>
-    <script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
-    <script src='lib/marked.js' type='text/javascript'></script>
-    <script src='lib/swagger-oauth.js' type='text/javascript'></script>
-
-    <!-- Some basic translations -->
-    <!-- <script src='lang/translator.js' type='text/javascript'></script> -->
-    <!-- <script src='lang/ru.js' type='text/javascript'></script> -->
-    <!-- <script src='lang/en.js' type='text/javascript'></script> -->
-
-    <script type="text/javascript">
-    $(function () {
-      var url = document.getElementById("input_baseUrl").selectedOptions[0].value;
-
-      // Pre load translate...
-      if(window.SwaggerTranslator) {
-        window.SwaggerTranslator.translate();
-      }
-      window.swaggerUi = new SwaggerUi({
-        url: url,
-        dom_id: "swagger-ui-container",
-        supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
-        onComplete: function(swaggerApi, swaggerUi){
-          if(typeof initOAuth == "function") {
-            initOAuth({
-              clientId: "your-client-id",
-              clientSecret: "your-client-secret-if-required",
-              realm: "your-realms",
-              appName: "your-app-name",
-              scopeSeparator: ","
-            });
-          }
-
-          if(window.SwaggerTranslator) {
-            window.SwaggerTranslator.translate();
-          }
-
-          $('pre code').each(function(i, e) {
-            hljs.highlightBlock(e)
-          });
-
-          addApiKeyAuthorization();
-        },
-        onFailure: function(data) {
-          log("Unable to Load SwaggerUI");
-        },
-        docExpansion: "none",
-        apisSorter: "alpha",
-        defaultModelRendering: 'schema',
-        showRequestHeaders: false
-      });
-
-      function addApiKeyAuthorization(){
-        var key = encodeURIComponent($('#input_apiKey')[0].value);
-        if(key && key.trim() != "") {
-            var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("api_key", key, "query");
-            window.swaggerUi.api.clientAuthorizations.add("api_key", apiKeyAuth);
-            log("added key " + key);
-        }
-      }
-
-      $('#input_apiKey').change(addApiKeyAuthorization);
-
-      // if you have an apiKey you would like to pre-populate on the page for demonstration purposes...
-      /*
-        var apiKey = "myApiKeyXXXX123456789";
-        $('#input_apiKey').val(apiKey);
-      */
-
-      window.swaggerUi.load();
-
-      function log() {
-        if ('console' in window) {
-          console.log.apply(console, arguments);
-        }
-      }
-  });
-  </script>
-</head>
-
-<body class="swagger-section">
-<div id='header'>
-    <div class="swagger-ui-wrap">
-        <a id="logo" href="http://swagger.io">swagger</a>
-        <form id='api_selector'>
-            <div class='input'>
-                <select id="input_baseUrl" name="baseUrl">
-                    <option id="private" label="private" value="/restful/swagger/private"/>
-                    <option id="public" label="public" value="/restful/swagger/public"/>
-                    <option id="prototyping" label="prototyping" value="/restful/swagger/prototyping"/>
-                </select>
-            </div>
-            <div class='input' style="display:none;"><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
-            <div class='input'><a id="explore" href="#" data-sw-translate>Explore</a></div>
-        </form>
-    </div>
-</div>
-
-<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>
-<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
-</body>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/3d9f8fe0/example/application/simpleapp/webapp/src/main/webapp/swagger-ui/index.html
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/webapp/src/main/webapp/swagger-ui/index.html b/example/application/simpleapp/webapp/src/main/webapp/swagger-ui/index.html
new file mode 100644
index 0000000..fc4d3a4
--- /dev/null
+++ b/example/application/simpleapp/webapp/src/main/webapp/swagger-ui/index.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <base href="../webjars/swagger-ui/2.1.3/"/>
+    <title>Swagger UI</title>
+    <link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
+    <link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
+    <link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
+    <link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
+    <link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
+    <link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
+    <link href='css/print.css' media='print' rel='stylesheet' type='text/css'/>
+    <script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
+    <script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
+    <script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
+    <script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
+    <script src='lib/handlebars-2.0.0.js' type='text/javascript'></script>
+    <script src='lib/underscore-min.js' type='text/javascript'></script>
+    <script src='lib/backbone-min.js' type='text/javascript'></script>
+    <script src='swagger-ui.js' type='text/javascript'></script>
+    <script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
+    <script src='lib/marked.js' type='text/javascript'></script>
+    <script src='lib/swagger-oauth.js' type='text/javascript'></script>
+
+    <!-- Some basic translations -->
+    <!-- <script src='lang/translator.js' type='text/javascript'></script> -->
+    <!-- <script src='lang/ru.js' type='text/javascript'></script> -->
+    <!-- <script src='lang/en.js' type='text/javascript'></script> -->
+
+    <script type="text/javascript">
+    $(function () {
+      var url = document.getElementById("input_baseUrl").selectedOptions[0].value;
+
+      // Pre load translate...
+      if(window.SwaggerTranslator) {
+        window.SwaggerTranslator.translate();
+      }
+      window.swaggerUi = new SwaggerUi({
+        url: url,
+        dom_id: "swagger-ui-container",
+        supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
+        onComplete: function(swaggerApi, swaggerUi){
+          if(typeof initOAuth == "function") {
+            initOAuth({
+              clientId: "your-client-id",
+              clientSecret: "your-client-secret-if-required",
+              realm: "your-realms",
+              appName: "your-app-name",
+              scopeSeparator: ","
+            });
+          }
+
+          if(window.SwaggerTranslator) {
+            window.SwaggerTranslator.translate();
+          }
+
+          $('pre code').each(function(i, e) {
+            hljs.highlightBlock(e)
+          });
+
+          addApiKeyAuthorization();
+        },
+        onFailure: function(data) {
+          log("Unable to Load SwaggerUI");
+        },
+        docExpansion: "none",
+        apisSorter: "alpha",
+        defaultModelRendering: 'schema',
+        showRequestHeaders: false
+      });
+
+      function addApiKeyAuthorization(){
+        var key = encodeURIComponent($('#input_apiKey')[0].value);
+        if(key && key.trim() != "") {
+            var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("api_key", key, "query");
+            window.swaggerUi.api.clientAuthorizations.add("api_key", apiKeyAuth);
+            log("added key " + key);
+        }
+      }
+
+      $('#input_apiKey').change(addApiKeyAuthorization);
+
+      // if you have an apiKey you would like to pre-populate on the page for demonstration purposes...
+      /*
+        var apiKey = "myApiKeyXXXX123456789";
+        $('#input_apiKey').val(apiKey);
+      */
+
+      window.swaggerUi.load();
+
+      function log() {
+        if ('console' in window) {
+          console.log.apply(console, arguments);
+        }
+      }
+  });
+  </script>
+</head>
+
+<body class="swagger-section">
+<div id='header'>
+    <div class="swagger-ui-wrap">
+        <a id="logo" href="http://swagger.io">swagger</a>
+        <form id='api_selector'>
+            <div class='input'>
+                <select id="input_baseUrl" name="baseUrl">
+                    <option id="private" label="private" value="/restful/swagger/private"/>
+                    <option id="public" label="public" value="/restful/swagger/public"/>
+                    <option id="prototyping" label="prototyping" value="/restful/swagger/prototyping"/>
+                </select>
+            </div>
+            <div class='input' style="display:none;"><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
+            <div class='input'><a id="explore" href="#" data-sw-translate>Reload</a></div>
+        </form>
+    </div>
+</div>
+
+<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>
+<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
+</body>
+</html>
\ No newline at end of file