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 2013/02/20 00:38:40 UTC

[2/2] git commit: ISIS-233: home page tck testing

Updated Branches:
  refs/heads/dan/ISIS-233-ro e5093edb5 -> ee3241aca


ISIS-233: home page tck testing

* accept header
* fixing link following now working
* renamed LinkFollower to LinkFollowSpecs


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

Branch: refs/heads/dan/ISIS-233-ro
Commit: ee3241aca19caf3a9eb6c06f462c413332485e84
Parents: e5093ed
Author: Dan Haywood <da...@apache.org>
Authored: Tue Feb 19 23:37:48 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Tue Feb 19 23:37:48 2013 +0000

----------------------------------------------------------------------
 .../applib/user/UserRepresentation.java            |    6 +
 .../restfulobjects/applib/util/PathNode.java       |   11 +-
 .../restfulobjects/rendering/LinkBuilder.java      |    1 -
 .../restfulobjects/rendering/LinkFollowSpecs.java  |  124 +++++++++++
 .../restfulobjects/rendering/LinkFollower.java     |  125 -----------
 .../restfulobjects/rendering/RendererFactory.java  |    2 +-
 .../rendering/ReprRendererAbstract.java            |   27 ++-
 .../AbstractObjectMemberReprRenderer.java          |    8 +-
 .../domainobjects/ActionResultReprRenderer.java    |    4 +-
 .../domainobjects/DomainObjectReprRenderer.java    |    8 +-
 .../rendering/domainobjects/ListReprRenderer.java  |    9 +-
 .../domainobjects/ObjectActionReprRenderer.java    |    6 +-
 .../ObjectCollectionReprRenderer.java              |    6 +-
 .../domainobjects/ObjectPropertyReprRenderer.java  |    6 +-
 .../domainobjects/ScalarValueReprRenderer.java     |    4 +-
 .../AbstractTypeFeatureReprRenderer.java           |    4 +-
 .../AbstractTypeMemberReprRenderer.java            |    4 +-
 .../domaintypes/ActionDescriptionReprRenderer.java |    4 +-
 .../ActionParameterDescriptionReprRenderer.java    |    4 +-
 .../CollectionDescriptionReprRenderer.java         |    4 +-
 .../domaintypes/DomainTypeReprRenderer.java        |    4 +-
 .../PropertyDescriptionReprRenderer.java           |    4 +-
 .../domaintypes/TypeActionResultReprRenderer.java  |    4 +-
 .../domaintypes/TypeListReprRenderer.java          |    6 +-
 .../rendering/util/FollowSpecUtil.java             |   50 +++++
 .../restfulobjects/rendering/util/GraphUtil.java   |   60 -----
 .../rendering/GraphTest_asGraph.java               |   77 -------
 .../rendering/LinkFollowSpecsTest_follow.java      |  158 ++++++++++++++
 .../rendering/LinkFollowerTest_follow.java         |  169 ---------------
 .../resources/DomainServiceResourceServerside.java |    3 +-
 .../server/resources/HomePageReprRenderer.java     |   31 +--
 .../server/resources/UserReprRenderer.java         |    8 +-
 .../server/resources/VersionReprRenderer.java      |    7 +-
 ...ceContextTest_ensureCompatibleAcceptHeader.java |    4 +-
 .../DomainResourceHelperTest_readBodyAsMap.java    |    3 +-
 .../home/HomePageResourceTest_get_accept.java      |    8 +-
 ...ePageResourceTest_templated_representation.java |  123 +++++++++++
 ...rceTest_templated_representationAndHeaders.java |  159 --------------
 ...PageResourceTest_templated_responseHeaders.java |   95 ++++++++
 .../home/HomePageResourceTest_xrofollowlinks.java  |    2 +-
 .../resources/user/UserResourceTest_accept.java    |   79 -------
 .../user/UserResourceTest_get_accept.java          |  109 ++++++++++
 .../UserResourceTest_representationAndHeaders.java |  142 ------------
 .../UserResourceTest_templated_representation.java |  117 ++++++++++
 ...UserResourceTest_templated_responseHeaders.java |   96 ++++++++
 45 files changed, 973 insertions(+), 912 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/user/UserRepresentation.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/user/UserRepresentation.java b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/user/UserRepresentation.java
index 67d3faa..6fb5906 100644
--- a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/user/UserRepresentation.java
+++ b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/user/UserRepresentation.java
@@ -19,6 +19,8 @@
 package org.apache.isis.viewer.restfulobjects.applib.user;
 
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.apache.isis.viewer.restfulobjects.applib.LinkRepresentation;
+import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.domainobjects.DomainRepresentation;
 import org.codehaus.jackson.JsonNode;
 
@@ -28,6 +30,10 @@ public class UserRepresentation extends DomainRepresentation {
         super(jsonNode);
     }
 
+    public LinkRepresentation getUp() {
+        return getLinkWithRel(Rel.UP);
+    }
+
     public String getUserName() {
         return getString("userName");
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/util/PathNode.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/util/PathNode.java b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/util/PathNode.java
index b9fcaf5..a980dae 100644
--- a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/util/PathNode.java
+++ b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/util/PathNode.java
@@ -128,7 +128,6 @@ public class PathNode {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((criteria == null) ? 0 : criteria.hashCode());
         result = prime * result + ((key == null) ? 0 : key.hashCode());
         return result;
     }
@@ -142,11 +141,6 @@ public class PathNode {
         if (getClass() != obj.getClass())
             return false;
         PathNode other = (PathNode) obj;
-        if (criteria == null) {
-            if (other.criteria != null)
-                return false;
-        } else if (!criteria.equals(other.criteria))
-            return false;
         if (key == null) {
             if (other.key != null)
                 return false;
@@ -154,12 +148,11 @@ public class PathNode {
             return false;
         return true;
     }
-    
+
+
     @Override
     public String toString() {
         return key + (criteria.isEmpty() ? "" : criteria);
     }
 
-
-    
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkBuilder.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkBuilder.java
index 84ed1bc..a2ceb59 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkBuilder.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkBuilder.java
@@ -20,7 +20,6 @@ package org.apache.isis.viewer.restfulobjects.rendering;
 import javax.ws.rs.core.MediaType;
 
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
-import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.applib.RestfulHttpMethod;
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecs.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecs.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecs.java
new file mode 100644
index 0000000..ed033a9
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecs.java
@@ -0,0 +1,124 @@
+/*
+ *  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.viewer.restfulobjects.rendering;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.apache.isis.viewer.restfulobjects.applib.util.PathNode;
+import org.apache.isis.viewer.restfulobjects.rendering.util.FollowSpecUtil;
+
+import com.google.common.collect.Lists;
+
+public final class LinkFollowSpecs {
+
+    public final static LinkFollowSpecs create(final List<List<String>> links) {
+        final List<List<PathNode>> specs = FollowSpecUtil.asFollowSpecs(links);
+        return new LinkFollowSpecs(specs, Mode.FOLLOWING, null);
+    }
+
+    private enum Mode {
+        FOLLOWING, TERMINATED;
+    }
+
+    private final List<List<PathNode>> pathSpecs;
+    private final Mode mode;
+    // don't care about the key, just the criteria
+    private final List<PathNode> criteriaSpecs;
+
+    private LinkFollowSpecs(final List<List<PathNode>> pathSpecs, final Mode mode, final List<PathNode> criteriaSpecs) {
+        this.pathSpecs = pathSpecs;
+        this.mode = mode;
+        this.criteriaSpecs = criteriaSpecs;
+    }
+
+    /**
+     * A little algebra...
+     */
+    public LinkFollowSpecs follow(final String pathTemplate, final Object... args) {
+        final String path = String.format(pathTemplate, args);
+        if (path == null) {
+            return terminated();
+        }
+        if (mode == Mode.TERMINATED) {
+            return terminated();
+        }
+        final PathNode candidate = PathNode.parse(path);
+        if (mode == Mode.FOLLOWING) {
+            List<List<PathNode>> remainingPathSpecs = Lists.newArrayList();
+            List<PathNode> firstSpecs = Lists.newArrayList();
+            for(List<PathNode> spec: pathSpecs) {
+                if(spec.isEmpty()) {
+                    continue;
+                }
+                PathNode first = spec.get(0);
+                if(candidate.equals(first)) {
+                    List<PathNode> remaining = spec.subList(1, spec.size());
+                    firstSpecs.add(first);
+                    remainingPathSpecs.add(remaining);
+                }
+            }
+            if(!remainingPathSpecs.isEmpty()) {
+                return new LinkFollowSpecs(remainingPathSpecs, Mode.FOLLOWING, firstSpecs);
+            }
+            return terminated();
+        }
+        return terminated();
+    }
+
+    private static LinkFollowSpecs terminated() {
+        return new LinkFollowSpecs(Collections.<List<PathNode>>emptyList(), Mode.TERMINATED, Collections.<PathNode>emptyList());
+    }
+
+    /**
+     * Not public API; use {@link #matches(JsonRepresentation)}.
+     */
+    boolean isFollowing() {
+        return mode == Mode.FOLLOWING;
+    }
+
+    public boolean isTerminated() {
+        return mode == Mode.TERMINATED;
+    }
+
+    /**
+     * Ensure that every key present in the provided map matches the criterium.
+     * 
+     * <p>
+     * Any keys in the criterium are ignored (these were matched on during the
+     * {@link #follow(String, Object...)} call).
+     */
+    public boolean matches(final JsonRepresentation link) {
+        if (!isFollowing()) {
+            return false;
+        }
+        if(criteriaSpecs == null) {
+            return true;
+        }
+        for (PathNode criteriaSpec : criteriaSpecs) {
+            if(criteriaSpec.matches(link)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollower.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollower.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollower.java
deleted file mode 100644
index 3818ff8..0000000
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollower.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- *  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.viewer.restfulobjects.rendering;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
-import org.apache.isis.viewer.restfulobjects.applib.util.PathNode;
-import org.apache.isis.viewer.restfulobjects.rendering.util.GraphUtil;
-
-@SuppressWarnings({ "rawtypes", "unchecked" })
-public final class LinkFollower {
-
-    public final static LinkFollower create(final List<List<String>> links) {
-        final Map<PathNode, Map> graph = GraphUtil.asGraph(links);
-        return new LinkFollower(graph, Mode.FOLLOWING, PathNode.NULL);
-    }
-
-    private enum Mode {
-        FOLLOWING, TERMINATED;
-    }
-
-    private final Map<PathNode, Map> graph;
-    private final Mode mode;
-    private final PathNode root;
-
-    private LinkFollower(final Map<PathNode, Map> graph, final Mode mode, final PathNode root) {
-        this.graph = graph;
-        this.mode = mode;
-        this.root = root;
-    }
-
-    /**
-     * A little algebra...
-     */
-    public LinkFollower follow(final String pathTemplate, final Object... args) {
-        final String path = String.format(pathTemplate, args);
-        if (path == null) {
-            return terminated(PathNode.NULL);
-        }
-        if (mode == Mode.TERMINATED) {
-            return terminated(this.root);
-        }
-        final PathNode node = PathNode.parse(path);
-        if (mode == Mode.FOLLOWING) {
-            final Map<PathNode, Map> remaining = graph.get(node);
-            if (remaining != null) {
-                final PathNode key = findKey(node);
-                return new LinkFollower(remaining, Mode.FOLLOWING, key);
-            } else {
-                return terminated(node);
-            }
-        }
-        return terminated(node);
-    }
-
-    /**
-     * somewhat bizarre, but we have to find the actual node that is in the
-     * graph; the one we matching on doesn't match on the
-     * {@link PathNode#getCriteria()} map.
-     */
-    private PathNode findKey(final PathNode node) {
-        final Set<PathNode> keySet = graph.keySet();
-        for (final PathNode key : keySet) {
-            if (key.equals(node)) {
-                return key;
-            }
-        }
-        // shouldn't happen
-        return node;
-    }
-
-    private static LinkFollower terminated(final PathNode node) {
-        return new LinkFollower(null, Mode.TERMINATED, node);
-    }
-
-    /**
-     * Not public API; use {@link #matches(JsonRepresentation)}.
-     */
-    boolean isFollowing() {
-        return mode == Mode.FOLLOWING;
-    }
-
-    public boolean isTerminated() {
-        return mode == Mode.TERMINATED;
-    }
-
-    public Map<String, String> criteria() {
-        return Collections.unmodifiableMap(root.getCriteria());
-    }
-
-    /**
-     * Ensure that every key present in the provided map matches the criterium.
-     * 
-     * <p>
-     * Any keys in the criterium that are not present in the map will be
-     * ignored.
-     */
-    public boolean matches(final JsonRepresentation link) {
-        if (!isFollowing()) {
-            return false;
-        }
-        return root == null || root.matches(link);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/RendererFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/RendererFactory.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/RendererFactory.java
index d05d712..14d51a5 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/RendererFactory.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/RendererFactory.java
@@ -25,6 +25,6 @@ public interface RendererFactory {
 
     RepresentationType getRepresentationType();
 
-    ReprRenderer<?, ?> newRenderer(RendererContext resourceContext, LinkFollower linkFollower, JsonRepresentation representation);
+    ReprRenderer<?, ?> newRenderer(RendererContext resourceContext, LinkFollowSpecs linkFollower, JsonRepresentation representation);
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java
index 1bbf026..171113d 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java
@@ -34,13 +34,13 @@ import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.DomainTypeRep
 public abstract class ReprRendererAbstract<R extends ReprRendererAbstract<R, T>, T> implements ReprRenderer<R, T> {
 
     protected final RendererContext rendererContext;
-    private final LinkFollower linkFollower;
+    private final LinkFollowSpecs linkFollower;
     private final RepresentationType representationType;
     protected final JsonRepresentation representation;
 
     protected boolean includesSelf;
 
-    public ReprRendererAbstract(final RendererContext rendererContext, final LinkFollower linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
+    public ReprRendererAbstract(final RendererContext rendererContext, final LinkFollowSpecs linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
         this.rendererContext = rendererContext;
         this.linkFollower = asProvidedElseCreate(linkFollower);
         this.representationType = representationType;
@@ -51,15 +51,15 @@ public abstract class ReprRendererAbstract<R extends ReprRendererAbstract<R, T>,
         return rendererContext;
     }
 
-    public LinkFollower getLinkFollower() {
+    public LinkFollowSpecs getLinkFollowSpecs() {
         return linkFollower;
     }
 
-    private LinkFollower asProvidedElseCreate(final LinkFollower linkFollower) {
+    private LinkFollowSpecs asProvidedElseCreate(final LinkFollowSpecs linkFollower) {
         if (linkFollower != null) {
             return linkFollower;
         }
-        return LinkFollower.create(rendererContext.getFollowLinks());
+        return LinkFollowSpecs.create(rendererContext.getFollowLinks());
     }
 
     @Override
@@ -73,17 +73,21 @@ public abstract class ReprRendererAbstract<R extends ReprRendererAbstract<R, T>,
         return (R) this;
     }
 
-    public R withSelf(final String href) {
+    public R withSelf(final JsonRepresentation link) {
+        return withLink(Rel.SELF, link);
+    }
+
+    public R withLink(final Rel rel, final String href) {
         if (href != null) {
-            getLinks().arrayAdd(LinkBuilder.newBuilder(rendererContext, Rel.SELF.getName(), representationType, href).build());
+            getLinks().arrayAdd(LinkBuilder.newBuilder(rendererContext, rel.getName(), representationType, href).build());
         }
         return cast(this);
     }
 
-    public R withSelf(final JsonRepresentation link) {
-        final String rel = link.getString("rel");
-        if (rel == null || !rel.equals(Rel.SELF.getName())) {
-            throw new IllegalArgumentException("Provided link does not have a 'rel' of 'self'; was: " + link);
+    public R withLink(final Rel rel, final JsonRepresentation link) {
+        final String relStr = link.getString("rel");
+        if (relStr == null || !relStr.equals(rel.getName())) {
+            throw new IllegalArgumentException("Provided link does not have a 'rel' of '" + rel.getName() + "'; was: " + link);
         }
         if (link != null) {
             getLinks().arrayAdd(link);
@@ -91,6 +95,7 @@ public abstract class ReprRendererAbstract<R extends ReprRendererAbstract<R, T>,
         return cast(this);
     }
 
+
     /**
      * Will lazily create links array as required
      */

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java
index c4d19e0..d15ce72 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java
@@ -25,7 +25,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 import org.codehaus.jackson.node.NullNode;
@@ -65,7 +65,7 @@ public abstract class AbstractObjectMemberReprRenderer<R extends ReprRendererAbs
 
     private final Where where;
 
-    public AbstractObjectMemberReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final RepresentationType representationType, final JsonRepresentation representation, Where where) {
+    public AbstractObjectMemberReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final RepresentationType representationType, final JsonRepresentation representation, Where where) {
         super(resourceContext, linkFollower, representationType, representation);
         this.where = where;
     }
@@ -209,8 +209,8 @@ public abstract class AbstractObjectMemberReprRenderer<R extends ReprRendererAbs
         final JsonRepresentation link = linkTo.memberBuilder(Rel.DETAILS, memberType, objectMember).build();
         getLinks().arrayAdd(link);
 
-        final LinkFollower membersLinkFollower = getLinkFollower();
-        final LinkFollower detailsLinkFollower = membersLinkFollower.follow("links[rel=%s]", Rel.DETAILS.getName());
+        final LinkFollowSpecs membersLinkFollower = getLinkFollowSpecs();
+        final LinkFollowSpecs detailsLinkFollower = membersLinkFollower.follow("links[rel=%s]", Rel.DETAILS.getName());
         if (membersLinkFollower.matches(representation) && detailsLinkFollower.matches(link)) {
             followDetailsLink(link);
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java
index 1ee3973..3623d81 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java
@@ -29,7 +29,7 @@ import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.applib.domainobjects.ActionResultRepresentation.ResultType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 
@@ -42,7 +42,7 @@ public class ActionResultReprRenderer extends ReprRendererAbstract<ActionResultR
     private JsonRepresentation arguments;
     private ObjectAdapter returnedAdapter;
 
-    public ActionResultReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public ActionResultReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.ACTION_RESULT, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
index 42294aa..737e5f8 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
@@ -38,7 +38,7 @@ import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.applib.RestfulHttpMethod;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.DomainTypeReprRenderer;
@@ -87,7 +87,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
     private ObjectAdapter objectAdapter;
     private Mode mode = Mode.REGULAR;
 
-    public DomainObjectReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public DomainObjectReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.DOMAIN_OBJECT, representation);
         usingLinkToBuilder(new DomainObjectLinkTo());
     }
@@ -184,7 +184,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
     }
 
     private void addAssociations(final ObjectAdapter objectAdapter, final JsonRepresentation members, final List<ObjectAssociation> associations) {
-        final LinkFollower linkFollower = getLinkFollower().follow("members");
+        final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("members");
         for (final ObjectAssociation assoc : associations) {
 
             if (mode.checkVisibility()) {
@@ -224,7 +224,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
     }
 
     private void addActions(final ObjectAdapter objectAdapter, final List<ObjectAction> actions, final JsonRepresentation members) {
-        final LinkFollower linkFollower = getLinkFollower().follow("members");
+        final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("members");
         for (final ObjectAction action : actions) {
             final Consent visibility = action.isVisible(getAuthenticationSession(), objectAdapter, rendererContext.getWhere());
             if (!visibility.isAllowed()) {

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
index 8ba44ad..94e1e65 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
@@ -23,7 +23,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 
@@ -34,7 +34,7 @@ public class ListReprRenderer extends ReprRendererAbstract<ListReprRenderer, Col
     private ObjectSpecification elementType;
     private ObjectSpecification returnType;
 
-    public ListReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public ListReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.LIST, representation);
         usingLinkToBuilder(new DomainObjectLinkTo());
     }
@@ -78,15 +78,16 @@ public class ListReprRenderer extends ReprRendererAbstract<ListReprRenderer, Col
         }
 
         final JsonRepresentation values = JsonRepresentation.newArray();
-        final LinkFollower linkFollower = getLinkFollower().follow("value");
 
         for (final ObjectAdapter adapter : objectAdapters) {
-            if (adapter.getSpecification().isHidden()) {
+            final ObjectSpecification specification = adapter.getSpecification();
+            if (specification.isHidden()) {
                 continue;
             }
             final JsonRepresentation linkToObject = linkTo.with(adapter).builder().build();
             values.arrayAdd(linkToObject);
 
+            final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("value");
             if (linkFollower.matches(linkToObject)) {
                 final DomainObjectReprRenderer renderer = new DomainObjectReprRenderer(getRendererContext(), linkFollower, JsonRepresentation.newMap());
                 final JsonRepresentation domainObject = renderer.with(adapter).render();

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
index 82d1d3c..7852044 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
@@ -28,7 +28,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.ActionDescriptionReprRenderer;
 import org.codehaus.jackson.node.NullNode;
@@ -37,7 +37,7 @@ import com.google.common.collect.Lists;
 
 public class ObjectActionReprRenderer extends AbstractObjectMemberReprRenderer<ObjectActionReprRenderer, ObjectAction> {
 
-    public ObjectActionReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public ObjectActionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.OBJECT_ACTION, representation, Where.OBJECT_FORMS);
     }
 
@@ -64,7 +64,7 @@ public class ObjectActionReprRenderer extends AbstractObjectMemberReprRenderer<O
      */
     @Override
     protected void followDetailsLink(final JsonRepresentation detailsLink) {
-        final ObjectActionReprRenderer renderer = new ObjectActionReprRenderer(getRendererContext(), getLinkFollower(), JsonRepresentation.newMap());
+        final ObjectActionReprRenderer renderer = new ObjectActionReprRenderer(getRendererContext(), getLinkFollowSpecs(), JsonRepresentation.newMap());
         renderer.with(new ObjectAndAction(objectAdapter, objectMember)).usingLinkTo(linkTo).asFollowed();
         detailsLink.mapPut("value", renderer.render());
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
index 46aec3e..e3db7c0 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
@@ -28,7 +28,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.CollectionDescriptionReprRenderer;
 
@@ -36,7 +36,7 @@ import com.google.common.collect.Lists;
 
 public class ObjectCollectionReprRenderer extends AbstractObjectMemberReprRenderer<ObjectCollectionReprRenderer, OneToManyAssociation> {
 
-    public ObjectCollectionReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public ObjectCollectionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.OBJECT_COLLECTION, representation, Where.PARENTED_TABLES);
     }
 
@@ -88,7 +88,7 @@ public class ObjectCollectionReprRenderer extends AbstractObjectMemberReprRender
      */
     @Override
     protected void followDetailsLink(final JsonRepresentation detailsLink) {
-        final ObjectCollectionReprRenderer renderer = new ObjectCollectionReprRenderer(getRendererContext(), getLinkFollower(), JsonRepresentation.newMap());
+        final ObjectCollectionReprRenderer renderer = new ObjectCollectionReprRenderer(getRendererContext(), getLinkFollowSpecs(), JsonRepresentation.newMap());
         renderer.with(new ObjectAndCollection(objectAdapter, objectMember)).asFollowed();
         detailsLink.mapPut("value", renderer.render());
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java
index 0080524..1195ddf 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java
@@ -26,7 +26,7 @@ import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.PropertyDescriptionReprRenderer;
 import org.codehaus.jackson.node.NullNode;
@@ -35,7 +35,7 @@ import com.google.common.collect.Lists;
 
 public class ObjectPropertyReprRenderer extends AbstractObjectMemberReprRenderer<ObjectPropertyReprRenderer, OneToOneAssociation> {
 
-    public ObjectPropertyReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public ObjectPropertyReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.OBJECT_PROPERTY, representation, Where.OBJECT_FORMS);
     }
 
@@ -84,7 +84,7 @@ public class ObjectPropertyReprRenderer extends AbstractObjectMemberReprRenderer
      */
     @Override
     protected void followDetailsLink(final JsonRepresentation detailsLink) {
-        final ObjectPropertyReprRenderer renderer = new ObjectPropertyReprRenderer(getRendererContext(), getLinkFollower(), JsonRepresentation.newMap());
+        final ObjectPropertyReprRenderer renderer = new ObjectPropertyReprRenderer(getRendererContext(), getLinkFollowSpecs(), JsonRepresentation.newMap());
         renderer.with(new ObjectAndProperty(objectAdapter, objectMember)).asFollowed();
         detailsLink.mapPut("value", renderer.render());
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
index cf51c5a..f549211 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
@@ -22,7 +22,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererException;
@@ -32,7 +32,7 @@ public class ScalarValueReprRenderer extends ReprRendererAbstract<ScalarValueRep
     private final JsonValueEncoder jsonValueEncoder = new JsonValueEncoder();
     private ObjectSpecification returnType;
 
-    ScalarValueReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    ScalarValueReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, null, representation); // null for representationType (there is none)
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeFeatureReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeFeatureReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeFeatureReprRenderer.java
index 9101ec8..a67beb2 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeFeatureReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeFeatureReprRenderer.java
@@ -20,7 +20,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 
@@ -31,7 +31,7 @@ public abstract class AbstractTypeFeatureReprRenderer<R extends ReprRendererAbst
     protected ObjectSpecification objectSpecification;
     protected T objectFeature;
 
-    public AbstractTypeFeatureReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
+    public AbstractTypeFeatureReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, representationType, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeMemberReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeMemberReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeMemberReprRenderer.java
index 5424533..904b278 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeMemberReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/AbstractTypeMemberReprRenderer.java
@@ -21,7 +21,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.MemberType;
@@ -30,7 +30,7 @@ public abstract class AbstractTypeMemberReprRenderer<R extends ReprRendererAbstr
 
     protected MemberType memberType;
 
-    public AbstractTypeMemberReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
+    public AbstractTypeMemberReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, representationType, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionDescriptionReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionDescriptionReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionDescriptionReprRenderer.java
index 2388c09..87ca4c2 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionDescriptionReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionDescriptionReprRenderer.java
@@ -26,7 +26,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 
 public class ActionDescriptionReprRenderer extends AbstractTypeMemberReprRenderer<ActionDescriptionReprRenderer, ObjectAction> {
@@ -38,7 +38,7 @@ public class ActionDescriptionReprRenderer extends AbstractTypeMemberReprRendere
         return LinkBuilder.newBuilder(resourceContext, rel.getName(), RepresentationType.ACTION_DESCRIPTION, url);
     }
 
-    public ActionDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public ActionDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.ACTION_DESCRIPTION, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionParameterDescriptionReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionParameterDescriptionReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionParameterDescriptionReprRenderer.java
index 8c7a53f..333935b 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionParameterDescriptionReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/ActionParameterDescriptionReprRenderer.java
@@ -24,7 +24,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 
 public class ActionParameterDescriptionReprRenderer extends AbstractTypeFeatureReprRenderer<ActionParameterDescriptionReprRenderer, ObjectActionParameter> {
@@ -38,7 +38,7 @@ public class ActionParameterDescriptionReprRenderer extends AbstractTypeFeatureR
         return LinkBuilder.newBuilder(resourceContext, rel.andParam("id", deriveId(objectActionParameter)), RepresentationType.ACTION_PARAMETER_DESCRIPTION, url);
     }
 
-    public ActionParameterDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public ActionParameterDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.ACTION_PARAMETER_DESCRIPTION, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/CollectionDescriptionReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/CollectionDescriptionReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/CollectionDescriptionReprRenderer.java
index 28338e7..e89b2fe 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/CollectionDescriptionReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/CollectionDescriptionReprRenderer.java
@@ -22,7 +22,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 
 public class CollectionDescriptionReprRenderer extends AbstractTypeMemberReprRenderer<CollectionDescriptionReprRenderer, OneToManyAssociation> {
@@ -34,7 +34,7 @@ public class CollectionDescriptionReprRenderer extends AbstractTypeMemberReprRen
         return LinkBuilder.newBuilder(resourceContext, rel.getName(), RepresentationType.COLLECTION_DESCRIPTION, url);
     }
 
-    public CollectionDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public CollectionDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.COLLECTION_DESCRIPTION, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/DomainTypeReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/DomainTypeReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/DomainTypeReprRenderer.java
index 6a27775..c2e96ef 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/DomainTypeReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/DomainTypeReprRenderer.java
@@ -28,7 +28,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 import org.codehaus.jackson.node.NullNode;
@@ -45,7 +45,7 @@ public class DomainTypeReprRenderer extends ReprRendererAbstract<DomainTypeReprR
 
     private ObjectSpecification objectSpecification;
 
-    public DomainTypeReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public DomainTypeReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.DOMAIN_TYPE, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/PropertyDescriptionReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/PropertyDescriptionReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/PropertyDescriptionReprRenderer.java
index 8fa12fc..6e0ca01 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/PropertyDescriptionReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/PropertyDescriptionReprRenderer.java
@@ -23,7 +23,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 
 public class PropertyDescriptionReprRenderer extends AbstractTypeMemberReprRenderer<PropertyDescriptionReprRenderer, OneToOneAssociation> {
@@ -35,7 +35,7 @@ public class PropertyDescriptionReprRenderer extends AbstractTypeMemberReprRende
         return LinkBuilder.newBuilder(resourceContext, rel.getName(), RepresentationType.PROPERTY_DESCRIPTION, url);
     }
 
-    public PropertyDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public PropertyDescriptionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.PROPERTY_DESCRIPTION, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeActionResultReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeActionResultReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeActionResultReprRenderer.java
index 8a40a9c..62d69fc 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeActionResultReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeActionResultReprRenderer.java
@@ -20,7 +20,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.LinkRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 
@@ -30,7 +30,7 @@ public class TypeActionResultReprRenderer extends ReprRendererAbstract<TypeActio
     private LinkRepresentation selfLink;
     private Object value;
 
-    public TypeActionResultReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public TypeActionResultReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.TYPE_ACTION_RESULT, representation);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeListReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeListReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeListReprRenderer.java
index f7a1dd0..974be69 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeListReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeListReprRenderer.java
@@ -25,7 +25,7 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
-import org.apache.isis.viewer.restfulobjects.rendering.LinkFollower;
+import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 
@@ -33,7 +33,7 @@ public class TypeListReprRenderer extends ReprRendererAbstract<TypeListReprRende
 
     private Collection<ObjectSpecification> specifications;
 
-    public TypeListReprRenderer(final RendererContext resourceContext, final LinkFollower linkFollower, final JsonRepresentation representation) {
+    public TypeListReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.TYPE_LIST, representation);
     }
 
@@ -48,7 +48,7 @@ public class TypeListReprRenderer extends ReprRendererAbstract<TypeListReprRende
 
         // self
         if (includesSelf) {
-            withSelf("domainTypes");
+            withLink(Rel.SELF, "domainTypes");
         }
 
         final JsonRepresentation specList = JsonRepresentation.newArray();

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/FollowSpecUtil.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/FollowSpecUtil.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/FollowSpecUtil.java
new file mode 100644
index 0000000..27a662f
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/FollowSpecUtil.java
@@ -0,0 +1,50 @@
+/*
+ *  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.viewer.restfulobjects.rendering.util;
+
+import java.util.List;
+
+import org.apache.isis.viewer.restfulobjects.applib.util.PathNode;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+public final class FollowSpecUtil {
+
+    private FollowSpecUtil() {
+    }
+
+    public final static List<List<PathNode>> asFollowSpecs(final List<List<String>> links) {
+        return Lists.newArrayList(Iterables.transform(links, new Function<List<String>, List<PathNode>>() {
+
+            @Override
+            public List<PathNode> apply(List<String> pathParts) {
+                return Lists.newArrayList(Iterables.transform(pathParts, new Function<String, PathNode>(){
+
+                    @Override
+                    public PathNode apply(String input) {
+                        return PathNode.parse(input);
+                    }
+                }
+                ));
+            }
+        }));
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/GraphUtil.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/GraphUtil.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/GraphUtil.java
deleted file mode 100644
index c797b1f..0000000
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/GraphUtil.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  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.viewer.restfulobjects.rendering.util;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.isis.viewer.restfulobjects.applib.util.PathNode;
-
-import com.google.common.collect.Maps;
-
-@SuppressWarnings({ "rawtypes", "unchecked" })
-public final class GraphUtil {
-
-    private GraphUtil() {
-    }
-
-    public final static Map<PathNode, Map> asGraph(final List<List<String>> links) {
-        if (links == null) {
-            return Collections.emptyMap();
-        }
-        final Map<PathNode, Map> map = Maps.newHashMap();
-        for (final List<String> link : links) {
-            GraphUtil.mergeInto(link, map);
-        }
-        return map;
-    }
-
-    private static void mergeInto(final List<String> list, final Map<PathNode, Map> map) {
-        if (list.size() == 0) {
-            return;
-        }
-        final String str = list.get(0);
-        final PathNode node = PathNode.parse(str);
-        Map<PathNode, Map> submap = map.get(node);
-        if (submap == null) {
-            submap = Maps.newHashMap();
-            map.put(node, submap);
-        }
-        mergeInto(list.subList(1, list.size()), submap);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/GraphTest_asGraph.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/GraphTest_asGraph.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/GraphTest_asGraph.java
deleted file mode 100644
index 32d427c..0000000
--- a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/GraphTest_asGraph.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  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.viewer.restfulobjects.rendering;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.isis.viewer.restfulobjects.applib.util.Parser;
-import org.apache.isis.viewer.restfulobjects.applib.util.PathNode;
-import org.apache.isis.viewer.restfulobjects.rendering.util.GraphUtil;
-import org.junit.Test;
-
-@SuppressWarnings({ "rawtypes", "unchecked" })
-public class GraphTest_asGraph {
-
-    @Test
-    public void simple() throws Exception {
-        final List<List<String>> links = asListOfLists("a.b.c,a.b.d,d.b,e,e");
-        final Map<PathNode, Map> root = GraphUtil.asGraph(links);
-
-        assertThat(root.size(), is(3));
-        final Map<String, Map> nodeA = root.get(PathNode.parse("a"));
-        assertThat(nodeA.size(), is(1));
-        final Map<String, Map> nodeAB = nodeA.get(PathNode.parse("b"));
-        assertThat(nodeAB.size(), is(2));
-        final Map<String, Map> nodeABC = nodeAB.get(PathNode.parse("c"));
-        assertThat(nodeABC.size(), is(0));
-        final Map<String, Map> nodeABD = nodeAB.get(PathNode.parse("d"));
-        assertThat(nodeABD.size(), is(0));
-
-        final Map<String, Map> nodeD = root.get(PathNode.parse("d"));
-        assertThat(nodeD.size(), is(1));
-        final Map<String, Map> nodeDB = nodeD.get(PathNode.parse("b"));
-        assertThat(nodeDB.size(), is(0));
-
-        final Map<String, Map> nodeE = root.get(PathNode.parse("e"));
-        assertThat(nodeE.size(), is(0));
-    }
-
-    @Test
-    public void empty() throws Exception {
-        final List<List<String>> links = asListOfLists("");
-        final Map<PathNode, Map> root = GraphUtil.asGraph(links);
-
-        assertThat(root.size(), is(0));
-    }
-
-    @Test
-    public void whenNull() throws Exception {
-        final Map<PathNode, Map> root = GraphUtil.asGraph(null);
-
-        assertThat(root.size(), is(0));
-    }
-
-    private List<List<String>> asListOfLists(final String string) {
-        return Parser.forListOfListOfStrings().valueOf(string);
-    }
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee3241ac/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecsTest_follow.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecsTest_follow.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecsTest_follow.java
new file mode 100644
index 0000000..fab909e
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowSpecsTest_follow.java
@@ -0,0 +1,158 @@
+/*
+ *  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.viewer.restfulobjects.rendering;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.apache.isis.viewer.restfulobjects.applib.util.Parser;
+import org.junit.Test;
+
+public class LinkFollowSpecsTest_follow {
+
+    @Test
+    public void simple() throws Exception {
+        final List<List<String>> links = asListOfLists("a.b.c");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        assertThat(linkFollower.follow("a").isFollowing(), is(true));
+        assertThat(linkFollower.follow("a").isTerminated(), is(false));
+    }
+
+    @Test
+    public void notMatching() throws Exception {
+        final List<List<String>> links = asListOfLists("a.b.c");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        assertThat(linkFollower.follow("x").isFollowing(), is(false));
+        assertThat(linkFollower.follow("x").isTerminated(), is(true));
+    }
+
+    @Test
+    public void create_noCriteria() throws Exception {
+        final List<List<String>> links = asListOfLists("a.b.c");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        assertThat(linkFollower.matches(JsonRepresentation.newMap()), is(true));
+    }
+
+    @Test
+    public void follow_noCriteria() throws Exception {
+        final List<List<String>> links = asListOfLists("a.b.c");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        assertThat(linkFollower.matches(JsonRepresentation.newMap()), is(true));
+    }
+
+    @Test
+    public void follow_withSingleCriteria() throws Exception {
+        final List<List<String>> links = asListOfLists("a[x=y].b.c");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        assertThat(linkFollower.follow("x").isFollowing(), is(false));
+
+        final LinkFollowSpecs followA = linkFollower.follow("a");
+
+        assertThat(followA.isFollowing(), is(true));
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "y")), is(true));
+        assertThat(followA.matches(JsonRepresentation.newMap()), is(false));
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "z")), is(false));
+    }
+
+    @Test
+    public void follow_withMultipleCriteria() throws Exception {
+        final List<List<String>> links = asListOfLists("a[x=y z=w].b.c");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        assertThat(linkFollower.follow("x").isFollowing(), is(false));
+
+        final LinkFollowSpecs followA = linkFollower.follow("a");
+
+        assertThat(followA.isFollowing(), is(true));
+
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "y", "z", "w")), is(true));
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "y", "z", "w", "foo", "bar")), is(true));
+        assertThat(followA.matches(JsonRepresentation.newMap()), is(false));
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "y")), is(false));
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "y", "foo", "bar")), is(false));
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "bad")), is(false));
+        assertThat(followA.matches(JsonRepresentation.newMap("x", "y", "z", "bad")), is(false));
+    }
+
+
+    @Test
+    public void simple_multiplePaths() throws Exception {
+        final List<List<String>> links = asListOfLists("a.b.c,x.y.z");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        LinkFollowSpecs followA = linkFollower.follow("a");
+        assertThat(followA.isFollowing(), is(true));
+        assertThat(followA.isTerminated(), is(false));
+
+        LinkFollowSpecs followX = linkFollower.follow("x");
+        assertThat(followX.isFollowing(), is(true));
+        assertThat(followX.isTerminated(), is(false));
+        
+        LinkFollowSpecs followXY = followX.follow("y");
+        assertThat(followXY.isFollowing(), is(true));
+        assertThat(followXY.isTerminated(), is(false));
+        
+        LinkFollowSpecs followXYZ = followXY.follow("z");
+        assertThat(followXYZ.isFollowing(), is(true));
+        assertThat(followXYZ.isTerminated(), is(false));
+        
+        LinkFollowSpecs followXYZQ = followXY.follow("q");
+        assertThat(followXYZQ.isFollowing(), is(false));
+        assertThat(followXYZQ.isTerminated(), is(true));
+    }
+
+    @Test
+    public void multiplePaths_withCriteria() throws Exception {
+        final List<List<String>> links = asListOfLists("links[rel=urn:org.restfulobjects:rels/version].x,links[rel=urn:org.restfulobjects:rels/user].y");
+
+        final LinkFollowSpecs linkFollower = LinkFollowSpecs.create(links);
+
+        LinkFollowSpecs followRelVersion = linkFollower.follow("links[rel=urn:org.restfulobjects:rels/version]");
+        assertThat(followRelVersion.isFollowing(), is(true));
+        assertThat(followRelVersion.isTerminated(), is(false));
+        
+        assertThat(followRelVersion.follow("x").isFollowing(), is(true));
+
+        LinkFollowSpecs followRelUser = linkFollower.follow("links[rel=urn:org.restfulobjects:rels/user]");
+        assertThat(followRelUser.isFollowing(), is(true));
+        assertThat(followRelUser.isTerminated(), is(false));
+        assertThat(followRelUser.follow("y").isFollowing(), is(true));
+    }
+
+    
+    private List<List<String>> asListOfLists(final String string) {
+        return Parser.forListOfListOfStrings().valueOf(string);
+    }
+}