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 2011/10/26 09:20:19 UTC

svn commit: r1189050 - in /incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources: ./ domainobjects/ domaintypes/

Author: danhaywood
Date: Wed Oct 26 07:20:18 2011
New Revision: 1189050

URL: http://svn.apache.org/viewvc?rev=1189050&view=rev
Log:
ISIS-109: going through representations to see what's missing against v0.48 of spec... lots of updates for property, collection, action and domain object representations

Modified:
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/ResourceAbstract.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/AbstractObjectMemberReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/CollectionSemantics.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectResourceServerside.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainResourceHelper.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/MemberType.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectActionReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectCollectionReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectPropertyReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/AbstractTypeFeatureReprBuilder.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/DomainTypeReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionParamReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionReprRenderer.java
    incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypePropertyReprRenderer.java

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/ResourceAbstract.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/ResourceAbstract.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/ResourceAbstract.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/ResourceAbstract.java Wed Oct 26 07:20:18 2011
@@ -119,6 +119,11 @@ public abstract class ResourceAbstract {
                     securityContext, getOidStringifier(), getLocalization(), getAuthenticationSession(), getPersistenceSession(), getAdapterManager());
     }
     
+    protected void init() {
+        init(RepresentationType.GENERIC);
+    }
+
+    
     protected ResourceContext getResourceContext() {
         return resourceContext;
     }

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/AbstractObjectMemberReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/AbstractObjectMemberReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/AbstractObjectMemberReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/AbstractObjectMemberReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -27,17 +27,34 @@ import org.apache.isis.viewer.json.viewe
 import org.apache.isis.viewer.json.viewer.representations.LinkFollower;
 import org.apache.isis.viewer.json.viewer.representations.Rel;
 import org.apache.isis.viewer.json.viewer.representations.ReprRendererAbstract;
+import org.codehaus.jackson.node.NullNode;
 
 public abstract class AbstractObjectMemberReprRenderer<R extends ReprRendererAbstract<R, ObjectAndMember<T>>, T extends ObjectMember> 
         extends ReprRendererAbstract<R, ObjectAndMember<T>> {
 
+    protected enum Mode {
+        INLINE,
+        FOLLOWED,
+        STANDALONE;
+
+        public boolean isInline() {
+            return this == INLINE;
+        }
+        public boolean isFollowed() {
+            return this == FOLLOWED;
+        }
+        public boolean isStandalone() {
+            return this == STANDALONE;
+        }
+    }
+    
     protected ObjectAdapterLinkTo linkToBuilder;
     
     protected ObjectAdapter objectAdapter;
     protected MemberType memberType;
     protected T objectMember;
-
-
+    protected Mode mode = Mode.INLINE; // unless we determine otherwise
+    
     public AbstractObjectMemberReprRenderer(ResourceContext resourceContext, LinkFollower linkFollower, RepresentationType representationType, JsonRepresentation representation) {
         super(resourceContext, linkFollower, representationType, representation);
     }
@@ -50,8 +67,8 @@ public abstract class AbstractObjectMemb
         usingLinkToBuilder(new DomainObjectLinkTo());
 
         // done eagerly so can use as criteria for x-ro-follow-links
-        putId();
-        putMemberType();
+        representation.mapPut(memberType.getJsProp(), objectMember.getId());
+        representation.mapPut("memberType", memberType.getName());
 
         return cast(this);
     }
@@ -64,48 +81,91 @@ public abstract class AbstractObjectMemb
         return cast(this);
     }
 
-    public R withSelf() {
-        final JsonRepresentation links = getLinks();
-        links.arrayAdd(linkToBuilder.linkToMember(Rel.SELF, memberType, objectMember).build());
+
+    /**
+     * Indicate that this is a standalone representation. 
+     */
+    public R asStandalone() {
+        mode = Mode.STANDALONE;
         return cast(this);
     }
 
-    protected void putId() {
-        representation.mapPut(memberType.getJsProp(), objectMember.getId());
+    /**
+     * Indicate that this is a representation to include as the result of a followed link. 
+     */
+    public R asFollowed() {
+        mode = Mode.FOLLOWED;
+        return cast(this);
     }
 
-    protected void putMemberType() {
-        representation.mapPut("memberType", memberType.getName());
+    /**
+     * For subclasses to call from their {@link #render()} method.
+     */
+    protected void addMemberContentSpecificToMode() {
+        if(mode.isInline()) {
+            addDetailsLink();
+            return;
+        } 
+        
+        if (mode.isStandalone()){
+            addLinkToSelf();
+        }
+        if (mode.isFollowed() || mode.isStandalone()){
+            addMutatorsIfEnabled();
+            
+            putExtensionsIsisProprietary();
+            addLinksToFormalDomainModel();
+            addLinksIsisProprietary();
+            return;
+        }
     }
-
-
-    public abstract R withMutatorsIfEnabled();
-
-    protected abstract JsonRepresentation mutatorArgs(MutatorSpec mutatorSpec);
     
-    protected R withValue() {
-        representation.mapPut("value", valueRep());
-        return cast(this);
+    private void addLinkToSelf() {
+        getLinks().arrayAdd(linkToBuilder.linkToMember(Rel.SELF, memberType, objectMember).build());
     }
 
+    protected abstract void addMutatorsIfEnabled();
+    
     /**
-     * Members that can provide a value should override.
+     * For subclasses to call back to when {@link #addMutatorsIfEnabled() adding mutators}.
      */
-    protected Object valueRep() {
-        return null;
+    protected void addLinkFor(final MutatorSpec mutatorSpec) {
+        if(hasMemberFacet(mutatorSpec.mutatorFacetType)) {
+            
+            JsonRepresentation arguments = mutatorArgs(mutatorSpec);
+            JsonRepresentation mutatorLink = 
+                    linkToBuilder.linkToMember(mutatorSpec.rel, memberType, objectMember, mutatorSpec.suffix)
+                    .withHttpMethod(mutatorSpec.httpMethod)
+                    .withArguments(arguments)
+                    .build();
+            getLinks().arrayAdd(mutatorLink);
+        }
     }
 
-    protected final void putDisabledReasonIfDisabled() {
-        String disabledReasonRep = usability().getReason();
-        representation.mapPut("disabledReason", disabledReasonRep);
+    /**
+     * Default implementation (common to properties and collections) that can 
+     * be overridden (ie by actions) if required.
+     */
+    protected JsonRepresentation mutatorArgs(MutatorSpec mutatorSpec) {
+        if(mutatorSpec.arguments.isNone()) {
+            return null;
+        }
+        if(mutatorSpec.arguments.isOne()) {
+            final JsonRepresentation repr = JsonRepresentation.newMap();
+            repr.mapPut("value", NullNode.getInstance()); // force a null into the map
+            return repr;
+        }
+        // overridden by actions
+        throw new UnsupportedOperationException("override mutatorArgs() to populate for many arguments");
     }
-
-    public R withDetailsLink() {
+    
+    private R addDetailsLink() {
         final JsonRepresentation link = 
-                linkToBuilder.linkToMember(memberType.getDetailsRel(), memberType, objectMember).build();
+                linkToBuilder.linkToMember(Rel.DETAILS, memberType, objectMember).build();
         getLinks().arrayAdd(link);
+        
         final LinkFollower membersLinkFollower = getLinkFollower();
-        final LinkFollower detailsLinkFollower = membersLinkFollower.follow("links[rel=%s]", memberType.getDetailsRel().getName());
+        final LinkFollower detailsLinkFollower = membersLinkFollower.follow("links[rel=%s]", Rel.DETAILS.getName());
         if(membersLinkFollower.matches(representation) && detailsLinkFollower.matches(link)) {
             followDetailsLink(link);
         }
@@ -114,14 +174,22 @@ public abstract class AbstractObjectMemb
 
     protected abstract void followDetailsLink(JsonRepresentation detailsLink);
 
+    protected final void putDisabledReasonIfDisabled() {
+        String disabledReasonRep = usability().getReason();
+        representation.mapPut("disabledReason", disabledReasonRep);
+    }
+
+    protected abstract void putExtensionsIsisProprietary();
+    protected abstract void addLinksToFormalDomainModel();
+    protected abstract void addLinksIsisProprietary();
+
     /**
-     * For Resources to call.
+     * Convenience method.
      */
     public boolean isMemberVisible() {
         return visibility().isAllowed();
     }
 
-
     protected <F extends Facet> F getMemberSpecFacet(Class<F> facetType) {
         ObjectSpecification otoaSpec = objectMember.getSpecification();
         return otoaSpec.getFacet(facetType);

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/CollectionSemantics.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/CollectionSemantics.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/CollectionSemantics.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/CollectionSemantics.java Wed Oct 26 07:20:18 2011
@@ -36,7 +36,11 @@ public enum CollectionSemantics {
     public String getAddToKey() {
         return addToKey;
     }
-    
+
+    public String getRemoveFromKey() {
+        return "removeFrom";
+    }
+
     public static CollectionSemantics determine(ResourceContext resourceContext, OneToManyAssociation collection) {
         return collection.getCollectionSemantics().isSet()?CollectionSemantics.SET:CollectionSemantics.LIST;
     }

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -140,8 +140,7 @@ public class DomainObjectReprRenderer ex
                         (ObjectPropertyReprRenderer) factory.newRenderer(getResourceContext(), linkFollower, JsonRepresentation.newMap());
                 
                 renderer.with(new ObjectAndProperty(objectAdapter, property))
-                        .usingLinkToBuilder(linkToBuilder)
-                        .withDetailsLink();
+                        .usingLinkToBuilder(linkToBuilder);
                 
                 members.arrayAdd(renderer.render());
             }
@@ -153,8 +152,7 @@ public class DomainObjectReprRenderer ex
                         (ObjectCollectionReprRenderer) factory.newRenderer(getResourceContext(), linkFollower, JsonRepresentation.newMap());
 
                 renderer.with(new ObjectAndCollection(objectAdapter, collection))
-                    .usingLinkToBuilder(linkToBuilder)
-                    .withDetailsLink();
+                    .usingLinkToBuilder(linkToBuilder);
                 
                 members.arrayAdd(renderer.render());
             }
@@ -181,8 +179,7 @@ public class DomainObjectReprRenderer ex
                         (ObjectActionReprRenderer) factory.newRenderer(getResourceContext(), linkFollower, JsonRepresentation.newMap());
                 
                 renderer.with(new ObjectAndAction(objectAdapter, action))
-                        .usingLinkToBuilder(linkToBuilder)
-                        .withDetailsLink();
+                        .usingLinkToBuilder(linkToBuilder);
 
                 members.arrayAdd(renderer.render());
             }

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectResourceServerside.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectResourceServerside.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectResourceServerside.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainObjectResourceServerside.java Wed Oct 26 07:20:18 2011
@@ -48,6 +48,7 @@ import org.apache.isis.viewer.json.viewe
 import org.apache.isis.viewer.json.viewer.representations.RendererFactory;
 import org.apache.isis.viewer.json.viewer.representations.RendererFactoryRegistry;
 import org.apache.isis.viewer.json.viewer.resources.ResourceAbstract;
+import org.apache.isis.viewer.json.viewer.resources.ResourceAbstract.Caching;
 import org.apache.isis.viewer.json.viewer.resources.domainobjects.DomainResourceHelper.Intent;
 
 @Path("/objects")
@@ -66,13 +67,12 @@ public class DomainObjectResourceServers
     @Produces({ MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_DOMAIN_OBJECT, RestfulMediaType.APPLICATION_JSON_ERROR })
     public Response object(
             @PathParam("oid") final String oidStr) {
-        final RepresentationType representationType = RepresentationType.DOMAIN_OBJECT;
-        init(representationType);
+        init(RepresentationType.DOMAIN_OBJECT);
 
         final ObjectAdapter objectAdapter = getObjectAdapter(oidStr);
         
         final RendererFactory rendererFactory = 
-                rendererFactoryRegistry.find(representationType);
+                rendererFactoryRegistry.find(RepresentationType.DOMAIN_OBJECT);
         
         final DomainObjectReprRenderer renderer = 
                 (DomainObjectReprRenderer) rendererFactory.newRenderer(getResourceContext(), null, JsonRepresentation.newMap());
@@ -95,9 +95,7 @@ public class DomainObjectResourceServers
         @PathParam("oid") final String oidStr, 
         final InputStream arguments) {
 
-        final RepresentationType representationType = RepresentationType.DOMAIN_OBJECT;
-        
-        init(representationType);
+        init(RepresentationType.DOMAIN_OBJECT);
 
         // TODO
         throw new UnsupportedOperationException();
@@ -113,8 +111,7 @@ public class DomainObjectResourceServers
     public Response propertyDetails(
             @PathParam("oid") final String oidStr,
             @PathParam("propertyId") final String propertyId) {
-        final RepresentationType representationType = RepresentationType.OBJECT_PROPERTY;
-        init(representationType);
+        init(RepresentationType.OBJECT_PROPERTY);
         
         final ObjectAdapter objectAdapter = getObjectAdapter(oidStr);
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
@@ -129,7 +126,7 @@ public class DomainObjectResourceServers
             @PathParam("oid") final String oidStr,
             @PathParam("propertyId") final String propertyId,
             final InputStream body) {
-        init(null);
+        init();
 
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
         
@@ -161,7 +158,7 @@ public class DomainObjectResourceServers
     public Response clearProperty(
             @PathParam("oid") final String oidStr,
             @PathParam("propertyId") final String propertyId) {
-        init(null);
+        init();
 
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
 
@@ -181,6 +178,7 @@ public class DomainObjectResourceServers
     }
 
 
+
     ////////////////////////////////////////////////////////////
     // domain object collection
     ////////////////////////////////////////////////////////////
@@ -191,6 +189,7 @@ public class DomainObjectResourceServers
     public Response accessCollection(
         @PathParam("oid") final String oidStr,
         @PathParam("collectionId") final String collectionId) {
+        init(RepresentationType.OBJECT_COLLECTION);
 
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
 
@@ -202,12 +201,9 @@ public class DomainObjectResourceServers
         final ObjectCollectionReprRenderer renderer = 
                 (ObjectCollectionReprRenderer) factory.newRenderer(getResourceContext(), null, JsonRepresentation.newMap());
 
-        renderer.with(new ObjectAndCollection(objectAdapter, collection));
+        renderer.with(new ObjectAndCollection(objectAdapter, collection)).asStandalone();
         
-        return Response.status(HttpStatusCode.OK.getJaxrsStatusType())
-                .entity(jsonFor(renderer))
-                .type(MediaType.APPLICATION_JSON_TYPE)
-                .build();
+        return ResourceAbstract.responseOfOk(renderer, Caching.NONE).build();
     }
 
     @PUT
@@ -217,7 +213,7 @@ public class DomainObjectResourceServers
             @PathParam("oid") final String oidStr,
             @PathParam("collectionId") final String collectionId,
             final InputStream body) {
-        init(null);
+        init();
 
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
 
@@ -254,7 +250,7 @@ public class DomainObjectResourceServers
             @PathParam("oid") final String oidStr,
             @PathParam("collectionId") final String collectionId,
             final InputStream body) {
-        init(null);
+        init();
 
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
 
@@ -292,7 +288,7 @@ public class DomainObjectResourceServers
         @PathParam("collectionId") final String collectionId,
         final InputStream body) {
 
-        init(null);
+        init();
         
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
 
@@ -326,8 +322,7 @@ public class DomainObjectResourceServers
     public Response actionPrompt(
             @PathParam("oid") final String oidStr,
             @PathParam("actionId") final String actionId) {
-        final RepresentationType representationType = RepresentationType.OBJECT_ACTION;
-        init(representationType);
+        init(RepresentationType.OBJECT_ACTION);
 
         final DomainResourceHelper helper = new DomainResourceHelper(getResourceContext());
 
@@ -391,6 +386,4 @@ public class DomainObjectResourceServers
         return helper.invokeAction(objectAdapter, actionId, body);
     }
 
-
-
 }

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainResourceHelper.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainResourceHelper.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainResourceHelper.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/DomainResourceHelper.java Wed Oct 26 07:20:18 2011
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map.Entry;
 
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -92,7 +93,8 @@ public class DomainResourceHelper {
         final ObjectPropertyReprRenderer renderer = 
                 (ObjectPropertyReprRenderer) factory.newRenderer(resourceContext, null, JsonRepresentation.newMap());
         
-        renderer.with(new ObjectAndProperty(objectAdapter, property));
+        renderer.with(new ObjectAndProperty(objectAdapter, property))
+                .asStandalone();
         
         return ResourceAbstract.responseOfOk(renderer, caching).build();
     }
@@ -110,8 +112,7 @@ public class DomainResourceHelper {
                 (ObjectActionReprRenderer) factory.newRenderer(resourceContext, null, JsonRepresentation.newMap());
         
         renderer.with(new ObjectAndAction(serviceAdapter, action))
-                .withSelf()
-                .withMutatorsIfEnabled();
+                .asStandalone();
 
         return ResourceAbstract.responseOfOk(renderer, Caching.NONE).build();
     }
@@ -144,16 +145,6 @@ public class DomainResourceHelper {
 
         JsonRepresentation arguments = parseQueryString(action, argumentsQueryString);
         
-        int numParameters = action.getParameterCount();
-        int argSize = arguments.size();
-        if (argSize != numParameters) {
-            throw JsonApplicationException.create(
-                    HttpStatusCode.BAD_REQUEST,
-                    "Action '%s' has %d parameters but received %d arguments",
-                    numParameters, argSize, action.getId());
-        }
-        
-        
         return invokeActionUsingAdapters(objectAdapter, action, arguments);
     }
 
@@ -211,21 +202,26 @@ public class DomainResourceHelper {
         final JsonRepresentation arguments) {
         
         List<ObjectAdapter> argAdapters = parseArguments(action, arguments);
-        final JsonRepresentation representation;
         
-        // validate
+        // validate individual args
         List<ObjectActionParameter> parameters = action.getParameters();
         for (int i = 0; i < parameters.size(); i++) {
             ObjectActionParameter parameter = parameters.get(i);
-            ObjectAdapter paramAdapter = argAdapters.get(i);
-            if (paramAdapter.getSpecification().containsFacet(ValueFacet.class)) {
-                Object arg = paramAdapter.getObject();
+            ObjectAdapter argAdapter = argAdapters.get(i);
+            if(argAdapter == null) {
+                // can only happen if this is an optional parameter; nothing to do
+                continue;
+            } 
+            if (argAdapter.getSpecification().containsFacet(ValueFacet.class)) {
+                Object arg = argAdapter.getObject();
                 String reasonNotValid = parameter.isValid(objectAdapter, arg);
                 if (reasonNotValid != null) {
                     throw JsonApplicationException.create(HttpStatusCode.NOT_ACCEPTABLE, reasonNotValid);
                 }
             }
         }
+        
+        // validate all args
         ObjectAdapter[] argArray = argAdapters.toArray(new ObjectAdapter[0]);
         Consent consent = action.isProposedArgumentSetValid(objectAdapter,
                 argArray);
@@ -241,6 +237,8 @@ public class DomainResourceHelper {
             return ResourceAbstract.responseOfNoContent(objectAdapter.getVersion()).build();
         }
 
+        final JsonRepresentation representation;
+        
         final CollectionFacet collectionFacet = returnedAdapter.getSpecification().getFacet(CollectionFacet.class);
         if (collectionFacet != null) {
             representation = representationWithSelfFor(RepresentationType.LIST, objectAdapter, action, arguments);
@@ -311,6 +309,10 @@ public class DomainResourceHelper {
             final ResourceContext resourceContext, 
             final ObjectSpecification objectSpec, 
             final JsonRepresentation representation) {
+
+        if(representation == null) {
+            return null;
+        }
         
         // value (encodable)
         if (objectSpec.isEncodeable()) {
@@ -503,23 +505,28 @@ public class DomainResourceHelper {
 
     private List<JsonRepresentation> argListFor(final ObjectAction action, JsonRepresentation arguments) {
         List<JsonRepresentation> argList = Lists.newArrayList();
+
         
-        int numParameters = action.getParameterCount();
-        int numArguments = arguments.size();
-        if (numArguments != numParameters) {
-            throw JsonApplicationException.create(
-                    HttpStatusCode.BAD_REQUEST,
-                    "Action '%s' has %d parameters but received %d arguments in body",
-                    action.getId(), numParameters, numArguments);
+        // ensure that we have no arguments that are not parameters
+        for(Entry<String, JsonRepresentation> arg: arguments.mapIterable()) {
+            final String argName = arg.getKey();
+            if(action.getParameter(argName) == null) {
+                throw JsonApplicationException.create(
+                        HttpStatusCode.BAD_REQUEST,
+                        "Action '%s' does not have a parameter %s but an argument of that name was provided",
+                        action.getId(), argName);
+            }
         }
+
+        // ensure that an argument value has been provided for all non-optional parameters 
         final List<ObjectActionParameter> parameters = action.getParameters();
         for (ObjectActionParameter param : parameters) {
             final String paramName = param.getName();
             final JsonRepresentation argRepr = arguments.getRepresentation(paramName);
-            if(argRepr == null) {
+            if(argRepr == null && !param.isOptional()) {
                 throw JsonApplicationException.create(
                         HttpStatusCode.BAD_REQUEST,
-                        "Action '%s', no argument found for parameter '%s'",
+                        "Action '%s', no argument found for (mandatory) parameter '%s'",
                         action.getId(), paramName);
             }
             argList.add(argRepr);

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/MemberType.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/MemberType.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/MemberType.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/MemberType.java Wed Oct 26 07:20:18 2011
@@ -42,11 +42,10 @@ import com.google.common.collect.Immutab
 
 public enum MemberType {
 
-    PROPERTY("properties/", "id", Rel.DETAILS, RepresentationType.OBJECT_PROPERTY, 
-            ImmutableMap.of(
-                "modify", MutatorSpec.of(Rel.MODIFY, PropertyValidateFacet.class, PropertySetterFacet.class, HttpMethod.PUT, BodyArgs.ONE),
-                "clear", MutatorSpec.of(Rel.CLEAR, PropertyValidateFacet.class, PropertyClearFacet.class, HttpMethod.DELETE, BodyArgs.NONE)
-                )) {
+    PROPERTY("properties/", "id", RepresentationType.OBJECT_PROPERTY, ImmutableMap.of(
+        "modify", MutatorSpec.of(Rel.MODIFY, PropertyValidateFacet.class, PropertySetterFacet.class, HttpMethod.PUT, BodyArgs.ONE),
+        "clear", MutatorSpec.of(Rel.CLEAR, PropertyValidateFacet.class, PropertyClearFacet.class, HttpMethod.DELETE, BodyArgs.NONE)
+        )) {
         @Override
         public ObjectSpecification specFor(ObjectMember objectMember) {
             return objectMember.getSpecification();
@@ -55,12 +54,11 @@ public enum MemberType {
     /**
      * {@link #getMutators()} are keyed by {@link CollectionSemantics#getAddToKey()}
      */
-    COLLECTION("collections/", "id", Rel.DETAILS, RepresentationType.OBJECT_COLLECTION, 
-            ImmutableMap.of(
-                "addToSet", MutatorSpec.of(Rel.ADD_TO, CollectionValidateAddToFacet.class, CollectionAddToFacet.class, HttpMethod.PUT, BodyArgs.ONE),
-                "addToList", MutatorSpec.of(Rel.ADD_TO, CollectionValidateAddToFacet.class, CollectionAddToFacet.class, HttpMethod.POST, BodyArgs.ONE),
-                "removeFrom", MutatorSpec.of(Rel.REMOVE_FROM, CollectionValidateRemoveFromFacet.class, CollectionRemoveFromFacet.class, HttpMethod.DELETE, BodyArgs.ONE)
-                )) {
+    COLLECTION("collections/", "id", RepresentationType.OBJECT_COLLECTION, ImmutableMap.of(
+        "addToSet", MutatorSpec.of(Rel.ADD_TO, CollectionValidateAddToFacet.class, CollectionAddToFacet.class, HttpMethod.PUT, BodyArgs.ONE),
+        "addToList", MutatorSpec.of(Rel.ADD_TO, CollectionValidateAddToFacet.class, CollectionAddToFacet.class, HttpMethod.POST, BodyArgs.ONE),
+        "removeFrom", MutatorSpec.of(Rel.REMOVE_FROM, CollectionValidateRemoveFromFacet.class, CollectionRemoveFromFacet.class, HttpMethod.DELETE, BodyArgs.ONE)
+        )) {
         @Override
         public ObjectSpecification specFor(ObjectMember objectMember) {
             return objectMember.getSpecification();
@@ -69,12 +67,11 @@ public enum MemberType {
     /**
      * {@link #getMutators()} are keyed by {@link ActionSemantics#getInvokeKey()}
      */
-    ACTION("actions/", "id", Rel.DETAILS, RepresentationType.OBJECT_ACTION,
-            ImmutableMap.of(
-                "invokeQueryOnly", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, HttpMethod.GET, BodyArgs.MANY, "invoke"),
-                "invokeIdempotent", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, HttpMethod.PUT, BodyArgs.MANY, "invoke"),
-                "invoke", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, HttpMethod.POST, BodyArgs.MANY, "invoke")
-            )) {
+    ACTION("actions/", "id", RepresentationType.OBJECT_ACTION, ImmutableMap.of(
+        "invokeQueryOnly", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, HttpMethod.GET, BodyArgs.MANY, "invoke"),
+        "invokeIdempotent", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, HttpMethod.PUT, BodyArgs.MANY, "invoke"),
+        "invoke", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, HttpMethod.POST, BodyArgs.MANY, "invoke")
+    )) {
         @Override
         public ObjectSpecification specFor(ObjectMember objectMember) {
             ObjectAction objectAction = (ObjectAction) objectMember;
@@ -84,17 +81,14 @@ public enum MemberType {
 
     private final String urlPart;
     private final String jsProp;
-    private final Rel detailsRel;
     private final String name;
     private final RepresentationType representationType;
 
     private final Map<String, MutatorSpec> mutators;
-    
 
-    private MemberType(String urlPart, String jsProp, Rel detailsRel, RepresentationType representationType, Map<String, MutatorSpec> mutators) {
+    private MemberType(String urlPart, String jsProp, RepresentationType representationType, Map<String, MutatorSpec> mutators) {
         this.urlPart = urlPart;
         this.jsProp = jsProp;
-        this.detailsRel = detailsRel;
         this.representationType = representationType;
         this.mutators = mutators;
         name = Enums.enumToCamelCase(this);
@@ -147,9 +141,6 @@ public enum MemberType {
         return representationType;
     }
 
-    public Rel getDetailsRel() {
-        return detailsRel;
-    }
 
     public String getName() {
         return name;

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectActionReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectActionReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectActionReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectActionReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -32,6 +32,7 @@ import org.apache.isis.viewer.json.viewe
 import org.apache.isis.viewer.json.viewer.representations.RendererFactoryRegistry;
 import org.apache.isis.viewer.json.viewer.representations.ReprRenderer;
 import org.apache.isis.viewer.json.viewer.representations.ReprRendererFactoryAbstract;
+import org.apache.isis.viewer.json.viewer.resources.domainobjects.AbstractObjectMemberReprRenderer.Mode;
 import org.apache.isis.viewer.json.viewer.resources.domaintypes.DomainTypeReprRenderer;
 import org.apache.isis.viewer.json.viewer.resources.domaintypes.TypeActionReprRenderer;
 import org.codehaus.jackson.node.NullNode;
@@ -61,12 +62,10 @@ public class ObjectActionReprRenderer ex
         
         putDisabledReasonIfDisabled();
         
-        JsonRepresentation extensions = getExtensions();
-        putExtensionsIsisProprietary(extensions);
-        
-        JsonRepresentation links = getLinks();
-        addLinksFormalDomainModel(links, resourceContext);
-        addLinksIsisProprietary(links, resourceContext);
+        addMemberContentSpecificToMode();
+        if(mode.isStandalone()) {
+            addParameterDetails();
+        }
 
         return representation;
     }
@@ -84,7 +83,7 @@ public class ObjectActionReprRenderer ex
         RendererFactory factory = RendererFactoryRegistry.instance.find(RepresentationType.OBJECT_ACTION);
         final ObjectActionReprRenderer renderer = 
                 (ObjectActionReprRenderer) factory.newRenderer(getResourceContext(), getLinkFollower(), JsonRepresentation.newMap());
-        renderer.with(new ObjectAndAction(objectAdapter, objectMember)).withMutatorsIfEnabled();
+        renderer.with(new ObjectAndAction(objectAdapter, objectMember)).asFollowed();
         detailsLink.mapPut("value", renderer.render());
     }
 
@@ -93,32 +92,19 @@ public class ObjectActionReprRenderer ex
     /////////////////////////////////////////////////////
 
     @Override
-    public ObjectActionReprRenderer withMutatorsIfEnabled() {
+    protected void addMutatorsIfEnabled() {
         if(usability().isVetoed()) {
-            return cast(this);
+            return;
         }
         Map<String, MutatorSpec> mutators = memberType.getMutators();
         final ActionSemantics semantics = ActionSemantics.determine(this.resourceContext, objectMember);
         
         final String mutator = semantics.getInvokeKey();
         final MutatorSpec mutatorSpec = mutators.get(mutator);
-        addInvokeLinkIfMutator(mutatorSpec);
         
-        return cast(this);
+        addLinkFor(mutatorSpec);
     }
 
-    private void addInvokeLinkIfMutator(MutatorSpec mutatorSpec) {
-        if(!hasMemberFacet(mutatorSpec.mutatorFacetType)) {
-            return;
-        } 
-        JsonRepresentation arguments = mutatorArgs(mutatorSpec);
-        JsonRepresentation detailsLink = 
-                linkToBuilder.linkToMember(Rel.INVOKE, memberType, objectMember, mutatorSpec.suffix)
-                .withHttpMethod(mutatorSpec.httpMethod)
-                .withArguments(arguments)
-                .build();
-        getLinks().arrayAdd(detailsLink);
-    }
     
 	private ObjectAdapter contributingServiceAdapter() {
     	ObjectSpecification serviceType = objectMember.getOnType();
@@ -133,32 +119,33 @@ public class ObjectActionReprRenderer ex
 	}
 
 	
-	   @Override
-	    protected JsonRepresentation mutatorArgs(MutatorSpec mutatorSpec) {
-	        JsonRepresentation argMap = JsonRepresentation.newMap();
-	        List<ObjectActionParameter> parameters = objectMember.getParameters();
-	        for(int i=0; i<objectMember.getParameterCount(); i++) {
-	            argMap.mapPut(parameters.get(i).getName(), argValueFor(i)); 
-	        }
-	        return argMap;
-	    }
-
-	    private Object argValueFor(int i) {
-	        if(objectMember.isContributed()) {
-	            ObjectActionParameter actionParameter = objectMember.getParameters().get(i);
-	            if (actionParameter.getSpecification().isOfType(objectAdapter.getSpecification())) {
-	                return DomainObjectReprRenderer.newLinkToBuilder(resourceContext, Rel.OBJECT, objectAdapter).build();
-	            }
-	        }
-	        return NullNode.instance;
-	    }
+    @Override
+    protected JsonRepresentation mutatorArgs(MutatorSpec mutatorSpec) {
+        JsonRepresentation argMap = JsonRepresentation.newMap();
+        List<ObjectActionParameter> parameters = objectMember.getParameters();
+        for(int i=0; i<objectMember.getParameterCount(); i++) {
+            argMap.mapPut(parameters.get(i).getName(), argValueFor(i)); 
+        }
+        return argMap;
+    }
+
+    private Object argValueFor(int i) {
+        if(objectMember.isContributed()) {
+            ObjectActionParameter actionParameter = objectMember.getParameters().get(i);
+            if (actionParameter.getSpecification().isOfType(objectAdapter.getSpecification())) {
+                return DomainObjectReprRenderer.newLinkToBuilder(resourceContext, Rel.OBJECT, objectAdapter).build();
+            }
+        }
+        // force a null into the map
+        return NullNode.getInstance();
+    }
 
 
     /////////////////////////////////////////////////////
     // parameter details
     /////////////////////////////////////////////////////
 
-    public ObjectActionReprRenderer withParameterDetails() {
+    private ObjectActionReprRenderer addParameterDetails() {
     	List<Object> parameters = Lists.newArrayList();
 		for (int i=0; i< objectMember.getParameterCount(); i++) {
 			ObjectActionParameter param = objectMember.getParameters().get(i);
@@ -207,31 +194,27 @@ public class ObjectActionReprRenderer ex
 	}
 
 	
-
-	
 	/////////////////////////////////////////////////////
 	// extensions and links
     /////////////////////////////////////////////////////
 	
-    private void putExtensionsIsisProprietary(JsonRepresentation extensions) {
-        extensions.mapPut("actionType", objectMember.getType().name().toLowerCase());
-        
-        final ActionSemantics semantics = ActionSemantics.determine(resourceContext, objectMember);
-        extensions.mapPut("actionSemantics", semantics.getName());
-    }
-
-     private void addLinksFormalDomainModel(JsonRepresentation links, ResourceContext resourceContext) {
-         links.arrayAdd(TypeActionReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build());
+     protected void addLinksToFormalDomainModel() {
+         getLinks().arrayAdd(TypeActionReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build());
      }
-
-     private void addLinksIsisProprietary(JsonRepresentation links, ResourceContext resourceContext) {
-       if(objectMember.isContributed()) {
+     
+     protected void addLinksIsisProprietary() {
+        if(objectMember.isContributed()) {
             ObjectAdapter serviceAdapter = contributingServiceAdapter();
             JsonRepresentation contributedByLink = DomainObjectReprRenderer.newLinkToBuilder(resourceContext, Rel.CONTRIBUTED_BY, serviceAdapter).build();
-            links.arrayAdd(contributedByLink);
+            getLinks().arrayAdd(contributedByLink);
         }
     }
 
-
+     protected void putExtensionsIsisProprietary() {
+         getExtensions().mapPut("actionType", objectMember.getType().name().toLowerCase());
+         
+         final ActionSemantics semantics = ActionSemantics.determine(resourceContext, objectMember);
+         getExtensions().mapPut("actionSemantics", semantics.getName());
+     }
 
 }
\ No newline at end of file

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectCollectionReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectCollectionReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectCollectionReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectCollectionReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -26,14 +26,14 @@ import org.apache.isis.core.metamodel.sp
 import org.apache.isis.viewer.json.applib.JsonRepresentation;
 import org.apache.isis.viewer.json.applib.RepresentationType;
 import org.apache.isis.viewer.json.viewer.ResourceContext;
-import org.apache.isis.viewer.json.viewer.representations.LinkFollower;
 import org.apache.isis.viewer.json.viewer.representations.LinkBuilder;
+import org.apache.isis.viewer.json.viewer.representations.LinkFollower;
 import org.apache.isis.viewer.json.viewer.representations.Rel;
 import org.apache.isis.viewer.json.viewer.representations.RendererFactory;
 import org.apache.isis.viewer.json.viewer.representations.RendererFactoryRegistry;
 import org.apache.isis.viewer.json.viewer.representations.ReprRenderer;
 import org.apache.isis.viewer.json.viewer.representations.ReprRendererFactoryAbstract;
-import org.apache.isis.viewer.json.viewer.resources.domaintypes.DomainTypeReprRenderer;
+import org.apache.isis.viewer.json.viewer.resources.domainobjects.AbstractObjectMemberReprRenderer.Mode;
 import org.apache.isis.viewer.json.viewer.resources.domaintypes.TypeCollectionReprRenderer;
 
 import com.google.common.collect.Lists;
@@ -58,19 +58,39 @@ public class ObjectCollectionReprRendere
     
     public JsonRepresentation render() {
         // id and memberType are put eagerly
-        
+
         putDisabledReasonIfDisabled();
-        
-        JsonRepresentation extensions = getExtensions();
-        putExtensionsIsisProprietary(extensions);
-        
-        JsonRepresentation links = getLinks();
-        addLinksFormalDomainModel(links, resourceContext);
-        addLinksIsisProprietary(links, resourceContext);
+
+        addMemberContentSpecificToMode();
+        if(mode.isStandalone()) {
+            addValue();
+        }
 
         return representation;
     }
 
+    
+    /////////////////////////////////////////////////////
+    // value
+    /////////////////////////////////////////////////////
+
+    private void addValue() {
+        ObjectAdapter valueAdapter = objectMember.get(objectAdapter);
+        if(valueAdapter == null) {
+            return;
+        }
+
+        final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(valueAdapter);
+        List<JsonRepresentation> list = Lists.newArrayList();
+        for (final ObjectAdapter elementAdapter : facet.iterable(valueAdapter)) {
+
+            LinkBuilder newBuilder = DomainObjectReprRenderer.newLinkToBuilder(resourceContext, Rel.OBJECT, elementAdapter);
+
+            list.add(newBuilder.build());
+        }
+        
+        representation.mapPut("value", list);
+    }
 
 
     /////////////////////////////////////////////////////
@@ -85,7 +105,7 @@ public class ObjectCollectionReprRendere
         RendererFactory factory = RendererFactoryRegistry.instance.find(RepresentationType.OBJECT_COLLECTION);
         final ObjectCollectionReprRenderer renderer = 
                 (ObjectCollectionReprRenderer) factory.newRenderer(getResourceContext(), getLinkFollower(), JsonRepresentation.newMap());
-        renderer.with(new ObjectAndCollection(objectAdapter, objectMember));
+        renderer.with(new ObjectAndCollection(objectAdapter, objectMember)).asFollowed();
         detailsLink.mapPut("value", renderer.render());
     }
 
@@ -94,75 +114,47 @@ public class ObjectCollectionReprRendere
     /////////////////////////////////////////////////////
 
     @Override
-    public ObjectCollectionReprRenderer withMutatorsIfEnabled() {
+    protected void addMutatorsIfEnabled() {
         if(usability().isVetoed()) {
-            return cast(this);
+            return;
         }
-        Map<String, MutatorSpec> mutators = memberType.getMutators();
-        for(String mutator: mutators.keySet()) {
-            MutatorSpec mutatorSpec = mutators.get(mutator);
-            if(hasMemberFacet(mutatorSpec.mutatorFacetType)) {
-                
-                JsonRepresentation arguments = mutatorArgs(mutatorSpec);
-                JsonRepresentation detailsLink = 
-                        linkToBuilder.linkToMember(mutatorSpec.rel, memberType, objectMember, mutatorSpec.suffix)
-                        .withHttpMethod(mutatorSpec.httpMethod)
-                        .withArguments(arguments)
-                        .build();
-                representation.mapPut(mutator, detailsLink);
-            }
-        }
-        return cast(this);
+        
+        final CollectionSemantics semantics = CollectionSemantics.determine(this.resourceContext, objectMember);
+        addMutatorLink(semantics.getAddToKey());
+        addMutatorLink(semantics.getRemoveFromKey());
+        
+        return;
     }
 
-
-    protected JsonRepresentation mutatorArgs(MutatorSpec mutatorSpec) {
-        final JsonRepresentation repr = JsonRepresentation.newMap();
-        if(mutatorSpec.arguments.isNone()) {
-            return repr;
-        }
-        if(mutatorSpec.arguments.isOne()) {
-            JsonRepresentation argValues = JsonRepresentation.newArray(1);
-            return argValues;
-        }
-        throw new UnsupportedOperationException("should be overridden if bodyArgs is not 0 or 1");
+    private void addMutatorLink(String key) {
+        Map<String, MutatorSpec> mutators = memberType.getMutators();
+        final MutatorSpec mutatorSpec = mutators.get(key);
+        addLinkFor(mutatorSpec);
     }
-    
 
-    @Override
-    protected Object valueRep() {
-        ObjectAdapter valueAdapter = objectMember.get(objectAdapter);
-        if(valueAdapter == null) {
-            return null;
-        }
-        final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(valueAdapter);
-        List<JsonRepresentation> list = Lists.newArrayList();
-        for (final ObjectAdapter elementAdapter : facet.iterable(valueAdapter)) {
 
-            LinkBuilder newBuilder = DomainObjectReprRenderer.newLinkToBuilder(resourceContext, Rel.OBJECT, elementAdapter);
 
-			list.add(newBuilder.build());
-        }
-        
-        return list;
-    }
+
 
     /////////////////////////////////////////////////////
     // extensions and links
     /////////////////////////////////////////////////////
     
-    private void putExtensionsIsisProprietary(JsonRepresentation extensions) {
-        final CollectionSemantics semantics = CollectionSemantics.determine(resourceContext, objectMember);
-        extensions.mapPut("collectionSemantics", semantics.name().toLowerCase());
+    
+    protected void addLinksToFormalDomainModel() {
+        final LinkBuilder linkBuilder = TypeCollectionReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember);
+        getLinks().arrayAdd(linkBuilder.build());
     }
 
-    private void addLinksFormalDomainModel(JsonRepresentation links, ResourceContext resourceContext) {
-        links.arrayAdd(TypeCollectionReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build());
+    @Override
+    protected void addLinksIsisProprietary() {
+        // none
     }
 
-    private void addLinksIsisProprietary(JsonRepresentation links, ResourceContext resourceContext) {
+    protected void putExtensionsIsisProprietary() {
+        final CollectionSemantics semantics = CollectionSemantics.determine(resourceContext, objectMember);
+        getExtensions().mapPut("collectionSemantics", semantics.name().toLowerCase());
     }
 
 
-
 }
\ No newline at end of file

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectPropertyReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectPropertyReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectPropertyReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domainobjects/ObjectPropertyReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -31,6 +31,7 @@ import org.apache.isis.viewer.json.viewe
 import org.apache.isis.viewer.json.viewer.representations.RendererFactoryRegistry;
 import org.apache.isis.viewer.json.viewer.representations.ReprRenderer;
 import org.apache.isis.viewer.json.viewer.representations.ReprRendererFactoryAbstract;
+import org.apache.isis.viewer.json.viewer.resources.domainobjects.AbstractObjectMemberReprRenderer.Mode;
 import org.apache.isis.viewer.json.viewer.resources.domaintypes.DomainTypeReprRenderer;
 import org.apache.isis.viewer.json.viewer.resources.domaintypes.TypePropertyReprRenderer;
 
@@ -58,20 +59,36 @@ public class ObjectPropertyReprRenderer 
     public JsonRepresentation render() {
         // id and memberType are put in eagerly
         
-        withValue();
+        addValue();
 
         putDisabledReasonIfDisabled();
 
-        JsonRepresentation extensions = getExtensions();
-        putExtensionsIsisProprietary(extensions);
+        addMemberContentSpecificToMode();
+        if(mode.isStandalone()) {
+            addChoices();
+        }
         
-        JsonRepresentation links = getLinks();
-        addLinksFormalDomainModel(links, resourceContext);
-        addLinksIsisProprietary(links, resourceContext);
-
         return representation;
     }
 
+    
+    /////////////////////////////////////////////////////
+    // value
+    /////////////////////////////////////////////////////
+
+    private void addValue() {
+        representation.mapPut("value", valueRep());
+    }
+
+    private Object valueRep() {
+        ObjectAdapter valueAdapter = objectMember.get(objectAdapter);
+        if(valueAdapter == null) {
+            return null;
+        }
+        return DomainObjectReprRenderer.valueOrRef(resourceContext, valueAdapter, objectMember.getSpecification());
+    }
+
+
 
     /////////////////////////////////////////////////////
     // details link
@@ -85,7 +102,7 @@ public class ObjectPropertyReprRenderer 
         RendererFactory factory = RendererFactoryRegistry.instance.find(RepresentationType.OBJECT_PROPERTY);
         final ObjectPropertyReprRenderer renderer = 
                 (ObjectPropertyReprRenderer) factory.newRenderer(getResourceContext(), getLinkFollower(), JsonRepresentation.newMap());
-        renderer.with(new ObjectAndProperty(objectAdapter, objectMember));
+        renderer.with(new ObjectAndProperty(objectAdapter, objectMember)).asFollowed();
         detailsLink.mapPut("value", renderer.render());
     }
 
@@ -95,55 +112,25 @@ public class ObjectPropertyReprRenderer 
 
 
     @Override
-    public ObjectPropertyReprRenderer withMutatorsIfEnabled() {
+    protected void addMutatorsIfEnabled() {
         if(usability().isVetoed()) {
-            return cast(this);
+            return;
         }
         Map<String, MutatorSpec> mutators = memberType.getMutators();
         for(String mutator: mutators.keySet()) {
             MutatorSpec mutatorSpec = mutators.get(mutator);
-            if(hasMemberFacet(mutatorSpec.mutatorFacetType)) {
-                
-                JsonRepresentation arguments = mutatorArgs(mutatorSpec);
-                JsonRepresentation detailsLink = 
-                        linkToBuilder.linkToMember(mutatorSpec.rel, memberType, objectMember, mutatorSpec.suffix)
-                        .withHttpMethod(mutatorSpec.httpMethod)
-                        .withArguments(arguments)
-                        .build();
-                representation.mapPut(mutator, detailsLink);
-            }
+            addLinkFor(mutatorSpec);
         }
-        return cast(this);
+        return;
     }
 
-    protected JsonRepresentation mutatorArgs(MutatorSpec mutatorSpec) {
-        final JsonRepresentation repr = JsonRepresentation.newMap();
-        if(mutatorSpec.arguments.isNone()) {
-            return repr;
-        }
-        if(mutatorSpec.arguments.isOne()) {
-            JsonRepresentation argValues = JsonRepresentation.newArray(1);
-            return argValues;
-        }
-        throw new UnsupportedOperationException("should be overridden if bodyArgs is not 0 or 1");
-    }
-
-
-	@Override
-    protected Object valueRep() {
-        ObjectAdapter valueAdapter = objectMember.get(objectAdapter);
-        if(valueAdapter == null) {
-		    return null;
-		}
-        return DomainObjectReprRenderer.valueOrRef(resourceContext, valueAdapter, objectMember.getSpecification());
-    }
 
 	
     /////////////////////////////////////////////////////
     // choices
     /////////////////////////////////////////////////////
 
-	public ObjectPropertyReprRenderer withChoices() {
+	private ObjectPropertyReprRenderer addChoices() {
 		Object propertyChoices = propertyChoices();
 		if(propertyChoices != null) {
 			representation.mapPut("choices", propertyChoices);
@@ -169,15 +156,19 @@ public class ObjectPropertyReprRenderer 
     // extensions and links
     /////////////////////////////////////////////////////
     
-    private void putExtensionsIsisProprietary(JsonRepresentation extensions) {
+    protected void addLinksToFormalDomainModel() {
+        getLinks().arrayAdd(
+                TypePropertyReprRenderer.newLinkToBuilder(getResourceContext(), Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build());
     }
 
-    private void addLinksFormalDomainModel(JsonRepresentation links, ResourceContext resourceContext) {
-        links.arrayAdd(TypePropertyReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build());
+    @Override
+    protected void addLinksIsisProprietary() {
+        // none
     }
 
-    private void addLinksIsisProprietary(JsonRepresentation links, ResourceContext resourceContext) {
+    @Override
+    protected void putExtensionsIsisProprietary() {
+        // none
     }
 
-
 }
\ No newline at end of file

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/AbstractTypeFeatureReprBuilder.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/AbstractTypeFeatureReprBuilder.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/AbstractTypeFeatureReprBuilder.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/AbstractTypeFeatureReprBuilder.java Wed Oct 26 07:20:18 2011
@@ -67,6 +67,8 @@ public abstract class AbstractTypeFeatur
         addLinkSelfIfRequired();
         addLinkToParentIfProvided();
         
+        addPropertiesSpecificToFeature();
+        
         addLinksSpecificToFeature();
         putExtensionsSpecificToFeature();
 
@@ -75,6 +77,12 @@ public abstract class AbstractTypeFeatur
 
     
     /**
+     * Optional hook method.
+     */
+    protected void addPropertiesSpecificToFeature() {
+    }
+
+    /**
      * Mandatory hook method.
      */
     protected abstract void addLinkSelfIfRequired();

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/DomainTypeReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/DomainTypeReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/DomainTypeReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/DomainTypeReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -83,6 +83,7 @@ public class DomainTypeReprRenderer exte
 
             putExtensionsNames();
             putExtensionsDescriptionIfAvailable();
+            putExtensionsIfService();
         }
 
         return representation;
@@ -117,7 +118,7 @@ public class DomainTypeReprRenderer exte
         getExtensions().mapPut("friendlyName", singularName);
 
         String pluralName = objectSpecification.getPluralName();
-        getExtensions().mapPut("singularName", pluralName);
+        getExtensions().mapPut("pluralName", pluralName);
     }
 
     protected void putExtensionsDescriptionIfAvailable() {
@@ -127,4 +128,8 @@ public class DomainTypeReprRenderer exte
         }
     }
 
+    protected void putExtensionsIfService() {
+        getExtensions().mapPut("isService", objectSpecification.isService());
+    }
+
 }
\ No newline at end of file

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionParamReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionParamReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionParamReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionParamReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -16,6 +16,7 @@
  */
 package org.apache.isis.viewer.json.viewer.resources.domaintypes;
 
+import org.apache.isis.core.metamodel.facets.maxlen.MaxLengthFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
@@ -79,6 +80,15 @@ public class TypeActionParamReprRenderer
     }
 
     @Override
+    protected void addPropertiesSpecificToFeature() {
+        representation.mapPut("optional", getObjectFeature().isOptional());
+        final MaxLengthFacet maxLength = getObjectFeature().getFacet(MaxLengthFacet.class);
+        if(maxLength != null && !maxLength.isNoop()) {
+            representation.mapPut("maxLength", maxLength.value());
+        }
+    }
+    
+    @Override
     protected void putExtensionsSpecificToFeature() {
         putExtensionsName();
         putExtensionsDescriptionIfAvailable();        

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypeActionReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -57,25 +57,26 @@ public class TypeActionReprRenderer exte
     public TypeActionReprRenderer(ResourceContext resourceContext, LinkFollower linkFollower, RepresentationType representationType, JsonRepresentation representation) {
         super(resourceContext, linkFollower, representationType, representation);
     }
-
     
     @Override
     protected void addLinksSpecificToFeature() {
-        addLinksForParameters();
+        addParameters();
         addLinkToReturnTypeIfAny();
         addLinkToElementTypeIfAny();
     }
 
-    private void addLinksForParameters() {
+    private void addParameters() {
         if(parentSpec == null) {
             return;
         }
+        final JsonRepresentation parameterList = JsonRepresentation.newArray();
         final List<ObjectActionParameter> parameters = getObjectFeature().getParameters();
         for (ObjectActionParameter parameter : parameters) {
             final LinkBuilder linkBuilder = TypeActionParamReprRenderer.newLinkToBuilder(getResourceContext(), Rel.ACTION_PARAM, parentSpec, parameter);
-            getLinks().arrayAdd(linkBuilder.build());
+            parameterList.arrayAdd(linkBuilder.build());
         }
         
+        representation.mapPut("parameters", parameterList);
     }
 
     protected void addLinkToElementTypeIfAny() {

Modified: incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypePropertyReprRenderer.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypePropertyReprRenderer.java?rev=1189050&r1=1189049&r2=1189050&view=diff
==============================================================================
--- incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypePropertyReprRenderer.java (original)
+++ incubator/isis/trunk/framework/viewer/json/json-viewer/src/main/java/org/apache/isis/viewer/json/viewer/resources/domaintypes/TypePropertyReprRenderer.java Wed Oct 26 07:20:18 2011
@@ -16,6 +16,7 @@
  */
 package org.apache.isis.viewer.json.viewer.resources.domaintypes;
 
+import org.apache.isis.core.metamodel.facets.maxlen.MaxLengthFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.viewer.json.applib.JsonRepresentation;
@@ -57,6 +58,15 @@ public class TypePropertyReprRenderer ex
         addLinkToReturnTypeIfAny();
     }
 
+    @Override
+    protected void addPropertiesSpecificToFeature() {
+        representation.mapPut("optional", !getObjectFeature().isMandatory());
+        final MaxLengthFacet maxLength = getObjectFeature().getFacet(MaxLengthFacet.class);
+        if(maxLength != null && !maxLength.isNoop()) {
+            representation.mapPut("maxLength", maxLength.value());
+        }
+    }
+
     private void addLinkToReturnTypeIfAny() {
         final ObjectSpecification returnType = getObjectFeature().getSpecification();
         if(returnType == null) {