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/08 19:29:52 UTC

[11/32] ISIS-323: lots more refactoring of RO

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtils.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtils.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtils.java
new file mode 100644
index 0000000..21c85c4
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtils.java
@@ -0,0 +1,52 @@
+/*
+ *  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.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+
+public final class UrlParserUtils {
+
+    private final static Pattern OBJECT_OID = Pattern.compile(".*objects\\/(.+)");;
+    private final static Pattern DOMAIN_TYPE = Pattern.compile(".*domainTypes\\/([^/]+).*");;
+
+    public final static String oidFromLink(final JsonRepresentation link) {
+        final String href = link.getString("href");
+        final Matcher matcher = OBJECT_OID.matcher(href);
+        if (!matcher.matches()) {
+            return null;
+        }
+        return matcher.group(1);
+    }
+
+    public final static String domainTypeFrom(final JsonRepresentation link) {
+        return domainTypeFrom(link.getString("href"));
+    }
+
+    public static String domainTypeFrom(final String href) {
+        final Matcher matcher = DOMAIN_TYPE.matcher(href);
+        if (!matcher.matches()) {
+            return null;
+        }
+        return matcher.group(1);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/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
new file mode 100644
index 0000000..32d427c
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/GraphTest_asGraph.java
@@ -0,0 +1,77 @@
+/*
+ *  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/bb79d33e/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowerTest_follow.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowerTest_follow.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowerTest_follow.java
new file mode 100644
index 0000000..e2a38f5
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/LinkFollowerTest_follow.java
@@ -0,0 +1,122 @@
+/*
+ *  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 LinkFollowerTest_follow {
+
+    @Test
+    public void simple() throws Exception {
+        final List<List<String>> links = asListOfLists("a.b.c");
+
+        final LinkFollower linkFollower = LinkFollower.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 LinkFollower linkFollower = LinkFollower.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 LinkFollower linkFollower = LinkFollower.create(links);
+
+        assertThat(linkFollower.criteria().size(), is(0));
+        assertThat(linkFollower.matches(JsonRepresentation.newMap()), is(true));
+    }
+
+    @Test
+    public void follow_noCriteria() throws Exception {
+        final List<List<String>> links = asListOfLists("a.b.c");
+
+        final LinkFollower linkFollower = LinkFollower.create(links);
+
+        final LinkFollower followA = linkFollower.follow("a");
+
+        assertThat(followA.criteria().size(), is(0));
+        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 LinkFollower linkFollower = LinkFollower.create(links);
+
+        assertThat(linkFollower.follow("x").isFollowing(), is(false));
+
+        final LinkFollower followA = linkFollower.follow("a");
+
+        assertThat(followA.isFollowing(), is(true));
+        final Map<String, String> criteria = followA.criteria();
+        assertThat(criteria.size(), is(1));
+        assertThat(criteria.get("x"), is("y"));
+        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 LinkFollower linkFollower = LinkFollower.create(links);
+
+        assertThat(linkFollower.follow("x").isFollowing(), is(false));
+
+        final LinkFollower followA = linkFollower.follow("a");
+
+        assertThat(followA.isFollowing(), is(true));
+        final Map<String, String> criteria = followA.criteria();
+        assertThat(criteria.size(), is(2));
+
+        assertThat(criteria.get("x"), is("y"));
+        assertThat(criteria.get("z"), is("w"));
+        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));
+    }
+
+    private List<List<String>> asListOfLists(final String string) {
+        return Parser.forListOfListOfStrings().valueOf(string);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
new file mode 100644
index 0000000..b313c74
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
@@ -0,0 +1,368 @@
+/*
+ *  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.domainobjects;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.codehaus.jackson.node.BigIntegerNode;
+import org.codehaus.jackson.node.BooleanNode;
+import org.codehaus.jackson.node.DecimalNode;
+import org.codehaus.jackson.node.DoubleNode;
+import org.codehaus.jackson.node.IntNode;
+import org.codehaus.jackson.node.LongNode;
+import org.codehaus.jackson.node.TextNode;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(JMock.class)
+public class JsonValueEncoderTest_asAdapter {
+
+    private final Mockery context = new JUnit4Mockery();
+
+    private JsonValueEncoder jsonValueEncoder;
+    private JsonRepresentation representation;
+    private ObjectSpecification objectSpec;
+
+    private EncodableFacet encodableFacet;
+    private ObjectAdapter objectAdapter;
+
+    @Before
+    public void setUp() throws Exception {
+        objectSpec = context.mock(ObjectSpecification.class);
+        encodableFacet = context.mock(EncodableFacet.class);
+        objectAdapter = context.mock(ObjectAdapter.class);
+
+        representation = new JsonRepresentation(TextNode.valueOf("aString"));
+        jsonValueEncoder = new JsonValueEncoder();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenSpecIsNull() throws Exception {
+        jsonValueEncoder.asAdapter(null, representation);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenReprIsNull() throws Exception {
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        jsonValueEncoder.asAdapter(objectSpec, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenReprIsAnArray() throws Exception {
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        jsonValueEncoder.asAdapter(objectSpec, JsonRepresentation.newArray());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenReprIsAMap() throws Exception {
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        assertNull(jsonValueEncoder.asAdapter(objectSpec, JsonRepresentation.newMap()));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenSpecDoesNotHaveAnEncodableFacet() throws Exception {
+        allowingObjectSpecHas(EncodableFacet.class, null);
+
+        assertNull(jsonValueEncoder.asAdapter(objectSpec, representation));
+    }
+
+    @Test
+    public void whenReprIsBooleanPrimitive() throws Exception {
+        whenReprIsBoolean(boolean.class);
+    }
+
+    @Test
+    public void whenReprIsBooleanWrapper() throws Exception {
+        whenReprIsBoolean(Boolean.class);
+    }
+
+    private void whenReprIsBoolean(final Class<?> correspondingClass) {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(correspondingClass);
+        final boolean value = true;
+        representation = new JsonRepresentation(BooleanNode.valueOf(value));
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).fromEncodedString("" + value);
+                will(returnValue(objectAdapter));
+            }
+        });
+
+        // when
+        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+
+        // then
+        assertSame(objectAdapter, adapter);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenObjectSpecIsBooleanButReprIsNot() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(boolean.class);
+
+        // when
+        jsonValueEncoder.asAdapter(objectSpec, representation);
+    }
+
+    @Test
+    public void whenReprIsIntegerPrimitive() throws Exception {
+        whenReprIsInteger(int.class);
+    }
+
+    @Test
+    public void whenReprIsIntegerWrapper() throws Exception {
+        whenReprIsInteger(Integer.class);
+    }
+
+    private void whenReprIsInteger(final Class<?> correspondingClass) {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(correspondingClass);
+        final int value = 123;
+        representation = new JsonRepresentation(IntNode.valueOf(value));
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).fromEncodedString("" + value);
+                will(returnValue(objectAdapter));
+            }
+        });
+
+        // when
+        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+
+        // then
+        assertSame(objectAdapter, adapter);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenObjectSpecIsIntegerButReprIsNot() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(int.class);
+
+        representation = JsonRepresentation.newMap("foo", "bar");
+
+        // when
+        jsonValueEncoder.asAdapter(objectSpec, representation);
+    }
+
+    @Test
+    public void whenReprIsLongPrimitive() throws Exception {
+        whenReprIsLong(long.class);
+    }
+
+    @Test
+    public void whenReprIsLongWrapper() throws Exception {
+        whenReprIsLong(Long.class);
+    }
+
+    private void whenReprIsLong(final Class<?> correspondingClass) {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(correspondingClass);
+        final long value = 1234567890L;
+        representation = new JsonRepresentation(LongNode.valueOf(value));
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).fromEncodedString("" + value);
+                will(returnValue(objectAdapter));
+            }
+        });
+
+        // when
+        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+
+        // then
+        assertSame(objectAdapter, adapter);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenObjectSpecIsLongButReprIsNot() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(long.class);
+
+        // when
+        jsonValueEncoder.asAdapter(objectSpec, representation);
+    }
+
+    @Test
+    public void whenReprIsDoublePrimitive() throws Exception {
+        whenReprIsDouble(double.class);
+    }
+
+    @Test
+    public void whenReprIsDoubleWrapper() throws Exception {
+        whenReprIsDouble(Double.class);
+    }
+
+    private void whenReprIsDouble(final Class<?> correspondingClass) {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(correspondingClass);
+        final double value = 123.45;
+        representation = new JsonRepresentation(DoubleNode.valueOf(value));
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).fromEncodedString("" + value);
+                will(returnValue(objectAdapter));
+            }
+        });
+
+        // when
+        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+
+        // then
+        assertSame(objectAdapter, adapter);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenObjectSpecIsDoubleButReprIsNot() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(double.class);
+
+        representation = JsonRepresentation.newMap("foo", "bar");
+
+        // when
+        jsonValueEncoder.asAdapter(objectSpec, representation);
+    }
+
+    @Test
+    public void whenReprIsBigInteger() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(BigInteger.class);
+        final BigInteger value = BigInteger.valueOf(123);
+        representation = new JsonRepresentation(BigIntegerNode.valueOf(value));
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).fromEncodedString("" + value);
+                will(returnValue(objectAdapter));
+            }
+        });
+
+        // when
+        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+
+        // then
+        assertSame(objectAdapter, adapter);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenObjectSpecIsBigIntegerButReprIsNot() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(BigInteger.class);
+
+        representation = JsonRepresentation.newMap("foo", "bar");
+
+        // when
+        jsonValueEncoder.asAdapter(objectSpec, representation);
+    }
+
+    @Test
+    public void whenReprIsBigDecimal() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(BigDecimal.class);
+        final BigDecimal value = new BigDecimal("123234234.45612312343535");
+        representation = new JsonRepresentation(DecimalNode.valueOf(value));
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).fromEncodedString("" + value);
+                will(returnValue(objectAdapter));
+            }
+        });
+
+        // when
+        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+
+        // then
+        assertSame(objectAdapter, adapter);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenObjectSpecIsBigDecimalButReprIsNot() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(BigDecimal.class);
+
+        representation = JsonRepresentation.newMap("foo", "bar");
+
+        // when
+        jsonValueEncoder.asAdapter(objectSpec, representation);
+    }
+
+    @Test
+    public void whenReprIsString() throws Exception {
+        // given
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        allowingObjectSpecCorrespondingClassIs(String.class);
+        representation = new JsonRepresentation(TextNode.valueOf("aString"));
+
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).fromEncodedString("aString");
+                will(returnValue(objectAdapter));
+            }
+        });
+
+        // when
+        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+
+        // then
+        assertSame(objectAdapter, adapter);
+    }
+
+    private <T extends Facet> void allowingObjectSpecHas(final Class<T> facetClass, final T encodableFacet) {
+        context.checking(new Expectations() {
+            {
+                allowing(objectSpec).getFacet(facetClass);
+                will(returnValue(encodableFacet));
+            }
+        });
+    }
+
+    private void allowingObjectSpecCorrespondingClassIs(final Class<?> result) {
+        context.checking(new Expectations() {
+            {
+                allowing(objectSpec).getCorrespondingClass();
+                will(returnValue(result));
+            }
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
new file mode 100644
index 0000000..584b883
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
@@ -0,0 +1,246 @@
+/*
+ *  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.domainobjects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(JMock.class)
+public class JsonValueEncoderTest_asObject {
+
+    private final Mockery context = new JUnit4Mockery();
+
+    private JsonValueEncoder jsonValueEncoder;
+    private JsonRepresentation representation;
+    private ObjectAdapter objectAdapter;
+    private ObjectSpecification objectSpec;
+
+    private EncodableFacet encodableFacet;
+    private Object encoded;
+
+    @Before
+    public void setUp() throws Exception {
+        objectAdapter = context.mock(ObjectAdapter.class);
+        objectSpec = context.mock(ObjectSpecification.class);
+
+        context.checking(new Expectations() {
+            {
+                allowing(objectAdapter).getSpecification();
+                will(returnValue(objectSpec));
+            }
+        });
+        encodableFacet = context.mock(EncodableFacet.class);
+
+        encoded = new Object();
+
+        jsonValueEncoder = new JsonValueEncoder();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenAdapterIsNull() throws Exception {
+        jsonValueEncoder.asObject(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void whenObjectAdapterIsNotSpecialCaseAndSpecIsNotEncodable() throws Exception {
+        allowingObjectSpecCorrespondingClassIs(String.class);
+        allowingObjectSpecHas(EncodableFacet.class, null);
+        jsonValueEncoder.asObject(objectAdapter);
+    }
+
+    @Test
+    public void whenBooleanPrimitive() throws Exception {
+        whenBoolean(boolean.class);
+    }
+
+    @Test
+    public void whenBooleanWrapper() throws Exception {
+        whenBoolean(Boolean.class);
+    }
+
+    private void whenBoolean(final Class<?> cls) {
+        allowingObjectSpecCorrespondingClassIs(cls);
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        never(encodableFacet);
+        context.checking(new Expectations() {
+            {
+                one(objectAdapter).getObject();
+                will(returnValue(true));
+            }
+        });
+        assertEquals(true, jsonValueEncoder.asObject(objectAdapter));
+    }
+
+    @Test
+    public void whenIntegerPrimitive() throws Exception {
+        whenInteger(int.class);
+    }
+
+    @Test
+    public void whenIntegerWrapper() throws Exception {
+        whenInteger(Integer.class);
+    }
+
+    private void whenInteger(final Class<?> cls) {
+        allowingObjectSpecCorrespondingClassIs(cls);
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        never(encodableFacet);
+        context.checking(new Expectations() {
+            {
+                one(objectAdapter).getObject();
+                will(returnValue(123));
+            }
+        });
+        assertEquals(123, jsonValueEncoder.asObject(objectAdapter));
+    }
+
+    @Test
+    public void whenLongPrimitive() throws Exception {
+        whenLong(long.class);
+    }
+
+    @Test
+    public void whenLongWrapper() throws Exception {
+        whenLong(Long.class);
+    }
+
+    private void whenLong(final Class<?> cls) {
+        allowingObjectSpecCorrespondingClassIs(cls);
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        never(encodableFacet);
+        context.checking(new Expectations() {
+            {
+                one(objectAdapter).getObject();
+                will(returnValue(123456789L));
+            }
+        });
+        assertEquals(123456789L, jsonValueEncoder.asObject(objectAdapter));
+    }
+
+    @Test
+    public void whenDoublePrimitive() throws Exception {
+        whenDouble(double.class);
+    }
+
+    @Test
+    public void whenDoubleWrapper() throws Exception {
+        whenDouble(Double.class);
+    }
+
+    private void whenDouble(final Class<?> cls) {
+        allowingObjectSpecCorrespondingClassIs(cls);
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        never(encodableFacet);
+        context.checking(new Expectations() {
+            {
+                one(objectAdapter).getObject();
+                will(returnValue(12345.6789));
+            }
+        });
+        assertEquals(12345.6789, jsonValueEncoder.asObject(objectAdapter));
+    }
+
+    @Test
+    public void whenBigInteger() throws Exception {
+        allowingObjectSpecCorrespondingClassIs(BigInteger.class);
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        never(encodableFacet);
+        final BigInteger value = new BigInteger("123456789012345");
+        context.checking(new Expectations() {
+
+            {
+                one(objectAdapter).getObject();
+                will(returnValue(value));
+            }
+        });
+        assertEquals(value, jsonValueEncoder.asObject(objectAdapter));
+    }
+
+    @Test
+    public void whenBigDecimal() throws Exception {
+        allowingObjectSpecCorrespondingClassIs(BigDecimal.class);
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        never(encodableFacet);
+        final BigDecimal value = new BigDecimal("1234567890.1234567890");
+        context.checking(new Expectations() {
+
+            {
+                one(objectAdapter).getObject();
+                will(returnValue(value));
+            }
+        });
+        assertEquals(value, jsonValueEncoder.asObject(objectAdapter));
+    }
+
+    @Test
+    public void whenString() throws Exception {
+        allowingObjectSpecCorrespondingClassIs(String.class);
+        allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
+        context.checking(new Expectations() {
+            {
+                one(encodableFacet).toEncodedString(objectAdapter);
+                will(returnValue("encodedString"));
+            }
+        });
+        assertSame("encodedString", jsonValueEncoder.asObject(objectAdapter));
+    }
+
+    private void allowingObjectSpecCorrespondingClassIs(final Class<?> result) {
+        context.checking(new Expectations() {
+            {
+                allowing(objectSpec).getCorrespondingClass();
+                will(returnValue(result));
+            }
+        });
+    }
+
+    private <T extends Facet> void allowingObjectSpecHas(final Class<T> facetClass, final T encodableFacet) {
+        context.checking(new Expectations() {
+            {
+                allowing(objectSpec).getFacet(facetClass);
+                will(returnValue(encodableFacet));
+            }
+        });
+    }
+
+    private void never(final EncodableFacet encodableFacet2) {
+        context.checking(new Expectations() {
+            {
+                never(encodableFacet2);
+            }
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/MapUtilsTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/MapUtilsTest.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/MapUtilsTest.java
new file mode 100644
index 0000000..56a80cf
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/MapUtilsTest.java
@@ -0,0 +1,49 @@
+/*
+ *  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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+public class MapUtilsTest {
+
+    @Test
+    public void happyCase() throws Exception {
+        final Map<String, String> map = MapUtils.mapOf("foo", "bar", "foz", "boz");
+        assertThat(map.get("foo"), is("bar"));
+        assertThat(map.get("foz"), is("boz"));
+        assertThat(map.size(), is(2));
+    }
+
+    @Test
+    public void emptyList() throws Exception {
+        final Map<String, String> map = MapUtils.mapOf();
+        assertThat(map.size(), is(0));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void uneven() throws Exception {
+        MapUtils.mapOf("foo");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtilsTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtilsTest.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtilsTest.java
new file mode 100644
index 0000000..f6956aa
--- /dev/null
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/util/UrlParserUtilsTest.java
@@ -0,0 +1,60 @@
+/*
+ *  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 static org.junit.Assert.assertEquals;
+
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.junit.Test;
+
+public class UrlParserUtilsTest {
+
+    @Test
+    public void oidFromLink() throws Exception {
+        final JsonRepresentation link = JsonRepresentation.newMap();
+        link.mapPut("href", "http://localhost/objects/OID:1");
+        final String oidFromHref = UrlParserUtils.oidFromLink(link);
+        assertEquals("OID:1", oidFromHref);
+    }
+
+    @Test
+    public void domainTypeFromLink() throws Exception {
+        final JsonRepresentation link = JsonRepresentation.newMap();
+        link.mapPut("href", "http://localhost/domainTypes/com.mycompany.myapp.Customer");
+        final String oidFromHref = UrlParserUtils.domainTypeFrom(link);
+        assertEquals("com.mycompany.myapp.Customer", oidFromHref);
+    }
+
+    @Test
+    public void domainTypeFromLinkTrailingSlash() throws Exception {
+        final JsonRepresentation link = JsonRepresentation.newMap();
+        link.mapPut("href", "http://localhost/domainTypes/com.mycompany.myapp.Customer/");
+        final String oidFromHref = UrlParserUtils.domainTypeFrom(link);
+        assertEquals("com.mycompany.myapp.Customer", oidFromHref);
+    }
+
+    @Test
+    public void domainTypeFromLinkFollowingStuff() throws Exception {
+        final JsonRepresentation link = JsonRepresentation.newMap();
+        link.mapPut("href", "http://localhost/domainTypes/com.mycompany.myapp.Customer/otherStuffHere");
+        final String oidFromHref = UrlParserUtils.domainTypeFrom(link);
+        assertEquals("com.mycompany.myapp.Customer", oidFromHref);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/pom.xml
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/pom.xml b/component/viewer/restfulobjects/server/pom.xml
new file mode 100644
index 0000000..e424fac
--- /dev/null
+++ b/component/viewer/restfulobjects/server/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.isis.viewer</groupId>
+		<artifactId>isis-viewer-restfulobjects</artifactId>
+		<version>2.0.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>isis-viewer-restfulobjects-server</artifactId>
+	<name>Isis RestfulObjects Viewer Server</name>
+
+	<properties>
+		<siteBaseDir>..</siteBaseDir>
+		<relativeUrl>viewer/</relativeUrl>
+	</properties>
+
+    <!-- used in Site generation for relative references. -->
+    <url>http://isis.apache.org/${relativeUrl}</url>
+
+	<dependencies>
+
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-unittestsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.isis.viewer</groupId>
+            <artifactId>isis-viewer-restfulobjects-rendering</artifactId>
+        </dependency>
+
+
+        <!-- the javax:* equivalents of these are excluded in 
+             dependencyManagement of resteasy-jaxrs, so  
+             are required here -->           
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_2.5_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-annotation_1.0_spec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-activation_1.1_spec</artifactId>
+        </dependency>
+
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/AbstractJaxRsApplication.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/AbstractJaxRsApplication.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/AbstractJaxRsApplication.java
new file mode 100644
index 0000000..3e462ce
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/AbstractJaxRsApplication.java
@@ -0,0 +1,53 @@
+/*
+ *  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.server;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.ws.rs.core.Application;
+
+public abstract class AbstractJaxRsApplication extends Application {
+
+    private final Set<Object> singletons = new LinkedHashSet<Object>();
+    private final Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
+
+    public AbstractJaxRsApplication() {
+    }
+
+    @Override
+    public Set<Class<?>> getClasses() {
+        return Collections.unmodifiableSet(classes);
+    }
+
+    @Override
+    public Set<Object> getSingletons() {
+        return Collections.unmodifiableSet(singletons);
+    }
+
+    protected boolean addClass(final Class<?> cls) {
+        return classes.add(cls);
+    }
+
+    protected boolean addSingleton(final Object resource) {
+        return singletons.add(resource);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/HasHttpStatusCode.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/HasHttpStatusCode.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/HasHttpStatusCode.java
new file mode 100644
index 0000000..360948d
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/HasHttpStatusCode.java
@@ -0,0 +1,26 @@
+/*
+ *  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.server;
+
+import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse.HttpStatusCode;
+
+public interface HasHttpStatusCode {
+
+    HttpStatusCode getHttpStatusCode();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java
new file mode 100644
index 0000000..ab6f7a3
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java
@@ -0,0 +1,255 @@
+/*
+ *  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.server;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.apache.isis.viewer.restfulobjects.applib.MediaTypes;
+import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
+import org.apache.isis.viewer.restfulobjects.applib.RestfulRequest.RequestParameter;
+import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse.HttpStatusCode;
+import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
+import org.apache.isis.viewer.restfulobjects.server.resources.DomainResourceHelper;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+public class ResourceContext implements RendererContext {
+
+    private final HttpHeaders httpHeaders;
+    private final UriInfo uriInfo;
+    private final Request request;
+    private final HttpServletRequest httpServletRequest;
+    private final HttpServletResponse httpServletResponse;
+    private final SecurityContext securityContext;
+    private final Localization localization;
+
+    @SuppressWarnings("unused")
+    private final IsisConfiguration configuration;
+    private final AuthenticationSession authenticationSession;
+    private final PersistenceSession persistenceSession;
+    private final AdapterManager adapterManager;
+    private final SpecificationLoader specificationLookup;
+
+    private List<List<String>> followLinks;
+
+    private final static Predicate<MediaType> MEDIA_TYPE_NOT_GENERIC_APPLICATION_JSON = new Predicate<MediaType>() {
+        @Override
+        public boolean apply(final MediaType mediaType) {
+            return !mediaType.equals(MediaType.APPLICATION_JSON_TYPE);
+        }
+    };
+    private final static Predicate<MediaType> MEDIA_TYPE_CONTAINS_PROFILE = new Predicate<MediaType>() {
+        @Override
+        public boolean apply(final MediaType mediaType) {
+            return mediaType.getParameters().containsKey("profile");
+        }
+    };
+    private final Where where;
+    private JsonRepresentation readQueryStringAsMap;
+
+    public ResourceContext(
+            final RepresentationType representationType, 
+            final HttpHeaders httpHeaders, final UriInfo uriInfo, 
+            final Request request, 
+            final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, 
+            final SecurityContext securityContext,
+            final Localization localization, 
+            final AuthenticationSession authenticationSession, final PersistenceSession persistenceSession, 
+            final AdapterManager objectAdapterLookup, final SpecificationLoader specificationLookup, final IsisConfiguration configuration, final Where where) {
+
+        this.httpHeaders = httpHeaders;
+        this.uriInfo = uriInfo;
+        this.request = request;
+        this.httpServletRequest = httpServletRequest;
+        this.httpServletResponse = httpServletResponse;
+        this.securityContext = securityContext;
+        this.localization = localization;
+        this.configuration = configuration;
+        this.authenticationSession = authenticationSession;
+        this.persistenceSession = persistenceSession;
+        this.adapterManager = objectAdapterLookup;
+        this.specificationLookup = specificationLookup;
+        this.where = where;
+
+        init(representationType);
+    }
+
+    void init(final RepresentationType representationType) {
+        ensureCompatibleAcceptHeader(representationType);
+        this.followLinks = Collections.unmodifiableList(getArg(RequestParameter.FOLLOW_LINKS));
+    }
+
+    public HttpHeaders getHttpHeaders() {
+        return httpHeaders;
+    }
+
+    public String getQueryString() {
+        return getHttpServletRequest().getQueryString();
+    }
+
+    public JsonRepresentation getQueryStringAsJsonRepr() {
+        if (readQueryStringAsMap == null) {
+            readQueryStringAsMap = DomainResourceHelper.readQueryStringAsMap(getQueryString());
+        }
+        return readQueryStringAsMap;
+    }
+
+    public <Q> Q getArg(final RequestParameter<Q> requestParameter) {
+        final JsonRepresentation queryStringJsonRepr = getQueryStringAsJsonRepr();
+        return requestParameter.valueOf(queryStringJsonRepr);
+    }
+
+    public UriInfo getUriInfo() {
+        return uriInfo;
+    }
+
+    public Request getRequest() {
+        return request;
+    }
+
+    public HttpServletRequest getHttpServletRequest() {
+        return httpServletRequest;
+    }
+
+    public HttpServletResponse getServletResponse() {
+        return httpServletResponse;
+    }
+
+    public SecurityContext getSecurityContext() {
+        return securityContext;
+    }
+
+    private void ensureCompatibleAcceptHeader(final RepresentationType representationType) {
+        if (representationType == null) {
+            return;
+        }
+        final com.google.common.net.MediaType producedType = representationType.getMediaType();
+        
+        final List<MediaType> acceptableJaxRsMediaTypes = acceptableMediaTypes();
+        final List<com.google.common.net.MediaType> acceptableGuavaMediaTypes = Lists.transform(acceptableJaxRsMediaTypes, MediaTypes.JAXRS_TO_GUAVA);
+
+        // reimplemented below using guava
+//        for (final MediaType mediaType : acceptableJaxRsMediaTypes) {
+//            if (compatible(mediaType, representationType)) {
+//                return;
+//            }
+//        }
+        
+        if(Iterables.tryFind(acceptableGuavaMediaTypes, accepts(producedType)).isPresent()) {
+            return;
+        }
+        if (!contains(producedType, acceptableJaxRsMediaTypes)) {
+            throw RestfulObjectsApplicationException.create(HttpStatusCode.NOT_ACCEPTABLE, "Resource produces %s media type", representationType.getMediaType());
+        }
+    }
+
+    private static Predicate<com.google.common.net.MediaType> accepts(final com.google.common.net.MediaType producedType) {
+        return new Predicate<com.google.common.net.MediaType>() {
+            @Override
+            public boolean apply(com.google.common.net.MediaType input) {
+                return producedType.is(input);
+            }
+        };
+
+    }
+
+    protected boolean contains(final com.google.common.net.MediaType producedType, final List<MediaType> acceptableMediaTypes) {
+        return acceptableMediaTypes.contains(producedType);
+    }
+
+    /**
+     * If no media type has a profile parameter, then simply return all the
+     * media types.
+     * 
+     * <p>
+     * Otherwise, though, filter out the {@link MediaType#APPLICATION_JSON_TYPE
+     * generic application/json} media type if it is present.
+     */
+    private List<MediaType> acceptableMediaTypes() {
+        final List<MediaType> acceptableMediaTypes = getHttpHeaders().getAcceptableMediaTypes();
+        if (Collections2.filter(acceptableMediaTypes, MEDIA_TYPE_CONTAINS_PROFILE).isEmpty()) {
+            return acceptableMediaTypes;
+        }
+        return Lists.newArrayList(Iterables.filter(acceptableMediaTypes, MEDIA_TYPE_NOT_GENERIC_APPLICATION_JSON));
+    }
+
+    private boolean compatible(final MediaType acceptedMediaType, final RepresentationType representationType) {
+        final MediaType producedJaxRsMediaType = MediaTypes.guavaToJaxRs(representationType.getMediaType());
+        final String profile = acceptedMediaType.getParameters().get("profile");
+        return profile == null ? acceptedMediaType.isCompatible(producedJaxRsMediaType) : acceptedMediaType.equals(producedJaxRsMediaType);
+    }
+
+    public List<List<String>> getFollowLinks() {
+        return followLinks;
+    }
+
+    public String urlFor(final String url) {
+        return getUriInfo().getBaseUri().toString() + url;
+    }
+
+    public Localization getLocalization() {
+        return localization;
+    }
+
+    public AuthenticationSession getAuthenticationSession() {
+        return authenticationSession;
+    }
+
+    public AdapterManager getAdapterManager() {
+        return adapterManager;
+    }
+
+    public PersistenceSession getPersistenceSession() {
+        return persistenceSession;
+    }
+
+    public List<ObjectAdapter> getServiceAdapters() {
+        return persistenceSession.getServices();
+    }
+
+    public SpecificationLoader getSpecificationLookup() {
+        return specificationLookup;
+    }
+
+    public Where getWhere() {
+        return where;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
new file mode 100644
index 0000000..d29af4a
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
@@ -0,0 +1,58 @@
+/*
+ *  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.server;
+
+import org.apache.isis.viewer.restfulobjects.rendering.RendererFactoryRegistry;
+import org.apache.isis.viewer.restfulobjects.server.resources.DomainObjectResourceServerside;
+import org.apache.isis.viewer.restfulobjects.server.resources.DomainServiceResourceServerside;
+import org.apache.isis.viewer.restfulobjects.server.resources.DomainTypeResourceServerside;
+import org.apache.isis.viewer.restfulobjects.server.resources.HomePageReprRenderer;
+import org.apache.isis.viewer.restfulobjects.server.resources.HomePageResourceServerside;
+import org.apache.isis.viewer.restfulobjects.server.resources.UserReprRenderer;
+import org.apache.isis.viewer.restfulobjects.server.resources.UserResourceServerside;
+import org.apache.isis.viewer.restfulobjects.server.resources.VersionReprRenderer;
+import org.apache.isis.viewer.restfulobjects.server.resources.VersionResourceServerside;
+
+public class RestfulObjectsApplication extends AbstractJaxRsApplication {
+
+    public static final String SPEC_VERSION = "0.52";
+
+    public RestfulObjectsApplication() {
+        addClass(HomePageResourceServerside.class);
+        addClass(DomainTypeResourceServerside.class);
+        addClass(UserResourceServerside.class);
+        addClass(DomainObjectResourceServerside.class);
+        addClass(DomainServiceResourceServerside.class);
+        addClass(VersionResourceServerside.class);
+
+        addSingleton(new RestfulObjectsApplicationExceptionMapper());
+        addSingleton(new RuntimeExceptionMapper());
+        
+        RendererFactoryRegistry.instance.register(new HomePageReprRenderer.Factory());
+        RendererFactoryRegistry.instance.register(new UserReprRenderer.Factory());
+        RendererFactoryRegistry.instance.register(new VersionReprRenderer.Factory());
+
+        // TODO: doesn't get injected
+        // addSingleton(new TypedReprBuilderFactoryRegistry());
+
+        // TODO: idea being to remove the init()
+        // addSingleton(new PreProcessInterceptorForIsisSession());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationException.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationException.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationException.java
new file mode 100644
index 0000000..1ec9a87
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationException.java
@@ -0,0 +1,69 @@
+/*
+ *  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.server;
+
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse.HttpStatusCode;
+
+public class RestfulObjectsApplicationException extends RuntimeException implements HasHttpStatusCode {
+
+    public static final RestfulObjectsApplicationException create(final HttpStatusCode httpStatusCode) {
+        return create(httpStatusCode, null);
+    }
+
+    public static RestfulObjectsApplicationException create(final HttpStatusCode httpStatusCode, final String message, final Object... args) {
+        return create(httpStatusCode, (Exception) null, message, args);
+    }
+
+    public static RestfulObjectsApplicationException create(final HttpStatusCode httpStatusCode, final Exception cause) {
+        return create(httpStatusCode, cause, null);
+    }
+
+    public static RestfulObjectsApplicationException create(final HttpStatusCode httpStatusCode, final Exception cause, final String message, final Object... args) {
+        return new RestfulObjectsApplicationException(httpStatusCode, formatString(message, args), cause, null);
+    }
+
+    public static RestfulObjectsApplicationException create(final HttpStatusCode httpStatusCode, final JsonRepresentation repr, final String message, final Object... args) {
+        return new RestfulObjectsApplicationException(httpStatusCode, formatString(message, args), null, repr);
+    }
+
+    private static String formatString(final String formatStr, final Object... args) {
+        return formatStr != null ? String.format(formatStr, args) : null;
+    }
+
+    private static final long serialVersionUID = 1L;
+    private final HttpStatusCode httpStatusCode;
+    private final JsonRepresentation jsonRepresentation;
+
+    private RestfulObjectsApplicationException(final HttpStatusCode httpStatusCode, final String message, final Throwable ex, final JsonRepresentation jsonRepresentation) {
+        super(message, ex);
+        this.httpStatusCode = httpStatusCode;
+        this.jsonRepresentation = jsonRepresentation;
+    }
+
+    @Override
+    public HttpStatusCode getHttpStatusCode() {
+        return httpStatusCode;
+    }
+
+    public JsonRepresentation getJsonRepresentation() {
+        return jsonRepresentation;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
new file mode 100644
index 0000000..87e93d1
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
@@ -0,0 +1,120 @@
+/*
+ *  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.server;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import com.google.common.collect.Lists;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+import org.apache.isis.viewer.restfulobjects.applib.RestfulMediaType;
+import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse;
+import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
+
+@Provider
+public class RestfulObjectsApplicationExceptionMapper implements ExceptionMapper<RestfulObjectsApplicationException> {
+
+    @Override
+    public Response toResponse(final RestfulObjectsApplicationException ex) {
+        final ResponseBuilder builder = Response.status(ex.getHttpStatusCode().getJaxrsStatusType()).type(RestfulMediaType.APPLICATION_JSON_ERROR).entity(jsonFor(ex));
+        final String message = ex.getMessage();
+        if (message != null) {
+            builder.header(RestfulResponse.Header.WARNING.getName(), message);
+        }
+        return builder.build();
+    }
+
+    private static class ExceptionPojo {
+
+        public static ExceptionPojo create(final Exception ex) {
+            return new ExceptionPojo(ex);
+        }
+
+        private static String format(final StackTraceElement stackTraceElement) {
+            return stackTraceElement.toString();
+        }
+
+        private final int httpStatusCode;
+        private final String message;
+        private final List<String> stackTrace = Lists.newArrayList();
+        private ExceptionPojo causedBy;
+
+        public ExceptionPojo(final Throwable ex) {
+            httpStatusCode = getHttpStatusCodeIfAny(ex);
+            this.message = ex.getMessage();
+            final StackTraceElement[] stackTraceElements = ex.getStackTrace();
+            for (final StackTraceElement stackTraceElement : stackTraceElements) {
+                this.stackTrace.add(format(stackTraceElement));
+            }
+            final Throwable cause = ex.getCause();
+            if (cause != null && cause != ex) {
+                this.causedBy = new ExceptionPojo(cause);
+            }
+        }
+
+        private int getHttpStatusCodeIfAny(final Throwable ex) {
+            if (!(ex instanceof HasHttpStatusCode)) {
+                return 0;
+            }
+            final HasHttpStatusCode hasHttpStatusCode = (HasHttpStatusCode) ex;
+            return hasHttpStatusCode.getHttpStatusCode().getStatusCode();
+        }
+
+        @SuppressWarnings("unused")
+        public int getHttpStatusCode() {
+            return httpStatusCode;
+        }
+
+        @SuppressWarnings("unused")
+        public String getMessage() {
+            return message;
+        }
+
+        @SuppressWarnings("unused")
+        public List<String> getStackTrace() {
+            return stackTrace;
+        }
+
+        @SuppressWarnings("unused")
+        public ExceptionPojo getCausedBy() {
+            return causedBy;
+        }
+
+    }
+
+    static String jsonFor(final RestfulObjectsApplicationException ex) {
+        final JsonRepresentation jsonRepresentation = ex.getJsonRepresentation();
+        if (jsonRepresentation != null) {
+            return jsonRepresentation.toString();
+        }
+        try {
+            return JsonMapper.instance().write(ExceptionPojo.create(ex));
+        } catch (final Exception e) {
+            // fallback
+            return "{ \"exception\": \"" + ExceptionUtils.getFullStackTrace(ex) + "\" }";
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java
new file mode 100644
index 0000000..994f184
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java
@@ -0,0 +1,100 @@
+/*
+ *  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.server;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import com.google.common.collect.Lists;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+
+import org.apache.isis.viewer.restfulobjects.applib.RestfulMediaType;
+import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse.HttpStatusCode;
+import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
+
+@Provider
+public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
+
+    @Override
+    public Response toResponse(final RuntimeException ex) {
+        final ResponseBuilder builder = Response.status(HttpStatusCode.INTERNAL_SERVER_ERROR.getJaxrsStatusType()).type(RestfulMediaType.APPLICATION_JSON_ERROR).entity(jsonFor(ex));
+        return builder.build();
+    }
+
+    private static class ExceptionPojo {
+
+        public static ExceptionPojo create(final Exception ex) {
+            return new ExceptionPojo(ex);
+        }
+
+        private static String format(final StackTraceElement stackTraceElement) {
+            return stackTraceElement.toString();
+        }
+
+        private final String message;
+        private final List<String> stackTrace = Lists.newArrayList();
+        private ExceptionPojo causedBy;
+
+        public ExceptionPojo(final Throwable ex) {
+            this.message = messageFor(ex);
+            final StackTraceElement[] stackTraceElements = ex.getStackTrace();
+            for (final StackTraceElement stackTraceElement : stackTraceElements) {
+                this.stackTrace.add(format(stackTraceElement));
+            }
+            final Throwable cause = ex.getCause();
+            if (cause != null && cause != ex) {
+                this.causedBy = new ExceptionPojo(cause);
+            }
+        }
+
+        private static String messageFor(final Throwable ex) {
+            final String message = ex.getMessage();
+            return message != null ? message : ex.getClass().getName();
+        }
+
+        @SuppressWarnings("unused")
+        public String getMessage() {
+            return message;
+        }
+
+        @SuppressWarnings("unused")
+        public List<String> getStackTrace() {
+            return stackTrace;
+        }
+
+        @SuppressWarnings("unused")
+        public ExceptionPojo getCausedBy() {
+            return causedBy;
+        }
+    }
+
+    static String jsonFor(final Exception ex) {
+        try {
+            return JsonMapper.instance().write(ExceptionPojo.create(ex));
+        } catch (final Exception e) {
+            // fallback
+            return "{ \"exception\": \"" + ExceptionUtils.getFullStackTrace(ex) + "\" }";
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyBasicAuth.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyBasicAuth.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyBasicAuth.java
new file mode 100644
index 0000000..54bd2b6
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyBasicAuth.java
@@ -0,0 +1,79 @@
+/*
+ *  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.server.authentication;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.codec.binary.Base64;
+
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.runtime.authentication.AuthenticationManager;
+import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.webapp.auth.AuthenticationSessionStrategyAbstract;
+
+/**
+ * Implements the HTTP Basic Auth protocol; does not bind the
+ * {@link AuthenticationSession} onto the {@link HttpSession}.
+ */
+public class AuthenticationSessionStrategyBasicAuth extends AuthenticationSessionStrategyAbstract {
+
+    private static Pattern USER_AND_PASSWORD_REGEX = Pattern.compile("^(.+):(.+)$");
+
+    @Override
+    public AuthenticationSession lookupValid(final ServletRequest servletRequest, final ServletResponse servletResponse) {
+
+        final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+        final String authStr = httpServletRequest.getHeader("Authorization");
+
+        // value should be in the form:
+        // Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+        if (authStr == null || !authStr.startsWith("Basic ")) {
+            return null;
+        }
+        final String digest = authStr.substring(6);
+
+        final String userAndPassword = new String(new Base64().decode(digest.getBytes()));
+        final Matcher matcher = USER_AND_PASSWORD_REGEX.matcher(userAndPassword);
+        if (!matcher.matches()) {
+            return null;
+        }
+
+        final String user = matcher.group(1);
+        final String password = matcher.group(2);
+
+        final AuthenticationSession authSession = getAuthenticationManager().authenticate(new AuthenticationRequestPassword(user, password));
+        return authSession;
+    }
+
+    // //////////////////////////////////////////////////////////
+    // Dependencies (from context)
+    // //////////////////////////////////////////////////////////
+
+    protected AuthenticationManager getAuthenticationManager() {
+        return IsisContext.getAuthenticationManager();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyHeader.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyHeader.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyHeader.java
new file mode 100644
index 0000000..84bfb73
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyHeader.java
@@ -0,0 +1,66 @@
+/*
+ *  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.server.authentication;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
+import org.apache.isis.core.webapp.auth.AuthenticationSessionStrategyAbstract;
+
+/**
+ * Implements a home-grown protocol, whereby the user id and roles are passed
+ * using custom headers.
+ * 
+ * <p>
+ * Does not bind the {@link AuthenticationSession} onto the {@link HttpSession}.
+ */
+public class AuthenticationSessionStrategyHeader extends AuthenticationSessionStrategyAbstract {
+
+    @Override
+    public AuthenticationSession lookupValid(final ServletRequest servletRequest, final ServletResponse servletResponse) {
+
+        final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+        final String user = httpServletRequest.getHeader("isis.user");
+        final List<String> roles = rolesFrom(httpServletRequest);
+
+        if (Strings.isNullOrEmpty(user)) {
+            return null;
+        }
+        return new SimpleSession(user, roles);
+    }
+
+    protected List<String> rolesFrom(final HttpServletRequest httpServletRequest) {
+        final String rolesStr = httpServletRequest.getHeader("isis.roles");
+        if (rolesStr == null) {
+            return Collections.emptyList();
+        }
+        return Lists.newArrayList(Splitter.on(",").split(rolesStr));
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb79d33e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyTrusted.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyTrusted.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyTrusted.java
new file mode 100644
index 0000000..666ccc3
--- /dev/null
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/authentication/AuthenticationSessionStrategyTrusted.java
@@ -0,0 +1,42 @@
+/*
+ *  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.server.authentication;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.runtime.authentication.exploration.AuthenticationRequestExploration;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.webapp.auth.AuthenticationSessionStrategyDefault;
+
+public class AuthenticationSessionStrategyTrusted extends AuthenticationSessionStrategyDefault {
+
+    @Override
+    public AuthenticationSession lookupValid(final ServletRequest servletRequest, final ServletResponse servletResponse) {
+        final AuthenticationSession session = super.lookupValid(servletRequest, servletResponse);
+        if (session != null) {
+            return session;
+        }
+
+        // will always succeed.
+        final AuthenticationRequestExploration request = new AuthenticationRequestExploration();
+        return IsisContext.getAuthenticationManager().authenticate(request);
+    }
+}