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 2016/01/08 18:01:58 UTC

[1/4] isis git commit: ISIS-993: factored out LayoutMetadataService, renamed the metadata classes

Repository: isis
Updated Branches:
  refs/heads/ISIS-993 0ac8eda9a -> 2cb78cf01


http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java
deleted file mode 100644
index 8d4ce10..0000000
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java
+++ /dev/null
@@ -1,192 +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.core.metamodel.facets.actions.layout;
-
-import java.lang.reflect.Method;
-
-import org.jmock.Expectations;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import org.apache.isis.applib.annotation.ActionLayout;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
-import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessMethodContext;
-import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet;
-import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacetFallback;
-import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
-import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaPosition;
-import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet;
-import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-public class ActionLayoutAnnotationFacetFactoryTest extends AbstractFacetFactoryJUnit4TestCase {
-
-    ActionLayoutFacetFactory facetFactory;
-
-    @Before
-    public void setUp() throws Exception {
-        facetFactory = new ActionLayoutFacetFactory();
-        facetFactory.setSpecificationLoader(mockSpecificationLoaderSpi);
-    }
-
-    @Test
-    public void testActionLayoutAnnotationPickedUp() {
-
-        class Customer {
-            @SuppressWarnings("unused")
-            @ActionLayout(position = ActionLayout.Position.PANEL)
-            public String foz() {
-                return null;
-            }
-        }
-        final Method method = findMethod(Customer.class, "foz");
-
-        context.checking(new Expectations() {
-            {
-                allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
-                will(returnValue(mockObjSpec));
-
-                allowing(mockObjSpec).getFacet(MixinFacet.class);
-                will(returnValue(null));
-
-                allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
-                will(returnValue(null));
-            }
-        });
-
-        facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
-                facetedMethod));
-
-        final Facet facet = facetedMethod.getFacet(ActionPositionFacet.class);
-        Assert.assertNotNull(facet);
-        Assert.assertTrue(facet instanceof ActionPositionFacetForActionLayoutAnnotation);
-        final ActionPositionFacetForActionLayoutAnnotation actionLayoutFacetAnnotation = (ActionPositionFacetForActionLayoutAnnotation) facet;
-        Assert.assertEquals(ActionLayout.Position.PANEL, actionLayoutFacetAnnotation.position());
-    }
-
-    @Test
-    public void testActionLayoutFallbackPickedUp() {
-
-        class Customer {
-            @SuppressWarnings("unused")
-            // no @ActionLayout
-            public String foo() {
-                return null;
-            }
-        }
-        final Method method = findMethod(Customer.class, "foo");
-
-        context.checking(new Expectations() {
-            {
-                allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
-                will(returnValue(mockObjSpec));
-
-                allowing(mockObjSpec).getFacet(MixinFacet.class);
-                will(returnValue(null));
-
-                allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
-                will(returnValue(null));
-            }
-        });
-
-        facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
-                facetedMethod));
-
-        final Facet facet = facetedMethod.getFacet(ActionPositionFacet.class);
-        Assert.assertNotNull(facet);
-        Assert.assertTrue(facet instanceof ActionPositionFacetFallback);
-    }
-
-    public static class CssClassFa extends ActionLayoutAnnotationFacetFactoryTest {
-
-        @Test
-        public void testDefaultPosition() {
-
-            class Customer {
-                @SuppressWarnings("unused")
-                @ActionLayout(cssClassFa = "font-awesome")
-                public String foz() {
-                    return null;
-                }
-            }
-            final Method method = findMethod(Customer.class, "foz");
-
-            context.checking(new Expectations() {
-                {
-                    allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
-                    will(returnValue(mockObjSpec));
-
-                    allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
-                    will(returnValue(null));
-                }
-            });
-
-            facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
-                    facetedMethod));
-
-            Facet facet = facetedMethod.getFacet(CssClassFaFacet.class);
-            assertThat(facet, is(notNullValue()));
-            assertThat(facet, is(instanceOf(CssClassFaFacetForActionLayoutAnnotation.class)));
-            CssClassFaFacetForActionLayoutAnnotation classFaFacetForActionLayoutAnnotation = (CssClassFaFacetForActionLayoutAnnotation) facet;
-            assertThat(classFaFacetForActionLayoutAnnotation.value(), is(equalTo("fa fa-fw fa-font-awesome")));
-            assertThat(classFaFacetForActionLayoutAnnotation.getPosition(), is(CssClassFaPosition.LEFT));
-        }
-
-        @Test
-        public void testRightPosition() {
-
-            class Customer {
-                @SuppressWarnings("unused")
-                @ActionLayout(cssClassFa = "font-awesome", cssClassFaPosition = ActionLayout.CssClassFaPosition.RIGHT)
-                public String foz() {
-                    return null;
-                }
-            }
-            final Method method = findMethod(Customer.class, "foz");
-
-            context.checking(new Expectations() {
-                {
-                    allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
-                    will(returnValue(mockObjSpec));
-
-                    allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
-                    will(returnValue(null));
-                }
-            });
-
-            facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
-                    facetedMethod));
-
-            Facet facet = facetedMethod.getFacet(CssClassFaFacet.class);
-            assertThat(facet, is(notNullValue()));
-            assertThat(facet, is(instanceOf(CssClassFaFacetForActionLayoutAnnotation.class)));
-            CssClassFaFacetForActionLayoutAnnotation classFaFacetForActionLayoutAnnotation = (CssClassFaFacetForActionLayoutAnnotation) facet;
-            assertThat(classFaFacetForActionLayoutAnnotation.value(), is(equalTo("fa fa-fw fa-font-awesome")));
-            assertThat(classFaFacetForActionLayoutAnnotation.getPosition(), is(CssClassFaPosition.RIGHT));
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutXmlLayoutAnnotationFacetFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutXmlLayoutAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutXmlLayoutAnnotationFacetFactoryTest.java
new file mode 100644
index 0000000..18f4a69
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutXmlLayoutAnnotationFacetFactoryTest.java
@@ -0,0 +1,192 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License. */
+
+package org.apache.isis.core.metamodel.facets.actions.layout;
+
+import java.lang.reflect.Method;
+
+import org.jmock.Expectations;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
+import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessMethodContext;
+import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet;
+import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacetFallback;
+import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
+import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaPosition;
+import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet;
+import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+public class ActionLayoutXmlLayoutAnnotationFacetFactoryTest extends AbstractFacetFactoryJUnit4TestCase {
+
+    ActionLayoutFacetFactory facetFactory;
+
+    @Before
+    public void setUp() throws Exception {
+        facetFactory = new ActionLayoutFacetFactory();
+        facetFactory.setSpecificationLoader(mockSpecificationLoaderSpi);
+    }
+
+    @Test
+    public void testActionLayoutAnnotationPickedUp() {
+
+        class Customer {
+            @SuppressWarnings("unused")
+            @ActionLayout(position = ActionLayout.Position.PANEL)
+            public String foz() {
+                return null;
+            }
+        }
+        final Method method = findMethod(Customer.class, "foz");
+
+        context.checking(new Expectations() {
+            {
+                allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
+                will(returnValue(mockObjSpec));
+
+                allowing(mockObjSpec).getFacet(MixinFacet.class);
+                will(returnValue(null));
+
+                allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
+                will(returnValue(null));
+            }
+        });
+
+        facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
+                facetedMethod));
+
+        final Facet facet = facetedMethod.getFacet(ActionPositionFacet.class);
+        Assert.assertNotNull(facet);
+        Assert.assertTrue(facet instanceof ActionPositionFacetForActionLayoutAnnotation);
+        final ActionPositionFacetForActionLayoutAnnotation actionLayoutFacetAnnotation = (ActionPositionFacetForActionLayoutAnnotation) facet;
+        Assert.assertEquals(ActionLayout.Position.PANEL, actionLayoutFacetAnnotation.position());
+    }
+
+    @Test
+    public void testActionLayoutFallbackPickedUp() {
+
+        class Customer {
+            @SuppressWarnings("unused")
+            // no @ActionLayout
+            public String foo() {
+                return null;
+            }
+        }
+        final Method method = findMethod(Customer.class, "foo");
+
+        context.checking(new Expectations() {
+            {
+                allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
+                will(returnValue(mockObjSpec));
+
+                allowing(mockObjSpec).getFacet(MixinFacet.class);
+                will(returnValue(null));
+
+                allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
+                will(returnValue(null));
+            }
+        });
+
+        facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
+                facetedMethod));
+
+        final Facet facet = facetedMethod.getFacet(ActionPositionFacet.class);
+        Assert.assertNotNull(facet);
+        Assert.assertTrue(facet instanceof ActionPositionFacetFallback);
+    }
+
+    public static class CssClassFa extends ActionLayoutXmlLayoutAnnotationFacetFactoryTest {
+
+        @Test
+        public void testDefaultPosition() {
+
+            class Customer {
+                @SuppressWarnings("unused")
+                @ActionLayout(cssClassFa = "font-awesome")
+                public String foz() {
+                    return null;
+                }
+            }
+            final Method method = findMethod(Customer.class, "foz");
+
+            context.checking(new Expectations() {
+                {
+                    allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
+                    will(returnValue(mockObjSpec));
+
+                    allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
+                    will(returnValue(null));
+                }
+            });
+
+            facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
+                    facetedMethod));
+
+            Facet facet = facetedMethod.getFacet(CssClassFaFacet.class);
+            assertThat(facet, is(notNullValue()));
+            assertThat(facet, is(instanceOf(CssClassFaFacetForActionLayoutAnnotation.class)));
+            CssClassFaFacetForActionLayoutAnnotation classFaFacetForActionLayoutAnnotation = (CssClassFaFacetForActionLayoutAnnotation) facet;
+            assertThat(classFaFacetForActionLayoutAnnotation.value(), is(equalTo("fa fa-fw fa-font-awesome")));
+            assertThat(classFaFacetForActionLayoutAnnotation.getPosition(), is(CssClassFaPosition.LEFT));
+        }
+
+        @Test
+        public void testRightPosition() {
+
+            class Customer {
+                @SuppressWarnings("unused")
+                @ActionLayout(cssClassFa = "font-awesome", cssClassFaPosition = ActionLayout.CssClassFaPosition.RIGHT)
+                public String foz() {
+                    return null;
+                }
+            }
+            final Method method = findMethod(Customer.class, "foz");
+
+            context.checking(new Expectations() {
+                {
+                    allowing(mockSpecificationLoaderSpi).loadSpecification(Customer.class);
+                    will(returnValue(mockObjSpec));
+
+                    allowing(mockObjSpec).getFacet(DomainServiceFacet.class);
+                    will(returnValue(null));
+                }
+            });
+
+            facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, mockMethodRemover,
+                    facetedMethod));
+
+            Facet facet = facetedMethod.getFacet(CssClassFaFacet.class);
+            assertThat(facet, is(notNullValue()));
+            assertThat(facet, is(instanceOf(CssClassFaFacetForActionLayoutAnnotation.class)));
+            CssClassFaFacetForActionLayoutAnnotation classFaFacetForActionLayoutAnnotation = (CssClassFaFacetForActionLayoutAnnotation) facet;
+            assertThat(classFaFacetForActionLayoutAnnotation.value(), is(equalTo("fa fa-fw fa-font-awesome")));
+            assertThat(classFaFacetForActionLayoutAnnotation.getPosition(), is(CssClassFaPosition.RIGHT));
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefaultTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefaultTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefaultTest.java
deleted file mode 100644
index 4a843bd..0000000
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefaultTest.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.core.metamodel.facets.object.layoutxml;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.junit.Test;
-
-import org.apache.isis.applib.layout.v1_0.PropertyGroup;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertThat;
-
-public class LayoutXmlFacetDefaultTest {
-
-    @Test
-    public void xxx() throws Exception {
-
-        final AtomicReference<PropertyGroup> x = new AtomicReference<>();
-
-        PropertyGroup firstValue = new PropertyGroup();
-        PropertyGroup otherValue = new PropertyGroup();
-
-        assertThat(x.get(), is(nullValue()));
-
-        boolean b = x.compareAndSet(null, firstValue);
-        assertThat(b, is(true));
-        assertThat(x.get(), is(firstValue));
-
-        boolean b2 = x.compareAndSet(null, firstValue);
-        assertThat(b2, is(false));
-        assertThat(x.get(), is(firstValue));
-
-        boolean b3 = x.compareAndSet(null, otherValue);
-        assertThat(b3, is(false));
-        assertThat(x.get(), is(firstValue));
-
-        boolean b4 = x.compareAndSet(firstValue, otherValue);
-        assertThat(b4, is(true));
-        assertThat(x.get(), is(otherValue));
-
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefaultTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefaultTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefaultTest.java
new file mode 100644
index 0000000..5ff3426
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefaultTest.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.core.metamodel.facets.object.layoutxml;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.Test;
+
+import org.apache.isis.applib.layout.v1_0.PropertyGroup;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+public class ObjectLayoutMetadataFacetDefaultTest {
+
+    @Test
+    public void xxx() throws Exception {
+
+        final AtomicReference<PropertyGroup> x = new AtomicReference<>();
+
+        PropertyGroup firstValue = new PropertyGroup();
+        PropertyGroup otherValue = new PropertyGroup();
+
+        assertThat(x.get(), is(nullValue()));
+
+        boolean b = x.compareAndSet(null, firstValue);
+        assertThat(b, is(true));
+        assertThat(x.get(), is(firstValue));
+
+        boolean b2 = x.compareAndSet(null, firstValue);
+        assertThat(b2, is(false));
+        assertThat(x.get(), is(firstValue));
+
+        boolean b3 = x.compareAndSet(null, otherValue);
+        assertThat(b3, is(false));
+        assertThat(x.get(), is(firstValue));
+
+        boolean b4 = x.compareAndSet(firstValue, otherValue);
+        assertThat(b4, is(true));
+        assertThat(x.get(), is(otherValue));
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/DomainObjectTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/DomainObjectTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/DomainObjectTest.java
deleted file mode 100644
index a8d06c0..0000000
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/DomainObjectTest.java
+++ /dev/null
@@ -1,121 +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.core.metamodel.layoutxml.v1_0;
-
-import java.util.Map;
-
-import javax.xml.bind.Marshaller;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import org.apache.isis.applib.layout.v1_0.Action;
-import org.apache.isis.applib.layout.v1_0.Collection;
-import org.apache.isis.applib.layout.v1_0.Column;
-import org.apache.isis.applib.layout.v1_0.DomainObject;
-import org.apache.isis.applib.layout.v1_0.Property;
-import org.apache.isis.applib.layout.v1_0.PropertyGroup;
-import org.apache.isis.applib.layout.v1_0.Tab;
-import org.apache.isis.applib.layout.v1_0.TabGroup;
-import org.apache.isis.applib.services.jaxb.JaxbService;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-public class DomainObjectTest {
-
-    private JaxbService jaxbService;
-
-    @Before
-    public void setUp() throws Exception {
-        jaxbService = new JaxbService.Simple();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-
-    }
-
-    @Test
-    public void xxx() throws Exception {
-
-        final DomainObject domainObject = new DomainObject();
-
-        TabGroup tabGroup = domainObject.getTabGroups().get(0);
-        Tab tab = tabGroup.getTabs().get(0);
-        tab.setName("Common");
-        Column left = tab.getLeft();
-
-        PropertyGroup leftPropGroup = new PropertyGroup();
-        left.setPropertyGroups(Lists.<PropertyGroup>newArrayList());
-        left.getPropertyGroups().add(leftPropGroup);
-        leftPropGroup.setName("General");
-
-        Collection similarToColl = new Collection();
-        left.setCollections(Lists.<Collection>newArrayList());
-        left.getCollections().add(similarToColl);
-        similarToColl.setId("similarTo");
-
-        Property nameProperty = leftPropGroup.getProperties().get(0);
-        nameProperty.setId("name");
-
-        Action updateNameAction = new Action();
-        updateNameAction.setId("updateName");
-        nameProperty.setActions(Lists.<Action>newArrayList());
-        nameProperty.getActions().add(updateNameAction);
-
-        Action deleteAction = new Action();
-        deleteAction.setId("delete");
-        domainObject.setActions(Lists.<Action>newArrayList());
-        domainObject.getActions().add(deleteAction);
-
-        String xml = jaxbService.toXml(domainObject,
-                ImmutableMap.<String,Object>of(
-                        Marshaller.JAXB_SCHEMA_LOCATION,
-                        "http://isis.apache.org/schema/applib/layout http://isis.apache.org/schema/applib/layout/layout-1.0.xsd"
-                ));
-        System.out.println(xml);
-
-        DomainObject domainObjectRoundtripped = jaxbService.fromXml(DomainObject.class, xml);
-        String xmlRoundtripped = jaxbService.toXml(domainObjectRoundtripped,
-                ImmutableMap.<String,Object>of(
-                        Marshaller.JAXB_SCHEMA_LOCATION,
-                        "http://isis.apache.org/schema/applib/layout http://isis.apache.org/schema/applib/layout/layout-1.0.xsd"
-                ));
-        assertThat(xml, is(equalTo(xmlRoundtripped)));
-
-
-        System.out.println("==========");
-
-        dumpXsd(domainObject);
-    }
-
-    protected void dumpXsd(final DomainObject domainObject) {
-        Map<String, String> schemas = jaxbService.toXsd(domainObject, JaxbService.IsisSchemas.INCLUDE);
-        for (Map.Entry<String, String> entry : schemas.entrySet()) {
-            //System.out.println(entry.getKey() + ":");
-            System.out.println(entry.getValue());
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java
new file mode 100644
index 0000000..73df1fb
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.layoutxml.v1_0;
+
+import java.util.Map;
+
+import javax.xml.bind.Marshaller;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.Column;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.PropertyGroup;
+import org.apache.isis.applib.layout.v1_0.Tab;
+import org.apache.isis.applib.layout.v1_0.TabGroup;
+import org.apache.isis.applib.services.jaxb.JaxbService;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public class ObjectLayoutMetadataTest {
+
+    private JaxbService jaxbService;
+
+    @Before
+    public void setUp() throws Exception {
+        jaxbService = new JaxbService.Simple();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+
+    }
+
+    @Test
+    public void xxx() throws Exception {
+
+        final ObjectLayoutMetadata objectLayoutMetadata = new ObjectLayoutMetadata();
+
+        TabGroup tabGroup = objectLayoutMetadata.getTabGroups().get(0);
+        Tab tab = tabGroup.getTabs().get(0);
+        tab.setName("Common");
+        Column left = tab.getLeft();
+
+        PropertyGroup leftPropGroup = new PropertyGroup();
+        left.setPropertyGroups(Lists.<PropertyGroup>newArrayList());
+        left.getPropertyGroups().add(leftPropGroup);
+        leftPropGroup.setName("General");
+
+        CollectionLayoutMetadata similarToColl = new CollectionLayoutMetadata();
+        left.setCollections(Lists.<CollectionLayoutMetadata>newArrayList());
+        left.getCollections().add(similarToColl);
+        similarToColl.setId("similarTo");
+
+        PropertyLayoutMetadata namePropertyLayoutMetadata = leftPropGroup.getProperties().get(0);
+        namePropertyLayoutMetadata.setId("name");
+
+        ActionLayoutMetadata updateNameActionLayoutMetadata = new ActionLayoutMetadata();
+        updateNameActionLayoutMetadata.setId("updateName");
+        namePropertyLayoutMetadata.setActions(Lists.<ActionLayoutMetadata>newArrayList());
+        namePropertyLayoutMetadata.getActions().add(updateNameActionLayoutMetadata);
+
+        ActionLayoutMetadata deleteActionLayoutMetadata = new ActionLayoutMetadata();
+        deleteActionLayoutMetadata.setId("delete");
+        objectLayoutMetadata.setActions(Lists.<ActionLayoutMetadata>newArrayList());
+        objectLayoutMetadata.getActions().add(deleteActionLayoutMetadata);
+
+        String xml = jaxbService.toXml(objectLayoutMetadata,
+                ImmutableMap.<String,Object>of(
+                        Marshaller.JAXB_SCHEMA_LOCATION,
+                        "http://isis.apache.org/schema/applib/layout http://isis.apache.org/schema/applib/layout/layout-1.0.xsd"
+                ));
+        System.out.println(xml);
+
+        ObjectLayoutMetadata objectLayoutMetadataRoundtripped = jaxbService.fromXml(ObjectLayoutMetadata.class, xml);
+        String xmlRoundtripped = jaxbService.toXml(objectLayoutMetadataRoundtripped,
+                ImmutableMap.<String,Object>of(
+                        Marshaller.JAXB_SCHEMA_LOCATION,
+                        "http://isis.apache.org/schema/applib/layout http://isis.apache.org/schema/applib/layout/layout-1.0.xsd"
+                ));
+        assertThat(xml, is(equalTo(xmlRoundtripped)));
+
+
+        System.out.println("==========");
+
+        dumpXsd(objectLayoutMetadata);
+    }
+
+    protected void dumpXsd(final ObjectLayoutMetadata objectLayoutMetadata) {
+        Map<String, String> schemas = jaxbService.toXsd(objectLayoutMetadata, JaxbService.IsisSchemas.INCLUDE);
+        for (Map.Entry<String, String> entry : schemas.entrySet()) {
+            //System.out.println(entry.getKey() + ":");
+            System.out.println(entry.getValue());
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionDefaultTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionDefaultTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionDefaultTest.java
deleted file mode 100644
index 7e446c1..0000000
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionDefaultTest.java
+++ /dev/null
@@ -1,107 +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.core.runtime.system;
-
-import org.jmock.Expectations;
-import org.jmock.auto.Mock;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
-import org.apache.isis.core.metamodel.runtimecontext.PersistenceSessionService;
-import org.apache.isis.core.metamodel.runtimecontext.MessageBrokerService;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.facets.FacetedMethod;
-import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
-import org.apache.isis.core.metamodel.facets.all.named.NamedFacetAbstract;
-import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
-import org.apache.isis.core.metamodel.spec.SpecificationLoader;
-import org.apache.isis.core.metamodel.spec.feature.ObjectMemberDependencies;
-import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionDefault;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-public class ObjectActionDefaultTest {
-
-    @Rule
-    public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
-    
-    
-    private ObjectActionDefault action;
-    
-    @Mock
-    private FacetedMethod mockFacetedMethod;
-
-    @Mock
-    private AuthenticationSessionProvider mockAuthenticationSessionProvider;
-    @Mock
-    private SpecificationLoader mockSpecificationLookup;
-    @Mock
-    private AdapterManager mockAdapterManager;
-    @Mock
-    private ServicesInjector mockServicesInjector;
-    @Mock
-    private MessageBrokerService mockMessageBrokerService;
-    @Mock
-    private PersistenceSessionService mockPersistenceSessionService;
-
-    @Before
-    public void setUp() throws Exception {
-
-        context.checking(new Expectations() {
-            {
-                one(mockFacetedMethod).getIdentifier();
-                will(returnValue(Identifier.actionIdentifier("Customer", "reduceheadcount")));
-            }
-        });
-
-        action = new ObjectActionDefault(mockFacetedMethod, new ObjectMemberDependencies(
-                mockSpecificationLookup, mockServicesInjector,
-                mockPersistenceSessionService));
-    }
-
-
-    @Test
-    public void testNameDefaultsToActionsMethodName() {
-        final String name = "Reduceheadcount";
-        final NamedFacet facet = new NamedFacetAbstract(name, true, mockFacetedMethod) {
-        };
-        context.checking(new Expectations() {
-            {
-                one(mockFacetedMethod).getFacet(NamedFacet.class);
-                will(returnValue(facet));
-            }
-        });
-        assertThat(action.getName(), is(equalTo(name)));
-    }
-
-    @Test
-    public void testId() {
-        assertEquals("reduceheadcount", action.getId());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionLayoutXmlDefaultTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionLayoutXmlDefaultTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionLayoutXmlDefaultTest.java
new file mode 100644
index 0000000..3bdb185
--- /dev/null
+++ b/core/runtime/src/test/java/org/apache/isis/core/runtime/system/ObjectActionLayoutXmlDefaultTest.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.runtime.system;
+
+import org.jmock.Expectations;
+import org.jmock.auto.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.metamodel.runtimecontext.PersistenceSessionService;
+import org.apache.isis.core.metamodel.runtimecontext.MessageBrokerService;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
+import org.apache.isis.core.metamodel.facets.all.named.NamedFacetAbstract;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMemberDependencies;
+import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionDefault;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class ObjectActionLayoutXmlDefaultTest {
+
+    @Rule
+    public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+    
+    
+    private ObjectActionDefault action;
+    
+    @Mock
+    private FacetedMethod mockFacetedMethod;
+
+    @Mock
+    private AuthenticationSessionProvider mockAuthenticationSessionProvider;
+    @Mock
+    private SpecificationLoader mockSpecificationLookup;
+    @Mock
+    private AdapterManager mockAdapterManager;
+    @Mock
+    private ServicesInjector mockServicesInjector;
+    @Mock
+    private MessageBrokerService mockMessageBrokerService;
+    @Mock
+    private PersistenceSessionService mockPersistenceSessionService;
+
+    @Before
+    public void setUp() throws Exception {
+
+        context.checking(new Expectations() {
+            {
+                one(mockFacetedMethod).getIdentifier();
+                will(returnValue(Identifier.actionIdentifier("Customer", "reduceheadcount")));
+            }
+        });
+
+        action = new ObjectActionDefault(mockFacetedMethod, new ObjectMemberDependencies(
+                mockSpecificationLookup, mockServicesInjector,
+                mockPersistenceSessionService));
+    }
+
+
+    @Test
+    public void testNameDefaultsToActionsMethodName() {
+        final String name = "Reduceheadcount";
+        final NamedFacet facet = new NamedFacetAbstract(name, true, mockFacetedMethod) {
+        };
+        context.checking(new Expectations() {
+            {
+                one(mockFacetedMethod).getFacet(NamedFacet.class);
+                will(returnValue(facet));
+            }
+        });
+        assertThat(action.getName(), is(equalTo(name)));
+    }
+
+    @Test
+    public void testId() {
+        assertEquals("reduceheadcount", action.getId());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
index 5d3c735..44f1eb0 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
@@ -206,7 +206,7 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
         try {
             Constructor<? extends Page> constructor = signInPageClass.getConstructor(PageParameters.class, ExceptionModel.class);
             signInPage = constructor.newInstance(parameters, exceptionModel);
-        } catch (Exception _) {
+        } catch (Exception ex) {
             try {
                 IPageFactory pageFactory = Application.get().getPageFactory();
                 signInPage = pageFactory.newPage(signInPageClass, parameters);

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/viewer-wicket-model/src/test/java/org/apache/isis/viewer/wicket/model/models/ActionModelTest.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-model/src/test/java/org/apache/isis/viewer/wicket/model/models/ActionModelTest.java b/core/viewer-wicket-model/src/test/java/org/apache/isis/viewer/wicket/model/models/ActionModelTest.java
index f7b5baa..d9741f1 100644
--- a/core/viewer-wicket-model/src/test/java/org/apache/isis/viewer/wicket/model/models/ActionModelTest.java
+++ b/core/viewer-wicket-model/src/test/java/org/apache/isis/viewer/wicket/model/models/ActionModelTest.java
@@ -19,15 +19,15 @@
 
 package org.apache.isis.viewer.wicket.model.models;
 
+import java.util.Map;
+
+import org.junit.Test;
+
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 import static org.junit.Assert.assertThat;
 
-import java.util.Map;
-
-import org.junit.Test;
-
 public class ActionModelTest {
 
     @Test

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
index 14c1473..1602ff0 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
@@ -22,7 +22,7 @@ package org.apache.isis.viewer.wicket.ui.components.entity.combined;
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.core.metamodel.facets.object.layoutxml.LayoutXmlFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutxml.ObjectLayoutMetadataFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
@@ -46,7 +46,7 @@ public class EntityCombinedPanelFactory extends EntityComponentFactoryAbstract {
     protected ApplicationAdvice doAppliesTo(final EntityModel entityModel) {
         final ObjectSpecification specification = entityModel.getTypeOfSpecification();
         // opposite to the EntityTabbedPanelFactory
-        return appliesIf(!specification.containsDoOpFacet(LayoutXmlFacet.class));
+        return appliesIf(!specification.containsDoOpFacet(ObjectLayoutMetadataFacet.class));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
index 5901d08..225dcdd 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
@@ -21,10 +21,7 @@ package org.apache.isis.viewer.wicket.ui.components.entity.properties;
 import java.util.List;
 import java.util.Map;
 
-import javax.annotation.Nullable;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Lists;
 
 import org.apache.wicket.Component;
@@ -159,10 +156,12 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
 
         final ColumnSpans columnSpans;
         if(tabMetaDataIfAny != null) {
+            final Column middle = tabMetaDataIfAny.getMiddle();
+            final Column right = tabMetaDataIfAny.getRight();
             columnSpans = ColumnSpans.asSpans(
                     tabMetaDataIfAny.getLeft().getSpan(),
-                    tabMetaDataIfAny.getMiddle().getSpan(),
-                    tabMetaDataIfAny.getRight().getSpan());
+                    middle != null? middle.getSpan(): 0,
+                    right != null? right.getSpan(): 0);
         } else {
             final MemberGroupLayoutFacet memberGroupLayoutFacet =
                     entityModel.getObject().getSpecification().getFacet(MemberGroupLayoutFacet.class);
@@ -177,7 +176,7 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
         
         boolean addedProperties;
         if(columnSpans.getLeft() > 0) {
-            addedProperties = addMembersInColumn(leftColumn, MemberGroupLayoutHint.LEFT, tabMetaDataIfAny, columnSpans);
+            addedProperties = addPropertiesInColumn(leftColumn, MemberGroupLayoutHint.LEFT, tabMetaDataIfAny, columnSpans);
             addButtons(leftColumn);
             addFeedbackGui(leftColumn);
         } else {
@@ -195,7 +194,7 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
         if(columnSpans.getMiddle() > 0) {
             MarkupContainer middleColumn = new WebMarkupContainer(ID_MIDDLE_COLUMN);
             add(middleColumn);
-            addMembersInColumn(middleColumn, MemberGroupLayoutHint.MIDDLE, tabMetaDataIfAny, columnSpans);
+            addPropertiesInColumn(middleColumn, MemberGroupLayoutHint.MIDDLE, tabMetaDataIfAny, columnSpans);
         } else {
             Components.permanentlyHide(this, ID_MIDDLE_COLUMN);
         }
@@ -204,7 +203,7 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
         if(columnSpans.getRight() > 0) {
             MarkupContainer rightColumn = new WebMarkupContainer(ID_RIGHT_COLUMN);
             add(rightColumn);
-            addMembersInColumn(rightColumn, MemberGroupLayoutHint.RIGHT, tabMetaDataIfAny, columnSpans);
+            addPropertiesInColumn(rightColumn, MemberGroupLayoutHint.RIGHT, tabMetaDataIfAny, columnSpans);
         } else {
             Components.permanentlyHide(this, ID_RIGHT_COLUMN);
         }
@@ -234,7 +233,7 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
         }
     }
 
-    private boolean addMembersInColumn(
+    private boolean addPropertiesInColumn(
             final MarkupContainer markupContainer,
             final MemberGroupLayoutHint hint,
             final Tab tabMetaDataIfAny,
@@ -247,17 +246,18 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
 
         final Column columnMetaDataIfAny = tabMetaDataIfAny != null ? hint.from(tabMetaDataIfAny) : null;
 
-        // if in a tab, then collections are also rendered.
         final List<ObjectAssociation> properties = visibleAssociations(adapter, ObjectAssociation.Filters.PROPERTIES);
 
         final RepeatingView memberGroupRv = new RepeatingView(ID_MEMBER_GROUP);
         markupContainer.add(memberGroupRv);
 
-        final Map<String, List<ObjectAssociation>> associationsByGroup =
-                ObjectAssociation.Util.groupByMemberOrderName(properties);
+        final Map<String, List<ObjectAssociation>> associationsByGroup = ObjectAssociation.Util.groupByMemberOrderName(properties);
 
         final List<String> groupNames = tabMetaDataIfAny != null
-                ? Lists.newArrayList(Iterables.transform(columnMetaDataIfAny.getPropertyGroups(), propertyGroupName()))
+                ? FluentIterable
+                    .from(columnMetaDataIfAny.getPropertyGroups())
+                    .transform(PropertyGroup.Util.nameOf())
+                    .toList()
                 : ObjectSpecifications.orderByMemberGroups(objSpec, associationsByGroup.keySet(), hint);
 
         for(final String groupName: groupNames) {
@@ -308,15 +308,6 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
         return !groupNames.isEmpty();
     }
 
-    private static Function<? super PropertyGroup, String> propertyGroupName() {
-        return new Function<PropertyGroup, String>() {
-            @Nullable @Override
-            public String apply(@Nullable final PropertyGroup propertyGroup) {
-                return propertyGroup.getName();
-            }
-        };
-    }
-
     private void addPropertyToForm(
             final EntityModel entityModel,
             final OneToOneAssociation otoa,

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
index e8438e1..cce3292 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
@@ -21,6 +21,7 @@ package org.apache.isis.viewer.wicket.ui.components.entity.tabgroups;
 
 import java.util.List;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Lists;
 
 import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
@@ -30,13 +31,13 @@ import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.Model;
 
-import org.apache.isis.applib.layout.v1_0.DomainObject;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
 import org.apache.isis.applib.layout.v1_0.Tab;
 import org.apache.isis.applib.layout.v1_0.TabGroup;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
-import org.apache.isis.core.metamodel.facets.object.layoutxml.LayoutXmlFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutxml.ObjectLayoutMetadataFacet;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
@@ -71,16 +72,19 @@ public class EntityTabGroupsPanel extends PanelAbstract<EntityModel> {
         }
 
         // forces metadata to be derived && synced
-        final LayoutXmlFacet layoutXmlFacet = model.getTypeOfSpecification().getFacet(LayoutXmlFacet.class);
-        final DomainObject domainObject = layoutXmlFacet.getLayoutMetadata();
+        final ObjectLayoutMetadataFacet objectLayoutMetadataFacet = model.getTypeOfSpecification().getFacet(ObjectLayoutMetadataFacet.class);
+        final ObjectLayoutMetadata objectLayoutMetadata = objectLayoutMetadataFacet.getMetadata();
 
         // TODO: debugging, remove
-        final String xml = getServicesInjector().lookupService(JaxbService.class).toXml(domainObject);
+        final String xml = getServicesInjector().lookupService(JaxbService.class).toXml(objectLayoutMetadata);
         System.out.println(xml);
 
         addOrReplace(ComponentType.ENTITY_SUMMARY, model);
 
-        final List<TabGroup> tabGroups = domainObject.getTabGroups();
+        final List<TabGroup> tabGroups = FluentIterable
+                .from(objectLayoutMetadata.getTabGroups())
+                .filter(TabGroup.Predicates.notEmpty())
+                .toList();
         final ListView<TabGroup> tabGroupsList =
                 new ListView<TabGroup>(ID_TAB_GROUPS, tabGroups) {
 
@@ -89,10 +93,12 @@ public class EntityTabGroupsPanel extends PanelAbstract<EntityModel> {
 
                 final List<ITab> tabs = Lists.newArrayList();
                 final TabGroup tabGroup = item.getModelObject();
-                final List<Tab> tabList = tabGroup.getTabs();
+                final List<Tab> tabList = FluentIterable
+                        .from(tabGroup.getTabs())
+                        .filter(Tab.Predicates.notEmpty())
+                        .toList();
 
                 for (final Tab tab : tabList) {
-
                     tabs.add(new AbstractTab(Model.of(tab.getName())) {
                         private static final long serialVersionUID = 1L;
 
@@ -115,10 +121,9 @@ public class EntityTabGroupsPanel extends PanelAbstract<EntityModel> {
             super(id);
 
             final EntityModel modelWithTabHints = new EntityModel(model.getPageParameters());
-            model.setTabMetadata(tab);
+            modelWithTabHints.setTabMetadata(tab);
 
             getComponentFactoryRegistry().addOrReplaceComponent(this, ID_ENTITY_PROPERTIES_AND_COLLECTIONS, ComponentType.ENTITY_PROPERTIES, modelWithTabHints);
-
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
index 825ea59..05e3b68 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
@@ -22,7 +22,7 @@ package org.apache.isis.viewer.wicket.ui.components.entity.tabgroups;
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.core.metamodel.facets.object.layoutxml.LayoutXmlFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutxml.ObjectLayoutMetadataFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
@@ -45,7 +45,7 @@ public class EntityTabGroupsPanelFactory extends EntityComponentFactoryAbstract
     @Override
     protected ApplicationAdvice doAppliesTo(final EntityModel entityModel) {
         final ObjectSpecification specification = entityModel.getTypeOfSpecification();
-        return appliesIf(specification.containsDoOpFacet(LayoutXmlFacet.class));
+        return appliesIf(specification.containsDoOpFacet(ObjectLayoutMetadataFacet.class));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
index acc3a36..e068168 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
@@ -131,10 +131,19 @@ public class EntityPage extends PageAbstract {
 
 
 
-        // the next bit is a work-around for JRebel integration...
-        // ... even though the IsisJRebelPlugin calls invalidateCache, it seems that there is 
-        // some caching elsewhere in the Wicket viewer meaning that stale metadata is referenced.
-        // doing an additional call here seems to be sufficient, though not exactly sure why... :-(
+        //
+        // invalidate the cache so that can do dynamic reloading of layout metadata etc.
+        //
+        // Note that it's necessary to load the page twice.  (I think) that the first time is to load the new
+        // Java class files into the webapp (but too "late" to be used), the second then works.
+        // Moving this functionality earlier on in the web request pipeline (eg WebRequestCycleForIsis)
+        // made no difference.
+        //
+        // what might help is using some sort of daemon process to monitor when the class files change, and then
+        // reload (a la JRebel).  Don't think DCEVM by itself is enough, but possibly using
+        // https://github.com/fakereplace/fakereplace or https://github.com/spring-projects/spring-loaded
+        // might instead suffice since they provide a java agent similar to JRebel.
+        //
         if(!getDeploymentType().isProduction()) {
             getSpecificationLoader().invalidateCacheFor(objectAdapter.getObject());
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
index d367269..8d69476 100644
--- a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
+++ b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
@@ -1,7 +1,5 @@
-DELIBERATE SYNTAX ERROR TO DISABLE NEW RENDERING
-
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<domainObject xsi:schemaLocation="http://isis.apache.org/schema/applib/layout http://isis.apache.org/schema/applib/layout/layout-1.0.xsd" xmlns="http://isis.apache.org/schema/applib/layout" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<objectLayout xsi:schemaLocation="http://isis.apache.org/schema/applib/layout http://isis.apache.org/schema/applib/layout/layout-1.0.xsd" xmlns="http://isis.apache.org/schema/applib/layout" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <actions>
         <action id="delete"/>
     </actions>
@@ -16,23 +14,27 @@ DELIBERATE SYNTAX ERROR TO DISABLE NEW RENDERING
                     </property>
                 </propertyGroup>
             </left>
-        </tab>
-        <tab name="Other">
-            <left span="4">
+            <middle span="4">
+            </middle>
+            <right span="4">
                 <propertyGroup name="Metadata">
                     <actions>
                         <action id="downloadJdoMetadata"/>
                     </actions>
                     <property id="versionSequence"/>
                 </propertyGroup>
+            </right>
+        </tab>
+        <tab name="Other">
+            <left span="4">
             </left>
         </tab>
     </tabGroup>
     <tabGroup>
         <tab name="Similar To">
             <left span="12">
-                <collection id="similarTo"/>
+                <collection id="similarTox"/>
             </left>
         </tab>
     </tabGroup>
-</domainObject>
\ No newline at end of file
+</objectLayout>
\ No newline at end of file


[3/4] isis git commit: ISIS-993: factored out LayoutMetadataService, renamed the metadata classes

Posted by da...@apache.org.
ISIS-993: factored out LayoutMetadataService, renamed the metadata classes


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

Branch: refs/heads/ISIS-993
Commit: 4da8f960ce4cfe8f386ff2a0de3fa0ae46609eeb
Parents: 0ac8eda
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Jan 8 15:46:30 2016 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Jan 8 15:46:30 2016 +0000

----------------------------------------------------------------------
 .../schema/applib/layout/layout-1.0.xsd         |  27 +-
 .../asciidoc/schema/applib/layout/layout.xsd    |  27 +-
 .../apache/isis/applib/layout/v1_0/Action.java  | 204 --------
 .../isis/applib/layout/v1_0/ActionHolder.java   |   2 +-
 .../layout/v1_0/ActionLayoutMetadata.java       | 223 +++++++++
 .../isis/applib/layout/v1_0/Collection.java     | 212 ---------
 .../layout/v1_0/CollectionLayoutMetadata.java   | 226 +++++++++
 .../apache/isis/applib/layout/v1_0/Column.java  |   6 +-
 .../isis/applib/layout/v1_0/DomainObject.java   | 174 -------
 .../layout/v1_0/ObjectLayoutMetadata.java       | 243 ++++++++++
 .../isis/applib/layout/v1_0/Property.java       | 209 ---------
 .../isis/applib/layout/v1_0/PropertyGroup.java  |  31 +-
 .../layout/v1_0/PropertyLayoutMetadata.java     | 227 +++++++++
 .../org/apache/isis/applib/layout/v1_0/Tab.java |  18 +-
 .../isis/applib/layout/v1_0/TabGroup.java       |  23 +-
 .../layout/ObjectLayoutMetadataService.java     |  34 ++
 .../layout/Object_downloadLayoutXml.java        |  67 +++
 .../isis/applib/services/layout/Util.java       |  33 ++
 .../layout/ActionPositionFacetForActionXml.java |   4 +-
 .../layout/BookmarkPolicyFacetForActionXml.java |   4 +-
 .../layout/CssClassFaFacetForActionXml.java     |   4 +-
 .../layout/CssClassFacetForActionXml.java       |   4 +-
 .../layout/DescribedAsFacetForActionXml.java    |   4 +-
 .../layout/HiddenFacetForActionLayoutXml.java   |   4 +-
 .../actions/layout/NamedFacetForActionXml.java  |   4 +-
 .../layout/CssClassFacetForCollectionXml.java   |   4 +-
 .../DefaultViewFacetForCollectionXml.java       |   4 +-
 .../DescribedAsFacetForCollectionXml.java       |   4 +-
 .../layout/HiddenFacetForCollectionXml.java     |   4 +-
 .../layout/NamedFacetForCollectionXml.java      |   4 +-
 .../layout/PagedFacetForCollectionXml.java      |   4 +-
 .../layout/SortedByFacetForCollectionXml.java   |   4 +-
 .../facets/object/layoutxml/LayoutXmlFacet.java |  32 --
 .../object/layoutxml/LayoutXmlFacetDefault.java | 381 ---------------
 .../object/layoutxml/LayoutXmlFacetFactory.java |  55 +--
 .../layoutxml/ObjectLayoutMetadataFacet.java    |  35 ++
 .../ObjectLayoutMetadataFacetDefault.java       |  65 +++
 .../CssClassFacetForPropertyXml.java            |   4 +-
 .../DescribedAsFacetForPropertyXml.java         |   4 +-
 .../HiddenFacetForPropertyXml.java              |   4 +-
 .../LabelAtFacetForPropertyXml.java             |   4 +-
 .../MultiLineFacetForPropertyXml.java           |   4 +-
 .../NamedFacetForPropertyXml.java               |   4 +-
 .../RenderedAdjustedFacetForPropertyXml.java    |   4 +-
 .../TypicalLengthFacetForPropertyXml.java       |   4 +-
 .../ObjectLayoutMetadataServiceDefault.java     | 468 +++++++++++++++++++
 .../metamodel/MetaModelServiceDefault.java      |   1 -
 .../ActionLayoutAnnotationFacetFactoryTest.java | 192 --------
 ...youtXmlLayoutAnnotationFacetFactoryTest.java | 192 ++++++++
 .../layoutxml/LayoutXmlFacetDefaultTest.java    |  60 ---
 .../ObjectLayoutMetadataFacetDefaultTest.java   |  60 +++
 .../layoutxml/v1_0/DomainObjectTest.java        | 121 -----
 .../v1_0/ObjectLayoutMetadataTest.java          | 121 +++++
 .../runtime/system/ObjectActionDefaultTest.java | 107 -----
 .../ObjectActionLayoutXmlDefaultTest.java       | 107 +++++
 .../wicket/WebRequestCycleForIsis.java          |   2 +-
 .../wicket/model/models/ActionModelTest.java    |   8 +-
 .../combined/EntityCombinedPanelFactory.java    |   4 +-
 .../entity/properties/EntityPropertiesForm.java |  37 +-
 .../entity/tabgroups/EntityTabGroupsPanel.java  |  25 +-
 .../tabgroups/EntityTabGroupsPanelFactory.java  |   4 +-
 .../wicket/ui/pages/entity/EntityPage.java      |  17 +-
 .../dom/simple/SimpleObject.layout.xml          |  18 +-
 63 files changed, 2305 insertions(+), 1881 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout-1.0.xsd
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout-1.0.xsd b/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout-1.0.xsd
index 6aeb3d6..7a3e949 100644
--- a/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout-1.0.xsd
+++ b/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout-1.0.xsd
@@ -1,14 +1,14 @@
 <?xml version="1.0" standalone="yes"?>
 <xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://isis.apache.org/schema/applib/layout" xmlns:tns="http://isis.apache.org/schema/applib/layout" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
-  <xs:element name="domainObject" type="tns:domainObject"/>
+  <xs:element name="objectLayout" type="tns:objectLayout"/>
 
-  <xs:complexType name="domainObject">
+  <xs:complexType name="objectLayout">
     <xs:sequence>
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
@@ -16,10 +16,11 @@
     </xs:sequence>
   </xs:complexType>
 
-  <xs:complexType name="action">
+  <xs:complexType name="actionLayout">
     <xs:sequence>
       <xs:element name="named" type="xs:string" minOccurs="0"/>
       <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="metadataError" type="xs:string" minOccurs="0"/>
     </xs:sequence>
     <xs:attribute name="bookmarking" type="tns:bookmarkPolicy"/>
     <xs:attribute name="cssClass" type="xs:string"/>
@@ -49,7 +50,7 @@
   <xs:complexType name="column">
     <xs:sequence>
       <xs:element name="propertyGroup" type="tns:propertyGroup" minOccurs="0" maxOccurs="unbounded"/>
-      <xs:element name="collection" type="tns:collection" minOccurs="0" maxOccurs="unbounded"/>
+      <xs:element name="collection" type="tns:collectionLayoutXml" minOccurs="0" maxOccurs="unbounded"/>
     </xs:sequence>
     <xs:attribute name="span" type="xs:int" use="required"/>
   </xs:complexType>
@@ -59,26 +60,27 @@
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
-      <xs:element name="property" type="tns:property" maxOccurs="unbounded"/>
+      <xs:element name="property" type="tns:propertyLayout" maxOccurs="unbounded"/>
     </xs:sequence>
     <xs:attribute name="name" type="xs:string" use="required"/>
   </xs:complexType>
 
-  <xs:complexType name="property">
+  <xs:complexType name="propertyLayout">
     <xs:sequence>
       <xs:element name="named" type="xs:string" minOccurs="0"/>
       <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
+      <xs:element name="metadataError" type="xs:string" minOccurs="0"/>
     </xs:sequence>
     <xs:attribute name="cssClass" type="xs:string"/>
     <xs:attribute name="hidden" type="tns:where"/>
@@ -90,7 +92,7 @@
     <xs:attribute name="typicalLength" type="xs:int"/>
   </xs:complexType>
 
-  <xs:complexType name="collection">
+  <xs:complexType name="collectionLayoutXml">
     <xs:sequence>
       <xs:element name="named" type="xs:string" minOccurs="0"/>
       <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
@@ -98,10 +100,11 @@
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
+      <xs:element name="metadataError" type="xs:string" minOccurs="0"/>
     </xs:sequence>
     <xs:attribute name="cssClass" type="xs:string"/>
     <xs:attribute name="defaultView" type="xs:string"/>
@@ -159,4 +162,4 @@
       <xs:enumeration value="NONE"/>
     </xs:restriction>
   </xs:simpleType>
-</xs:schema>
\ No newline at end of file
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout.xsd
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout.xsd b/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout.xsd
index 6aeb3d6..7a3e949 100644
--- a/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout.xsd
+++ b/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout.xsd
@@ -1,14 +1,14 @@
 <?xml version="1.0" standalone="yes"?>
 <xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://isis.apache.org/schema/applib/layout" xmlns:tns="http://isis.apache.org/schema/applib/layout" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
-  <xs:element name="domainObject" type="tns:domainObject"/>
+  <xs:element name="objectLayout" type="tns:objectLayout"/>
 
-  <xs:complexType name="domainObject">
+  <xs:complexType name="objectLayout">
     <xs:sequence>
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
@@ -16,10 +16,11 @@
     </xs:sequence>
   </xs:complexType>
 
-  <xs:complexType name="action">
+  <xs:complexType name="actionLayout">
     <xs:sequence>
       <xs:element name="named" type="xs:string" minOccurs="0"/>
       <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="metadataError" type="xs:string" minOccurs="0"/>
     </xs:sequence>
     <xs:attribute name="bookmarking" type="tns:bookmarkPolicy"/>
     <xs:attribute name="cssClass" type="xs:string"/>
@@ -49,7 +50,7 @@
   <xs:complexType name="column">
     <xs:sequence>
       <xs:element name="propertyGroup" type="tns:propertyGroup" minOccurs="0" maxOccurs="unbounded"/>
-      <xs:element name="collection" type="tns:collection" minOccurs="0" maxOccurs="unbounded"/>
+      <xs:element name="collection" type="tns:collectionLayoutXml" minOccurs="0" maxOccurs="unbounded"/>
     </xs:sequence>
     <xs:attribute name="span" type="xs:int" use="required"/>
   </xs:complexType>
@@ -59,26 +60,27 @@
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
-      <xs:element name="property" type="tns:property" maxOccurs="unbounded"/>
+      <xs:element name="property" type="tns:propertyLayout" maxOccurs="unbounded"/>
     </xs:sequence>
     <xs:attribute name="name" type="xs:string" use="required"/>
   </xs:complexType>
 
-  <xs:complexType name="property">
+  <xs:complexType name="propertyLayout">
     <xs:sequence>
       <xs:element name="named" type="xs:string" minOccurs="0"/>
       <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
+      <xs:element name="metadataError" type="xs:string" minOccurs="0"/>
     </xs:sequence>
     <xs:attribute name="cssClass" type="xs:string"/>
     <xs:attribute name="hidden" type="tns:where"/>
@@ -90,7 +92,7 @@
     <xs:attribute name="typicalLength" type="xs:int"/>
   </xs:complexType>
 
-  <xs:complexType name="collection">
+  <xs:complexType name="collectionLayoutXml">
     <xs:sequence>
       <xs:element name="named" type="xs:string" minOccurs="0"/>
       <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
@@ -98,10 +100,11 @@
       <xs:element name="actions" minOccurs="0">
         <xs:complexType>
           <xs:sequence>
-            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="action" type="tns:actionLayout" minOccurs="0" maxOccurs="unbounded"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
+      <xs:element name="metadataError" type="xs:string" minOccurs="0"/>
     </xs:sequence>
     <xs:attribute name="cssClass" type="xs:string"/>
     <xs:attribute name="defaultView" type="xs:string"/>
@@ -159,4 +162,4 @@
       <xs:enumeration value="NONE"/>
     </xs:restriction>
   </xs:simpleType>
-</xs:schema>
\ No newline at end of file
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Action.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Action.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Action.java
deleted file mode 100644
index 7dd00de..0000000
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Action.java
+++ /dev/null
@@ -1,204 +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.applib.layout.v1_0;
-
-import java.io.Serializable;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.isis.applib.annotation.BookmarkPolicy;
-import org.apache.isis.applib.annotation.Where;
-
-/**
- * Broadly corresponds to {@link org.apache.isis.applib.annotation.ActionLayout}.
- *
- * <p>
- *  Note that {@link org.apache.isis.applib.annotation.ActionLayout#contributed()} is omitted because this only applies
- *  to domain services.
- * </p>
- */
-@XmlType(
-    propOrder = {
-        "named"
-        , "describedAs"
-    }
-)
-public class Action implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    public Action() {
-    }
-    public Action(final String id) {
-        setId(id);
-    }
-
-    private String id;
-    /**
-     * Method name.
-     *
-     * <p>
-     *     Overloaded methods are not supported.
-     * </p>
-     */
-    @XmlAttribute(name="id", required = true)
-    public String getId() {
-        return id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-
-
-    private BookmarkPolicy bookmarking;
-
-    @XmlAttribute(required = false)
-    public BookmarkPolicy getBookmarking() {
-        return bookmarking;
-    }
-
-    public void setBookmarking(BookmarkPolicy bookmarking) {
-        this.bookmarking = bookmarking;
-    }
-
-
-    private String cssClass;
-
-    @XmlAttribute(required = false)
-    public String getCssClass() {
-        return cssClass;
-    }
-
-    public void setCssClass(String cssClass) {
-        this.cssClass = cssClass;
-    }
-
-
-    private String cssClassFa;
-
-    @XmlAttribute(required = false)
-    public String getCssClassFa() {
-        return cssClassFa;
-    }
-
-    public void setCssClassFa(String cssClassFa) {
-        this.cssClassFa = cssClassFa;
-    }
-
-
-
-    private org.apache.isis.applib.annotation.ActionLayout.CssClassFaPosition cssClassFaPosition;
-
-    @XmlAttribute(required = false)
-    public org.apache.isis.applib.annotation.ActionLayout.CssClassFaPosition getCssClassFaPosition() {
-        return cssClassFaPosition;
-    }
-
-    public void setCssClassFaPosition(org.apache.isis.applib.annotation.ActionLayout.CssClassFaPosition cssClassFaPosition) {
-        this.cssClassFaPosition = cssClassFaPosition;
-    }
-
-
-    private String describedAs;
-
-    @XmlElement(required = false)
-    public String getDescribedAs() {
-        return describedAs;
-    }
-
-    public void setDescribedAs(String describedAs) {
-        this.describedAs = describedAs;
-    }
-
-
-
-    private Where hidden;
-
-    @XmlAttribute(required = false)
-    public Where getHidden() {
-        return hidden;
-    }
-
-    public void setHidden(Where hidden) {
-        this.hidden = hidden;
-    }
-
-
-
-    private String named;
-
-    @XmlElement(required = false)
-    public String getNamed() {
-        return named;
-    }
-
-    public void setNamed(String named) {
-        this.named = named;
-    }
-
-
-
-    private Boolean namedEscaped;
-
-    @XmlAttribute(required = false)
-    public Boolean getNamedEscaped() {
-        return namedEscaped;
-    }
-
-    public void setNamedEscaped(Boolean namedEscaped) {
-        this.namedEscaped = namedEscaped;
-    }
-
-
-
-    private org.apache.isis.applib.annotation.ActionLayout.Position position;
-
-    @XmlAttribute(required = false)
-    public org.apache.isis.applib.annotation.ActionLayout.Position getPosition() {
-        return position;
-    }
-
-    public void setPosition(org.apache.isis.applib.annotation.ActionLayout.Position position) {
-        this.position = position;
-    }
-
-
-    private ActionHolder owner;
-    /**
-     * Owner.
-     *
-     * <p>
-     *     Set programmatically by framework after reading in from XML.
-     * </p>
-     */
-    @XmlTransient
-    public ActionHolder getOwner() {
-        return owner;
-    }
-
-    public void setOwner(final ActionHolder owner) {
-        this.owner = owner;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionHolder.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionHolder.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionHolder.java
index bac4ebb..d5a6b37 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionHolder.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionHolder.java
@@ -21,5 +21,5 @@ package org.apache.isis.applib.layout.v1_0;
 import java.util.List;
 
 public interface ActionHolder {
-    List<Action> getActions();
+    List<ActionLayoutMetadata> getActions();
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayoutMetadata.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayoutMetadata.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayoutMetadata.java
new file mode 100644
index 0000000..bf454d1
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayoutMetadata.java
@@ -0,0 +1,223 @@
+/*
+ *  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.applib.layout.v1_0;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.isis.applib.annotation.BookmarkPolicy;
+import org.apache.isis.applib.annotation.Where;
+
+/**
+ * Broadly corresponds to {@link org.apache.isis.applib.annotation.ActionLayout}.
+ *
+ * <p>
+ *  Note that {@link org.apache.isis.applib.annotation.ActionLayout#contributed()} is omitted because this only applies
+ *  to domain services.
+ * </p>
+ */
+@XmlType(
+    name = "actionLayout"
+    , propOrder = {
+        "named"
+        , "describedAs"
+        , "metadataError"
+    }
+)
+public class ActionLayoutMetadata implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    public ActionLayoutMetadata() {
+    }
+    public ActionLayoutMetadata(final String id) {
+        setId(id);
+    }
+
+    private String id;
+    /**
+     * Method name.
+     *
+     * <p>
+     *     Overloaded methods are not supported.
+     * </p>
+     */
+    @XmlAttribute(name="id", required = true)
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+
+
+    private BookmarkPolicy bookmarking;
+
+    @XmlAttribute(required = false)
+    public BookmarkPolicy getBookmarking() {
+        return bookmarking;
+    }
+
+    public void setBookmarking(BookmarkPolicy bookmarking) {
+        this.bookmarking = bookmarking;
+    }
+
+
+    private String cssClass;
+
+    @XmlAttribute(required = false)
+    public String getCssClass() {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass) {
+        this.cssClass = cssClass;
+    }
+
+
+    private String cssClassFa;
+
+    @XmlAttribute(required = false)
+    public String getCssClassFa() {
+        return cssClassFa;
+    }
+
+    public void setCssClassFa(String cssClassFa) {
+        this.cssClassFa = cssClassFa;
+    }
+
+
+
+    private org.apache.isis.applib.annotation.ActionLayout.CssClassFaPosition cssClassFaPosition;
+
+    @XmlAttribute(required = false)
+    public org.apache.isis.applib.annotation.ActionLayout.CssClassFaPosition getCssClassFaPosition() {
+        return cssClassFaPosition;
+    }
+
+    public void setCssClassFaPosition(org.apache.isis.applib.annotation.ActionLayout.CssClassFaPosition cssClassFaPosition) {
+        this.cssClassFaPosition = cssClassFaPosition;
+    }
+
+
+    private String describedAs;
+
+    @XmlElement(required = false)
+    public String getDescribedAs() {
+        return describedAs;
+    }
+
+    public void setDescribedAs(String describedAs) {
+        this.describedAs = describedAs;
+    }
+
+
+
+    private Where hidden;
+
+    @XmlAttribute(required = false)
+    public Where getHidden() {
+        return hidden;
+    }
+
+    public void setHidden(Where hidden) {
+        this.hidden = hidden;
+    }
+
+
+
+    private String named;
+
+    @XmlElement(required = false)
+    public String getNamed() {
+        return named;
+    }
+
+    public void setNamed(String named) {
+        this.named = named;
+    }
+
+
+
+    private Boolean namedEscaped;
+
+    @XmlAttribute(required = false)
+    public Boolean getNamedEscaped() {
+        return namedEscaped;
+    }
+
+    public void setNamedEscaped(Boolean namedEscaped) {
+        this.namedEscaped = namedEscaped;
+    }
+
+
+
+    private org.apache.isis.applib.annotation.ActionLayout.Position position;
+
+    @XmlAttribute(required = false)
+    public org.apache.isis.applib.annotation.ActionLayout.Position getPosition() {
+        return position;
+    }
+
+    public void setPosition(org.apache.isis.applib.annotation.ActionLayout.Position position) {
+        this.position = position;
+    }
+
+
+
+
+    private ActionHolder owner;
+    /**
+     * Owner.
+     *
+     * <p>
+     *     Set programmatically by framework after reading in from XML.
+     * </p>
+     */
+    @XmlTransient
+    public ActionHolder getOwner() {
+        return owner;
+    }
+
+    public void setOwner(final ActionHolder owner) {
+        this.owner = owner;
+    }
+
+
+    private String metadataError;
+
+    /**
+     * For diagnostics; populated by the framework if and only if a metadata error.
+     */
+    @XmlElement(required = false)
+    public String getMetadataError() {
+        return metadataError;
+    }
+
+    public void setMetadataError(final String metadataError) {
+        this.metadataError = metadataError;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Collection.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Collection.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Collection.java
deleted file mode 100644
index 371db40..0000000
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Collection.java
+++ /dev/null
@@ -1,212 +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.applib.layout.v1_0;
-
-import java.io.Serializable;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.isis.applib.annotation.Where;
-
-/**
- * Broadly corresponds to the {@link org.apache.isis.applib.annotation.CollectionLayout} annotation.
- *
- * <p>
- *     Note that {@link org.apache.isis.applib.annotation.CollectionLayout#render()} is omitted because
- *     {@link #defaultView} is its replacement.
- * </p>
- */
-@XmlType(
-        propOrder = {
-                "named"
-                ,"describedAs"
-                ,"sortedBy"
-                , "actions"
-        }
-)
-public class Collection implements ColumnContent, ActionHolder, Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    public Collection() {
-    }
-    public Collection(final String id) {
-        setId(id);
-    }
-
-
-    private String id;
-
-    /**
-     * Collection identifier, being the getter method without "get" prefix, first letter lower cased.
-     */
-    @XmlAttribute(required = true)
-    public String getId() {
-        return id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-
-
-    private String cssClass;
-
-    @XmlAttribute(required = false)
-    public String getCssClass() {
-        return cssClass;
-    }
-
-    public void setCssClass(String cssClass) {
-        this.cssClass = cssClass;
-    }
-
-
-
-    private String describedAs;
-
-    @XmlElement(required = false)
-    public String getDescribedAs() {
-        return describedAs;
-    }
-
-    public void setDescribedAs(String describedAs) {
-        this.describedAs = describedAs;
-    }
-
-
-
-    private String defaultView;
-
-    /**
-     * Typically <code>table</code> or <code>hidden</code>, but could be any other named view that is configured and
-     * appropriate, eg <code>gmap3</code> or <code>fullcalendar2</code>.
-     */
-    @XmlAttribute(required = false)
-    public String getDefaultView() {
-        return defaultView;
-    }
-
-    public void setDefaultView(String defaultView) {
-        this.defaultView = defaultView;
-    }
-
-
-    private Where hidden;
-
-    @XmlAttribute(required = false)
-    public Where getHidden() {
-        return hidden;
-    }
-
-    public void setHidden(Where hidden) {
-        this.hidden = hidden;
-    }
-
-
-    private String named;
-
-    @XmlElement(required = false)
-    public String getNamed() {
-        return named;
-    }
-
-    public void setNamed(String named) {
-        this.named = named;
-    }
-
-
-    private Boolean namedEscaped;
-
-    @XmlAttribute(required = false)
-    public Boolean getNamedEscaped() {
-        return namedEscaped;
-    }
-
-    public void setNamedEscaped(Boolean namedEscaped) {
-        this.namedEscaped = namedEscaped;
-    }
-
-
-    private Integer paged;
-
-    @XmlAttribute(required = false)
-    public Integer getPaged() {
-        return paged;
-    }
-
-    public void setPaged(Integer paged) {
-        this.paged = paged;
-    }
-
-
-
-    private String sortedBy;
-
-    @XmlElement(required = false)
-    public String getSortedBy() {
-        return sortedBy;
-    }
-
-    public void setSortedBy(String sortedBy) {
-        this.sortedBy = sortedBy;
-    }
-
-
-
-    private List<Action> actions;
-
-    @XmlElementWrapper(name = "actions", required = false)
-    @XmlElement(name = "action", required = false)
-    public List<Action> getActions() {
-        return actions;
-    }
-
-    public void setActions(List<Action> actions) {
-        this.actions = actions;
-    }
-
-
-
-    private Column owner;
-    /**
-     * Owner.
-     *
-     * <p>
-     *     Set programmatically by framework after reading in from XML.
-     * </p>
-     */
-    @XmlTransient
-    public Column getOwner() {
-        return owner;
-    }
-
-    public void setOwner(final Column owner) {
-        this.owner = owner;
-    }
-
-
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayoutMetadata.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayoutMetadata.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayoutMetadata.java
new file mode 100644
index 0000000..4dc14cd
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayoutMetadata.java
@@ -0,0 +1,226 @@
+/*
+ *  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.applib.layout.v1_0;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.isis.applib.annotation.Where;
+
+/**
+ * Broadly corresponds to the {@link org.apache.isis.applib.annotation.CollectionLayout} annotation.
+ *
+ * <p>
+ *     Note that {@link org.apache.isis.applib.annotation.CollectionLayout#render()} is omitted because
+ *     {@link #defaultView} is its replacement.
+ * </p>
+ */
+@XmlType(
+        propOrder = {
+                "named"
+                ,"describedAs"
+                ,"sortedBy"
+                , "actions"
+                , "metadataError"
+        }
+)
+public class CollectionLayoutMetadata implements ColumnContent, ActionHolder, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    public CollectionLayoutMetadata() {
+    }
+    public CollectionLayoutMetadata(final String id) {
+        setId(id);
+    }
+
+
+    private String id;
+
+    /**
+     * Collection identifier, being the getter method without "get" prefix, first letter lower cased.
+     */
+    @XmlAttribute(required = true)
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+
+
+    private String cssClass;
+
+    @XmlAttribute(required = false)
+    public String getCssClass() {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass) {
+        this.cssClass = cssClass;
+    }
+
+
+
+    private String describedAs;
+
+    @XmlElement(required = false)
+    public String getDescribedAs() {
+        return describedAs;
+    }
+
+    public void setDescribedAs(String describedAs) {
+        this.describedAs = describedAs;
+    }
+
+
+
+    private String defaultView;
+
+    /**
+     * Typically <code>table</code> or <code>hidden</code>, but could be any other named view that is configured and
+     * appropriate, eg <code>gmap3</code> or <code>fullcalendar2</code>.
+     */
+    @XmlAttribute(required = false)
+    public String getDefaultView() {
+        return defaultView;
+    }
+
+    public void setDefaultView(String defaultView) {
+        this.defaultView = defaultView;
+    }
+
+
+    private Where hidden;
+
+    @XmlAttribute(required = false)
+    public Where getHidden() {
+        return hidden;
+    }
+
+    public void setHidden(Where hidden) {
+        this.hidden = hidden;
+    }
+
+
+    private String named;
+
+    @XmlElement(required = false)
+    public String getNamed() {
+        return named;
+    }
+
+    public void setNamed(String named) {
+        this.named = named;
+    }
+
+
+    private Boolean namedEscaped;
+
+    @XmlAttribute(required = false)
+    public Boolean getNamedEscaped() {
+        return namedEscaped;
+    }
+
+    public void setNamedEscaped(Boolean namedEscaped) {
+        this.namedEscaped = namedEscaped;
+    }
+
+
+    private Integer paged;
+
+    @XmlAttribute(required = false)
+    public Integer getPaged() {
+        return paged;
+    }
+
+    public void setPaged(Integer paged) {
+        this.paged = paged;
+    }
+
+
+
+    private String sortedBy;
+
+    @XmlElement(required = false)
+    public String getSortedBy() {
+        return sortedBy;
+    }
+
+    public void setSortedBy(String sortedBy) {
+        this.sortedBy = sortedBy;
+    }
+
+
+
+    private List<ActionLayoutMetadata> actions;
+
+    @XmlElementWrapper(name = "actions", required = false)
+    @XmlElement(name = "action", required = false)
+    public List<ActionLayoutMetadata> getActions() {
+        return actions;
+    }
+
+    public void setActions(List<ActionLayoutMetadata> actionLayoutMetadatas) {
+        this.actions = actionLayoutMetadatas;
+    }
+
+
+
+    private Column owner;
+    /**
+     * Owner.
+     *
+     * <p>
+     *     Set programmatically by framework after reading in from XML.
+     * </p>
+     */
+    @XmlTransient
+    public Column getOwner() {
+        return owner;
+    }
+
+    public void setOwner(final Column owner) {
+        this.owner = owner;
+    }
+
+
+    private String metadataError;
+
+    /**
+     * For diagnostics; populated by the framework if and only if a metadata error.
+     */
+    @XmlElement(required = false)
+    public String getMetadataError() {
+        return metadataError;
+    }
+
+    public void setMetadataError(final String metadataError) {
+        this.metadataError = metadataError;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Column.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Column.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Column.java
index 905438f..1f5ca23 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Column.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Column.java
@@ -71,15 +71,15 @@ public class Column implements Serializable {
     }
 
 
-    private List<Collection> collections = Lists.newArrayList();
+    private List<CollectionLayoutMetadata> collections = Lists.newArrayList();
 
     // no wrapper
     @XmlElement(name = "collection", required = false)
-    public List<Collection> getCollections() {
+    public List<CollectionLayoutMetadata> getCollections() {
         return collections;
     }
 
-    public void setCollections(final List<Collection> collections) {
+    public void setCollections(final List<CollectionLayoutMetadata> collections) {
         this.collections = collections;
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/DomainObject.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/DomainObject.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/DomainObject.java
deleted file mode 100644
index 99388eb..0000000
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/DomainObject.java
+++ /dev/null
@@ -1,174 +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.applib.layout.v1_0;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.isis.applib.services.dto.Dto;
-
-@XmlRootElement
-@XmlType(
-        propOrder = {
-                "actions"
-                , "tabGroups"
-        }
-)
-public class DomainObject implements Dto, ActionHolder, Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    private List<Action> actions;
-
-    @XmlElementWrapper(name = "actions", required = false)
-    @XmlElement(name = "action", required = false)
-    public List<Action> getActions() {
-        return actions;
-    }
-
-    public void setActions(List<Action> actions) {
-        this.actions = actions;
-    }
-
-
-    // must have at least one tab group
-    private List<TabGroup> tabGroups = new ArrayList<TabGroup>() {{
-        add(new TabGroup());
-    }};
-
-    // no wrapper
-
-    /**
-     * Must have at least one tab group; no wrapper.
-     */
-    @XmlElement(name = "tabGroup", required = true)
-    public List<TabGroup> getTabGroups() {
-        return tabGroups;
-    }
-
-    public void setTabGroups(List<TabGroup> tabGroups) {
-        this.tabGroups = tabGroups;
-    }
-
-
-    public interface Visitor {
-        void visit(final DomainObject domainObject);
-        void visit(final TabGroup tabGroup);
-        void visit(final Tab tab);
-        void visit(final Column column);
-        void visit(final PropertyGroup propertyGroup);
-        void visit(final Property property);
-        void visit(final Collection collection);
-        void visit(final Action action);
-    }
-
-    public static class VisitorAdapter implements Visitor {
-        @Override
-        public void visit(final DomainObject domainObject) { }
-        @Override
-        public void visit(final TabGroup tabGroup) { }
-        @Override
-        public void visit(final Tab tab) { }
-        @Override
-        public void visit(final Column column) { }
-        @Override
-        public void visit(final PropertyGroup propertyGroup) {}
-        @Override
-        public void visit(final Property property) {}
-        @Override
-        public void visit(final Collection collection) {}
-        @Override
-        public void visit(final Action action) { }
-    }
-
-    /**
-     * Initializes all "owner" references across the graph, eg {@link TabGroup#setOwner(DomainObject)} and {@link Tab#setOwner(TabGroup)} .
-     */
-    public void init() {
-        visit(new VisitorAdapter());
-    }
-
-    public void visit(final Visitor visitor) {
-        visitor.visit(this);
-        traverseActions(this, visitor);
-        final List<TabGroup> tabGroups = getTabGroups();
-        for (final TabGroup tabGroup : tabGroups) {
-            tabGroup.setOwner(this);
-            visitor.visit(tabGroup);
-            final List<Tab> tabs = tabGroup.getTabs();
-            for (final Tab tab : tabs) {
-                tab.setOwner(tabGroup);
-                visitor.visit(tab);
-                traverseColumn(tab.getLeft(), tab, visitor);
-                traverseColumn(tab.getMiddle(), tab, visitor);
-                traverseColumn(tab.getRight(), tab, visitor);
-            }
-        }
-    }
-
-    private void traverseColumn(final Column column, final Tab tab, final Visitor visitor) {
-        if(column == null) {
-            return;
-        }
-        column.setOwner(tab);
-        visitor.visit(column);
-        traversePropertyGroups(column, visitor);
-        traverseCollections(column, visitor);
-    }
-
-    private void traversePropertyGroups(final Column column, final Visitor visitor) {
-        for (final PropertyGroup propertyGroup : column.getPropertyGroups()) {
-            propertyGroup.setOwner(column);
-            visitor.visit(propertyGroup);
-            traverseActions(propertyGroup, visitor);
-            final List<Property> properties = propertyGroup.getProperties();
-            for (final Property property : properties) {
-                property.setOwner(propertyGroup);
-                visitor.visit(property);
-                traverseActions(property, visitor);
-            }
-        }
-    }
-
-    private void traverseCollections(final Column column, final Visitor visitor) {
-        for (final Collection collection : column.getCollections()) {
-            collection.setOwner(column);
-            visitor.visit(collection);
-            traverseActions(collection, visitor);
-        }
-    }
-
-    private void traverseActions(final ActionHolder actionHolder, final Visitor visitor) {
-        final List<Action> actions = actionHolder.getActions();
-        if(actions == null) {
-            return;
-        }
-        for (final Action action : actions) {
-            action.setOwner(actionHolder);
-            visitor.visit(action);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java
new file mode 100644
index 0000000..2f056a8
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java
@@ -0,0 +1,243 @@
+/*
+ *  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.applib.layout.v1_0;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import com.google.common.collect.Maps;
+
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.services.dto.Dto;
+import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
+
+@XmlRootElement(
+        name = "objectLayout"
+)
+@XmlType(
+        name = "objectLayout"
+        , propOrder = {
+                "actions"
+                , "tabGroups"
+        }
+)
+public class ObjectLayoutMetadata implements Dto, ActionHolder, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<ActionLayoutMetadata> actions;
+
+    @XmlElementWrapper(name = "actions", required = false)
+    @XmlElement(name = "action", required = false)
+    public List<ActionLayoutMetadata> getActions() {
+        return actions;
+    }
+
+    public void setActions(List<ActionLayoutMetadata> actionLayoutMetadatas) {
+        this.actions = actionLayoutMetadatas;
+    }
+
+
+    // must have at least one tab group
+    private List<TabGroup> tabGroups = new ArrayList<TabGroup>() {{
+        add(new TabGroup());
+    }};
+
+    // no wrapper
+
+    /**
+     * Must have at least one tab group; no wrapper.
+     */
+    @XmlElement(name = "tabGroup", required = true)
+    public List<TabGroup> getTabGroups() {
+        return tabGroups;
+    }
+
+    public void setTabGroups(List<TabGroup> tabGroups) {
+        this.tabGroups = tabGroups;
+    }
+
+
+    public interface Visitor {
+        void visit(final ObjectLayoutMetadata objectLayoutMetadata);
+        void visit(final TabGroup tabGroup);
+        void visit(final Tab tab);
+        void visit(final Column column);
+        void visit(final PropertyGroup propertyGroup);
+        void visit(final PropertyLayoutMetadata propertyLayoutMetadata);
+        void visit(final CollectionLayoutMetadata collectionLayoutMetadata);
+        void visit(final ActionLayoutMetadata actionLayoutMetadata);
+    }
+
+    public static class VisitorAdapter implements Visitor {
+        @Override
+        public void visit(final ObjectLayoutMetadata objectLayoutMetadata) { }
+        @Override
+        public void visit(final TabGroup tabGroup) { }
+        @Override
+        public void visit(final Tab tab) { }
+        @Override
+        public void visit(final Column column) { }
+        @Override
+        public void visit(final PropertyGroup propertyGroup) {}
+        @Override
+        public void visit(final PropertyLayoutMetadata propertyLayoutMetadata) {}
+        @Override
+        public void visit(final CollectionLayoutMetadata collectionLayoutMetadata) {}
+        @Override
+        public void visit(final ActionLayoutMetadata actionLayoutMetadata) { }
+    }
+
+
+    /**
+     * Visits all elements of the graph.  The {@link Visitor} implementation
+     * can assume that all "owner" references are populated.
+     */
+    public void visit(final Visitor visitor) {
+        visitor.visit(this);
+        traverseActions(this, visitor);
+        final List<TabGroup> tabGroups = getTabGroups();
+        for (final TabGroup tabGroup : tabGroups) {
+            tabGroup.setOwner(this);
+            visitor.visit(tabGroup);
+            final List<Tab> tabs = tabGroup.getTabs();
+            for (final Tab tab : tabs) {
+                tab.setOwner(tabGroup);
+                visitor.visit(tab);
+                traverseColumn(tab.getLeft(), tab, visitor);
+                traverseColumn(tab.getMiddle(), tab, visitor);
+                traverseColumn(tab.getRight(), tab, visitor);
+            }
+        }
+    }
+
+    private void traverseColumn(final Column column, final Tab tab, final Visitor visitor) {
+        if(column == null) {
+            return;
+        }
+        column.setOwner(tab);
+        visitor.visit(column);
+        traversePropertyGroups(column, visitor);
+        traverseCollections(column, visitor);
+    }
+
+    private void traversePropertyGroups(final Column column, final Visitor visitor) {
+        for (final PropertyGroup propertyGroup : column.getPropertyGroups()) {
+            propertyGroup.setOwner(column);
+            visitor.visit(propertyGroup);
+            traverseActions(propertyGroup, visitor);
+            final List<PropertyLayoutMetadata> properties = propertyGroup.getProperties();
+            for (final PropertyLayoutMetadata propertyLayoutMetadata : properties) {
+                propertyLayoutMetadata.setOwner(propertyGroup);
+                visitor.visit(propertyLayoutMetadata);
+                traverseActions(propertyLayoutMetadata, visitor);
+            }
+        }
+    }
+
+    private void traverseCollections(final Column column, final Visitor visitor) {
+        for (final CollectionLayoutMetadata collectionLayoutMetadata : column.getCollections()) {
+            collectionLayoutMetadata.setOwner(column);
+            visitor.visit(collectionLayoutMetadata);
+            traverseActions(collectionLayoutMetadata, visitor);
+        }
+    }
+
+    private void traverseActions(final ActionHolder actionHolder, final Visitor visitor) {
+        final List<ActionLayoutMetadata> actionLayoutMetadatas = actionHolder.getActions();
+        if(actionLayoutMetadatas == null) {
+            return;
+        }
+        for (final ActionLayoutMetadata actionLayoutMetadata : actionLayoutMetadatas) {
+            actionLayoutMetadata.setOwner(actionHolder);
+            visitor.visit(actionLayoutMetadata);
+        }
+    }
+
+
+    @Programmatic
+    @XmlTransient
+    public LinkedHashMap<String, PropertyLayoutMetadata> getAllPropertiesById() {
+        final LinkedHashMap<String, PropertyLayoutMetadata> propertyIds = Maps.newLinkedHashMap();
+        visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            public void visit(final PropertyLayoutMetadata propertyLayoutMetadata) {
+                propertyIds.put(propertyLayoutMetadata.getId(), propertyLayoutMetadata);
+            }
+        });
+        return propertyIds;
+    }
+
+
+    @Programmatic
+    @XmlTransient
+    public LinkedHashMap<String, CollectionLayoutMetadata> getAllCollectionsById() {
+        final LinkedHashMap<String, CollectionLayoutMetadata> collectionIds = Maps.newLinkedHashMap();
+        final LinkedHashMap<String, ActionLayoutMetadata> actionIds = Maps.newLinkedHashMap();
+
+        visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            @Override
+            public void visit(final CollectionLayoutMetadata collectionLayoutMetadata) {
+                collectionIds.put(collectionLayoutMetadata.getId(), collectionLayoutMetadata);
+            }
+        });
+        return collectionIds;
+    }
+
+
+    @Programmatic
+    @XmlTransient
+    public LinkedHashMap<String, ActionLayoutMetadata> getAllActionsById() {
+        final LinkedHashMap<String, ActionLayoutMetadata> actionIds = Maps.newLinkedHashMap();
+
+        visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            @Override
+            public void visit(final ActionLayoutMetadata actionLayoutMetadata) {
+                actionIds.put(actionLayoutMetadata.getId(), actionLayoutMetadata);
+            }
+        });
+        return actionIds;
+    }
+
+
+
+    private boolean normalized;
+
+    /**
+     * Whether {@link ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class)}
+     * has been called on this instance.
+     */
+    @Programmatic
+    @XmlTransient
+    public boolean isNormalized() {
+        return normalized;
+    }
+
+    public void setNormalized(final boolean normalized) {
+        this.normalized = normalized;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Property.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Property.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Property.java
deleted file mode 100644
index e01e47c..0000000
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Property.java
+++ /dev/null
@@ -1,209 +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.applib.layout.v1_0;
-
-import java.io.Serializable;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.isis.applib.annotation.LabelPosition;
-import org.apache.isis.applib.annotation.Where;
-
-/**
- * Broadly corresponds to the {@link org.apache.isis.applib.annotation.PropertyLayout} annotation.
- */
-@XmlType(
-        propOrder = {
-                "named"
-                , "describedAs"
-                , "actions"
-        }
-)
-public class Property implements ActionHolder, Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    public Property() {
-    }
-
-    public Property(final String id) {
-        this.id = id;
-    }
-
-    private String id;
-
-    /**
-     * Property identifier, being the getter method without "get" or "is" prefix, first letter lower cased.
-     */
-    @XmlAttribute(required = true)
-    public String getId() {
-        return id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-
-
-    private String cssClass;
-
-    @XmlAttribute(required = false)
-    public String getCssClass() {
-        return cssClass;
-    }
-
-    public void setCssClass(String cssClass) {
-        this.cssClass = cssClass;
-    }
-
-
-    private String describedAs;
-
-    @XmlElement(required = false)
-    public String getDescribedAs() {
-        return describedAs;
-    }
-
-    public void setDescribedAs(String describedAs) {
-        this.describedAs = describedAs;
-    }
-
-
-    private Where hidden;
-
-    @XmlAttribute(required = false)
-    public Where getHidden() {
-        return hidden;
-    }
-
-    public void setHidden(Where hidden) {
-        this.hidden = hidden;
-    }
-
-
-    private LabelPosition labelPosition;
-
-    @XmlAttribute(required = false)
-    public LabelPosition getLabelPosition() {
-        return labelPosition;
-    }
-
-    public void setLabelPosition(LabelPosition labelPosition) {
-        this.labelPosition = labelPosition;
-    }
-
-
-    private Integer multiLine;
-
-    @XmlAttribute(required = false)
-    public Integer getMultiLine() {
-        return multiLine;
-    }
-
-    public void setMultiLine(Integer multiLine) {
-        this.multiLine = multiLine;
-    }
-
-
-    private String named;
-
-    @XmlElement(required = false)
-    public String getNamed() {
-        return named;
-    }
-
-    public void setNamed(String named) {
-        this.named = named;
-    }
-
-
-    private Boolean namedEscaped;
-
-    @XmlAttribute(required = false)
-    public Boolean getNamedEscaped() {
-        return namedEscaped;
-    }
-
-    public void setNamedEscaped(Boolean namedEscaped) {
-        this.namedEscaped = namedEscaped;
-    }
-
-
-    private Boolean renderedAsDayBefore;
-
-    @XmlAttribute(required = false)
-    public Boolean getRenderedAsDayBefore() {
-        return renderedAsDayBefore;
-    }
-
-    public void setRenderedAsDayBefore(Boolean renderedAsDayBefore) {
-        this.renderedAsDayBefore = renderedAsDayBefore;
-    }
-
-
-    private Integer typicalLength;
-
-    @XmlAttribute(required = false)
-    public Integer getTypicalLength() {
-        return typicalLength;
-    }
-
-    public void setTypicalLength(Integer typicalLength) {
-        this.typicalLength = typicalLength;
-    }
-
-
-
-    private List<Action> actions;
-
-    @XmlElementWrapper(required = false)
-    @XmlElement(name = "action", required = false)
-    public List<Action> getActions() {
-        return actions;
-    }
-
-    public void setActions(List<Action> actions) {
-        this.actions = actions;
-    }
-
-
-    private PropertyGroup owner;
-    /**
-     * Owner.
-     *
-     * <p>
-     *     Set programmatically by framework after reading in from XML.
-     * </p>
-     */
-    @XmlTransient
-    public PropertyGroup getOwner() {
-        return owner;
-    }
-
-    public void setOwner(final PropertyGroup owner) {
-        this.owner = owner;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java
index 78ef28a..fd7f3c7 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java
@@ -22,13 +22,14 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.annotation.Nullable;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
-import com.google.common.collect.Lists;
+import com.google.common.base.Function;
 
 import org.apache.isis.applib.annotation.MemberOrder;
 
@@ -66,31 +67,31 @@ public class PropertyGroup implements ColumnContent, ActionHolder, Serializable
 
 
 
-    private List<Action> actions;
+    private List<ActionLayoutMetadata> actions;
 
     @XmlElementWrapper(required = false)
     @XmlElement(name = "action", required = false)
-    public List<Action> getActions() {
+    public List<ActionLayoutMetadata> getActions() {
         return actions;
     }
 
-    public void setActions(List<Action> actions) {
-        this.actions = actions;
+    public void setActions(List<ActionLayoutMetadata> actionLayoutMetadatas) {
+        this.actions = actionLayoutMetadatas;
     }
 
 
 
     // must be at least one property in the property group
-    private List<Property> properties = new ArrayList<Property>() {{
-        add(new Property());
+    private List<PropertyLayoutMetadata> properties = new ArrayList<PropertyLayoutMetadata>() {{
+        add(new PropertyLayoutMetadata());
     }};
 
     @XmlElement(name = "property", required = true)
-    public List<Property> getProperties() {
+    public List<PropertyLayoutMetadata> getProperties() {
         return properties;
     }
 
-    public void setProperties(List<Property> properties) {
+    public void setProperties(List<PropertyLayoutMetadata> properties) {
         this.properties = properties;
     }
 
@@ -113,4 +114,16 @@ public class PropertyGroup implements ColumnContent, ActionHolder, Serializable
     }
 
 
+    public static class Util {
+        private Util(){}
+        public static Function<? super PropertyGroup, String> nameOf() {
+            return new Function<PropertyGroup, String>() {
+                @Nullable @Override
+                public String apply(@Nullable final PropertyGroup propertyGroup) {
+                    return propertyGroup.getName();
+                }
+            };
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayoutMetadata.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayoutMetadata.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayoutMetadata.java
new file mode 100644
index 0000000..5f6b3b1
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayoutMetadata.java
@@ -0,0 +1,227 @@
+/*
+ *  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.applib.layout.v1_0;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.isis.applib.annotation.LabelPosition;
+import org.apache.isis.applib.annotation.Where;
+
+/**
+ * Broadly corresponds to the {@link org.apache.isis.applib.annotation.PropertyLayout} annotation.
+ */
+@XmlType(
+        name = "propertyLayout"
+        , propOrder = {
+                "named"
+                , "describedAs"
+                , "actions"
+                , "metadataError"
+        }
+)
+public class PropertyLayoutMetadata implements ActionHolder, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    public PropertyLayoutMetadata() {
+    }
+
+    public PropertyLayoutMetadata(final String id) {
+        this.id = id;
+    }
+
+    private String id;
+
+    /**
+     * Property identifier, being the getter method without "get" or "is" prefix, first letter lower cased.
+     */
+    @XmlAttribute(required = true)
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+
+
+    private String cssClass;
+
+    @XmlAttribute(required = false)
+    public String getCssClass() {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass) {
+        this.cssClass = cssClass;
+    }
+
+
+    private String describedAs;
+
+    @XmlElement(required = false)
+    public String getDescribedAs() {
+        return describedAs;
+    }
+
+    public void setDescribedAs(String describedAs) {
+        this.describedAs = describedAs;
+    }
+
+
+    private Where hidden;
+
+    @XmlAttribute(required = false)
+    public Where getHidden() {
+        return hidden;
+    }
+
+    public void setHidden(Where hidden) {
+        this.hidden = hidden;
+    }
+
+
+    private LabelPosition labelPosition;
+
+    @XmlAttribute(required = false)
+    public LabelPosition getLabelPosition() {
+        return labelPosition;
+    }
+
+    public void setLabelPosition(LabelPosition labelPosition) {
+        this.labelPosition = labelPosition;
+    }
+
+
+    private Integer multiLine;
+
+    @XmlAttribute(required = false)
+    public Integer getMultiLine() {
+        return multiLine;
+    }
+
+    public void setMultiLine(Integer multiLine) {
+        this.multiLine = multiLine;
+    }
+
+
+    private String named;
+
+    @XmlElement(required = false)
+    public String getNamed() {
+        return named;
+    }
+
+    public void setNamed(String named) {
+        this.named = named;
+    }
+
+
+    private Boolean namedEscaped;
+
+    @XmlAttribute(required = false)
+    public Boolean getNamedEscaped() {
+        return namedEscaped;
+    }
+
+    public void setNamedEscaped(Boolean namedEscaped) {
+        this.namedEscaped = namedEscaped;
+    }
+
+
+    private Boolean renderedAsDayBefore;
+
+    @XmlAttribute(required = false)
+    public Boolean getRenderedAsDayBefore() {
+        return renderedAsDayBefore;
+    }
+
+    public void setRenderedAsDayBefore(Boolean renderedAsDayBefore) {
+        this.renderedAsDayBefore = renderedAsDayBefore;
+    }
+
+
+    private Integer typicalLength;
+
+    @XmlAttribute(required = false)
+    public Integer getTypicalLength() {
+        return typicalLength;
+    }
+
+    public void setTypicalLength(Integer typicalLength) {
+        this.typicalLength = typicalLength;
+    }
+
+
+
+    private List<ActionLayoutMetadata> actions;
+
+    @XmlElementWrapper(required = false)
+    @XmlElement(name = "action", required = false)
+    public List<ActionLayoutMetadata> getActions() {
+        return actions;
+    }
+
+    public void setActions(List<ActionLayoutMetadata> actionLayoutMetadatas) {
+        this.actions = actionLayoutMetadatas;
+    }
+
+
+    private PropertyGroup owner;
+    /**
+     * Owner.
+     *
+     * <p>
+     *     Set programmatically by framework after reading in from XML.
+     * </p>
+     */
+    @XmlTransient
+    public PropertyGroup getOwner() {
+        return owner;
+    }
+
+    public void setOwner(final PropertyGroup owner) {
+        this.owner = owner;
+    }
+
+
+
+    private String metadataError;
+
+    /**
+     * For diagnostics; populated by the framework if and only if a metadata error.
+     */
+    @XmlElement(required = false)
+    public String getMetadataError() {
+        return metadataError;
+    }
+
+    public void setMetadataError(final String metadataError) {
+        this.metadataError = metadataError;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Tab.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Tab.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Tab.java
index e81d20a..04d2542 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Tab.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Tab.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
+import com.google.common.base.Predicate;
 import com.google.common.collect.Lists;
 
 import org.apache.isis.applib.annotation.Programmatic;
@@ -130,9 +131,20 @@ public class Tab implements Serializable {
         if(propertyGroups != null) {
             contents.addAll(propertyGroups);
         }
-        final List<Collection> collections = column.getCollections();
-        if(collections != null) {
-            contents.addAll(collections);
+        final List<CollectionLayoutMetadata> collectionLayoutMetadatas = column.getCollections();
+        if(collectionLayoutMetadatas != null) {
+            contents.addAll(collectionLayoutMetadatas);
+        }
+    }
+
+    public static class Predicates {
+        public static Predicate<Tab> notEmpty() {
+            return new Predicate<Tab>() {
+                @Override
+                public boolean apply(final Tab tab) {
+                    return !tab.getContents().isEmpty();
+                }
+            };
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/TabGroup.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/TabGroup.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/TabGroup.java
index 60f39b8..7547d5e 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/TabGroup.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/TabGroup.java
@@ -26,6 +26,9 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+
 @XmlType()
 public class TabGroup implements Serializable {
 
@@ -50,7 +53,7 @@ public class TabGroup implements Serializable {
 
 
 
-    private DomainObject owner;
+    private ObjectLayoutMetadata owner;
 
     /**
      * Owner.
@@ -60,12 +63,26 @@ public class TabGroup implements Serializable {
      * </p>
      */
     @XmlTransient
-    public DomainObject getOwner() {
+    public ObjectLayoutMetadata getOwner() {
         return owner;
     }
 
-    public void setOwner(final DomainObject owner) {
+    public void setOwner(final ObjectLayoutMetadata owner) {
         this.owner = owner;
     }
 
+
+    public static class Predicates {
+        public static Predicate<TabGroup> notEmpty() {
+            return new Predicate<TabGroup>() {
+                @Override
+                public boolean apply(final TabGroup tabGroup) {
+                    return FluentIterable
+                            .from(tabGroup.getTabs())
+                            .anyMatch(Tab.Predicates.notEmpty());
+                }
+            };
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java
new file mode 100644
index 0000000..56efd62
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java
@@ -0,0 +1,34 @@
+/**
+ *  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.applib.services.layout;
+
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+
+public interface ObjectLayoutMetadataService {
+
+    @Programmatic ObjectLayoutMetadata fromXml(Class<?> domainClass);
+
+    /**
+     *  @param objectLayoutMetadata - the layout to be validated.
+     * @param domainClass - as per domain class.
+     */
+    @Programmatic ObjectLayoutMetadata normalize(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass);
+
+    @Programmatic String toXml(ObjectLayoutMetadata objectLayoutMetadata);
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java
new file mode 100644
index 0000000..9a3f5d2
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java
@@ -0,0 +1,67 @@
+/**
+ *  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.applib.services.layout;
+
+import java.io.IOException;
+
+import javax.inject.Inject;
+import javax.xml.bind.JAXBException;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Mixin;
+import org.apache.isis.applib.annotation.RestrictTo;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.dto.Dto;
+import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.applib.value.Clob;
+
+@Mixin
+public class Object_downloadLayoutXml {
+
+    private final Object object;
+
+    public Object_downloadLayoutXml(final Dto object) {
+        this.object = object;
+    }
+
+    public static class ActionDomainEvent extends org.apache.isis.applib.IsisApplibModule.ActionDomainEvent<Object_downloadLayoutXml> {}
+
+    @Action(
+            domainEvent = ActionDomainEvent.class,
+            semantics = SemanticsOf.SAFE,
+            restrictTo = RestrictTo.PROTOTYPING
+    )
+    @ActionLayout(
+            cssClassFa = "fa-download"
+    )
+    @MemberOrder(sequence = "550.1")
+    public Object $$(final String fileName) throws JAXBException, IOException {
+        final String xml = layoutXmlService.toXml(object);
+        return new Clob(Util.withSuffix(fileName, "xml"), "text/xml", xml);
+    }
+
+    public String default0$$() {
+        return Util.withSuffix(object.getClass().getName(), "xml");
+    }
+
+
+    @Inject
+    JaxbService layoutXmlService;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/applib/src/main/java/org/apache/isis/applib/services/layout/Util.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/Util.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Util.java
new file mode 100644
index 0000000..7e04bf8
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Util.java
@@ -0,0 +1,33 @@
+/**
+ *  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.applib.services.layout;
+
+class Util {
+
+    private Util(){}
+
+    static String withSuffix(String fileName, String suffix) {
+        if(!suffix.startsWith(".")) {
+            suffix = "." + suffix;
+        }
+        if(!fileName.endsWith(suffix)) {
+            fileName += suffix;
+        }
+        return fileName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionPositionFacetForActionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionPositionFacetForActionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionPositionFacetForActionXml.java
index d19bf9d..d2ea8ea 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionPositionFacetForActionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionPositionFacetForActionXml.java
@@ -19,14 +19,14 @@
 
 package org.apache.isis.core.metamodel.facets.actions.layout;
 
-import org.apache.isis.applib.layout.v1_0.Action;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet;
 import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacetAbstract;
 
 public class ActionPositionFacetForActionXml extends ActionPositionFacetAbstract {
 
-    public static ActionPositionFacet create(Action actionLayout, FacetHolder holder) {
+    public static ActionPositionFacet create(ActionLayoutMetadata actionLayout, FacetHolder holder) {
         if(actionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/BookmarkPolicyFacetForActionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/BookmarkPolicyFacetForActionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/BookmarkPolicyFacetForActionXml.java
index b3a9623..8ba315b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/BookmarkPolicyFacetForActionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/BookmarkPolicyFacetForActionXml.java
@@ -20,14 +20,14 @@
 package org.apache.isis.core.metamodel.facets.actions.layout;
 
 import org.apache.isis.applib.annotation.BookmarkPolicy;
-import org.apache.isis.applib.layout.v1_0.Action;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacetAbstract;
 
 public class BookmarkPolicyFacetForActionXml extends BookmarkPolicyFacetAbstract {
 
-    public static BookmarkPolicyFacet create(final Action actionLayout, final FacetHolder holder) {
+    public static BookmarkPolicyFacet create(final ActionLayoutMetadata actionLayout, final FacetHolder holder) {
         if (actionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFaFacetForActionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFaFacetForActionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFaFacetForActionXml.java
index d0258d4..b413266 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFaFacetForActionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFaFacetForActionXml.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.metamodel.facets.actions.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Action;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacetAbstract;
@@ -29,7 +29,7 @@ import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaPositi
 
 public class CssClassFaFacetForActionXml extends CssClassFaFacetAbstract {
 
-    public static CssClassFaFacet create(final Action actionLayout, final FacetHolder holder) {
+    public static CssClassFaFacet create(final ActionLayoutMetadata actionLayout, final FacetHolder holder) {
         if(actionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFacetForActionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFacetForActionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFacetForActionXml.java
index 9ba1431..d50323f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFacetForActionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/CssClassFacetForActionXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.actions.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Action;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacetAbstract;
 
 public class CssClassFacetForActionXml extends CssClassFacetAbstract {
 
-    public static CssClassFacet create(Action actionLayout, FacetHolder holder) {
+    public static CssClassFacet create(ActionLayoutMetadata actionLayout, FacetHolder holder) {
         if(actionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/DescribedAsFacetForActionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/DescribedAsFacetForActionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/DescribedAsFacetForActionXml.java
index a33dd7c..ee81891 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/DescribedAsFacetForActionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/DescribedAsFacetForActionXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.actions.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Action;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacetAbstract;
 
 public class DescribedAsFacetForActionXml extends DescribedAsFacetAbstract {
 
-    public static DescribedAsFacet create(Action actionLayout, FacetHolder holder) {
+    public static DescribedAsFacet create(ActionLayoutMetadata actionLayout, FacetHolder holder) {
         if(actionLayout == null) {
             return null;
         }


[4/4] isis git commit: ISIS-993: more on the layout service, ability to download a zip of all layouts

Posted by da...@apache.org.
ISIS-993: more on the layout service, ability to download a zip of all layouts


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

Branch: refs/heads/ISIS-993
Commit: 2cb78cf0112e1213717223f9cfd442c04d68bb60
Parents: 4da8f96
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Jan 8 17:01:24 2016 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Jan 8 17:01:24 2016 +0000

----------------------------------------------------------------------
 .../applib/services/dto/Dto_downloadXml.java    |   9 +-
 .../applib/services/dto/Dto_downloadXsd.java    |   2 +
 .../layout/ObjectLayoutMetadataService.java     |  21 ++-
 .../layout/Object_downloadLayoutXml.java        |  30 ++--
 .../services/layout/Object_viewLayout.java      |  70 +++++++++
 .../ObjectLayoutMetadataFacet.java              |  35 +++++
 .../ObjectLayoutMetadataFacetDefault.java       |  65 ++++++++
 .../ObjectLayoutMetadataFacetFactory.java       |  61 ++++++++
 .../object/layoutxml/LayoutXmlFacetFactory.java |  61 --------
 .../layoutxml/ObjectLayoutMetadataFacet.java    |  35 -----
 .../ObjectLayoutMetadataFacetDefault.java       |  65 --------
 .../ObjectLayoutMetadataServiceDefault.java     |  13 +-
 .../services/metamodel/MetadataMenu.java        | 150 +++++++++++++++++++
 .../core/metamodel/services/metamodel/Util.java |  33 ++++
 .../dflt/ProgrammingModelFacetsJava5.java       |   4 +-
 .../combined/EntityCombinedPanelFactory.java    |   2 +-
 .../entity/tabgroups/EntityTabGroupsPanel.java  |   2 +-
 .../tabgroups/EntityTabGroupsPanelFactory.java  |   2 +-
 .../dom/simple/SimpleObject.layout.xml          |  13 +-
 19 files changed, 481 insertions(+), 192 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXml.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXml.java b/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXml.java
index 3cd9ad4..34b1072 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXml.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXml.java
@@ -16,15 +16,13 @@
  */
 package org.apache.isis.applib.services.dto;
 
-import java.io.IOException;
-
 import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Mixin;
+import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.RestrictTo;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.jaxb.JaxbService;
@@ -50,8 +48,9 @@ public class Dto_downloadXml {
             cssClassFa = "fa-download"
     )
     @MemberOrder(sequence = "500.1")
-    public Object $$(final String fileName) throws JAXBException, IOException {
-
+    public Object $$(
+            @ParameterLayout(named = "File name")
+            final String fileName) {
         final String xml = jaxbService.toXml(dto);
         return new Clob(Util.withSuffix(fileName, "xml"), "text/xml", xml);
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXsd.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXsd.java b/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXsd.java
index 9366ec4..a139f15 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXsd.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/dto/Dto_downloadXsd.java
@@ -33,6 +33,7 @@ import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Mixin;
+import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.RestrictTo;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.jaxb.JaxbService;
@@ -67,6 +68,7 @@ public class Dto_downloadXsd {
     )
     @MemberOrder(sequence = "500.2")
     public Object $$(
+            @ParameterLayout(named = "File name")
             final String fileName,
             final JaxbService.IsisSchemas isisSchemas) {
 

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java
index 56efd62..f0da669 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java
@@ -21,14 +21,29 @@ import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
 
 public interface ObjectLayoutMetadataService {
 
-    @Programmatic ObjectLayoutMetadata fromXml(Class<?> domainClass);
+    /**
+     * Returns raw (unnormalized) metadata, per the <code>.layout.xml</code> file.
+     */
+    @Programmatic
+    ObjectLayoutMetadata fromXml(Class<?> domainClass);
 
     /**
      *  @param objectLayoutMetadata - the layout to be validated.
      * @param domainClass - as per domain class.
      */
-    @Programmatic ObjectLayoutMetadata normalize(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass);
+    @Programmatic
+    ObjectLayoutMetadata normalize(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass);
 
-    @Programmatic String toXml(ObjectLayoutMetadata objectLayoutMetadata);
+    /**
+     * Obtains the layout metadata for the specified domain object.  It will have been {@link #normalize(ObjectLayoutMetadata, Class) normalized} already.
+     */
+    @Programmatic
+    ObjectLayoutMetadata toMetadata(Object domainObject);
+
+    /**
+     * Obtains the layout metadata for the specified domain class.  It will have been {@link #normalize(ObjectLayoutMetadata, Class) normalized} already.
+     */
+    @Programmatic
+    ObjectLayoutMetadata toMetadata(Class<?> domainClass);
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java
index 9a3f5d2..aca104c 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java
@@ -16,18 +16,16 @@
  */
 package org.apache.isis.applib.services.layout;
 
-import java.io.IOException;
-
 import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Mixin;
+import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.RestrictTo;
 import org.apache.isis.applib.annotation.SemanticsOf;
-import org.apache.isis.applib.services.dto.Dto;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.value.Clob;
 
@@ -36,7 +34,7 @@ public class Object_downloadLayoutXml {
 
     private final Object object;
 
-    public Object_downloadLayoutXml(final Dto object) {
+    public Object_downloadLayoutXml(final Object object) {
         this.object = object;
     }
 
@@ -51,17 +49,31 @@ public class Object_downloadLayoutXml {
             cssClassFa = "fa-download"
     )
     @MemberOrder(sequence = "550.1")
-    public Object $$(final String fileName) throws JAXBException, IOException {
-        final String xml = layoutXmlService.toXml(object);
+    public Object $$(
+            @ParameterLayout(named = "File name")
+            final String fileName) {
+        final ObjectLayoutMetadata metadata = getObjectLayoutMetadata();
+        final String xml = jaxbService.toXml(metadata);
         return new Clob(Util.withSuffix(fileName, "xml"), "text/xml", xml);
     }
 
+    public boolean hide$$() {
+        return getObjectLayoutMetadata() == null;
+    }
     public String default0$$() {
-        return Util.withSuffix(object.getClass().getName(), "xml");
+        return Util.withSuffix(object.getClass().getSimpleName(), "layout.xml");
+    }
+
+    protected ObjectLayoutMetadata getObjectLayoutMetadata() {
+        return objectLayoutMetadataService.toMetadata(object);
     }
 
 
+
+    @Inject
+    ObjectLayoutMetadataService objectLayoutMetadataService;
+
     @Inject
-    JaxbService layoutXmlService;
+    JaxbService jaxbService;
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_viewLayout.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_viewLayout.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_viewLayout.java
new file mode 100644
index 0000000..4957e9c
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_viewLayout.java
@@ -0,0 +1,70 @@
+/**
+ *  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.applib.services.layout;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Mixin;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.RestrictTo;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+
+@Mixin
+public class Object_viewLayout {
+
+    private final Object object;
+
+    public Object_viewLayout(final Object object) {
+        this.object = object;
+    }
+
+    public static class ActionDomainEvent extends org.apache.isis.applib.IsisApplibModule.ActionDomainEvent<Object_viewLayout> {}
+
+
+
+    @Programmatic // TODO ... excluded for now (getting an Isis framework exception in the view model rendering).
+    @Action(
+            domainEvent = ActionDomainEvent.class,
+            semantics = SemanticsOf.SAFE,
+            restrictTo = RestrictTo.PROTOTYPING
+    )
+    @ActionLayout(
+            cssClassFa = "fa-th"
+    )
+    @MemberOrder(sequence = "550.2")
+    public ObjectLayoutMetadata $$() {
+        return getObjectLayoutMetadata();
+    }
+
+    public boolean hide$$() {
+        return getObjectLayoutMetadata() == null;
+    }
+
+    protected ObjectLayoutMetadata getObjectLayoutMetadata() {
+        return objectLayoutMetadataService.toMetadata(object);
+    }
+
+
+
+    @Inject
+    ObjectLayoutMetadataService objectLayoutMetadataService;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java
new file mode 100644
index 0000000..4d8db93
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.facets.object.layoutmetadata;
+
+
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+
+/**
+ * Corresponds to providing a <code>.layout.xml</code> file for the domain object's class.
+ */
+public interface ObjectLayoutMetadataFacet extends Facet {
+
+    /**
+     * Will have been {@link org.apache.isis.applib.services.layout.ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class) normalized}.
+     */
+    ObjectLayoutMetadata getMetadata();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java
new file mode 100644
index 0000000..95e3712
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.facets.object.layoutmetadata;
+
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+public class ObjectLayoutMetadataFacetDefault
+            extends FacetAbstract
+            implements ObjectLayoutMetadataFacet {
+
+    private final ObjectLayoutMetadata metadata;
+    private final ObjectLayoutMetadataService objectLayoutMetadataService;
+
+    public static Class<? extends Facet> type() {
+        return ObjectLayoutMetadataFacet.class;
+    }
+
+
+    public static ObjectLayoutMetadataFacet create(
+            final FacetHolder facetHolder,
+            final ObjectLayoutMetadata objectLayoutMetadata,
+            final ObjectLayoutMetadataService objectLayoutMetadataService) {
+        if(objectLayoutMetadata == null) {
+            return null;
+        }
+        return new ObjectLayoutMetadataFacetDefault(facetHolder, objectLayoutMetadata, objectLayoutMetadataService);
+    }
+
+    private ObjectLayoutMetadataFacetDefault(
+            final FacetHolder facetHolder,
+            final ObjectLayoutMetadata metadata,
+            final ObjectLayoutMetadataService objectLayoutMetadataService) {
+        super(ObjectLayoutMetadataFacetDefault.type(), facetHolder, Derivation.NOT_DERIVED);
+        this.metadata = metadata;
+        this.objectLayoutMetadataService = objectLayoutMetadataService;
+    }
+
+
+    public ObjectLayoutMetadata getMetadata() {
+        final ObjectSpecification objectSpecification = (ObjectSpecification) getFacetHolder();
+        return objectLayoutMetadataService.normalize(metadata, objectSpecification.getCorrespondingClass());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java
new file mode 100644
index 0000000..0f1b4e8
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java
@@ -0,0 +1,61 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License. */
+package org.apache.isis.core.metamodel.facets.object.layoutmetadata;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjectorAware;
+
+public class ObjectLayoutMetadataFacetFactory extends FacetFactoryAbstract implements ServicesInjectorAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ObjectLayoutMetadataFacetFactory.class);
+
+    public ObjectLayoutMetadataFacetFactory() {
+        super(FeatureType.OBJECTS_ONLY);
+    }
+
+    @Override
+    public void process(final ProcessClassContext processClassContext) {
+        final Class<?> cls = processClassContext.getCls();
+        final FacetHolder facetHolder = processClassContext.getFacetHolder();
+
+        final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class);
+        FacetUtil.addFacet(
+                ObjectLayoutMetadataFacetDefault.create(facetHolder, readMetadata(cls), objectLayoutMetadataService));
+    }
+
+    private ObjectLayoutMetadata readMetadata(final Class<?> domainClass) {
+        final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class);
+        return objectLayoutMetadataService.fromXml(domainClass);
+    }
+
+    private ServicesInjector servicesInjector;
+
+    @Override
+    public void setServicesInjector(final ServicesInjector servicesInjector) {
+        this.servicesInjector = servicesInjector;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
deleted file mode 100644
index f898f61..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
+++ /dev/null
@@ -1,61 +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.core.metamodel.facets.object.layoutxml;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
-import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.FacetUtil;
-import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
-import org.apache.isis.core.metamodel.runtimecontext.ServicesInjectorAware;
-
-public class LayoutXmlFacetFactory extends FacetFactoryAbstract implements ServicesInjectorAware {
-
-    private static final Logger LOG = LoggerFactory.getLogger(LayoutXmlFacetFactory.class);
-
-    public LayoutXmlFacetFactory() {
-        super(FeatureType.OBJECTS_ONLY);
-    }
-
-    @Override
-    public void process(final ProcessClassContext processClassContext) {
-        final Class<?> cls = processClassContext.getCls();
-        final FacetHolder facetHolder = processClassContext.getFacetHolder();
-
-        final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class);
-        FacetUtil.addFacet(
-                ObjectLayoutMetadataFacetDefault.create(facetHolder, readMetadata(cls), objectLayoutMetadataService));
-    }
-
-    private ObjectLayoutMetadata readMetadata(final Class<?> domainClass) {
-        final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class);
-        return objectLayoutMetadataService.fromXml(domainClass);
-    }
-
-    private ServicesInjector servicesInjector;
-
-    @Override
-    public void setServicesInjector(final ServicesInjector servicesInjector) {
-        this.servicesInjector = servicesInjector;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java
deleted file mode 100644
index 7285fc0..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java
+++ /dev/null
@@ -1,35 +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.core.metamodel.facets.object.layoutxml;
-
-
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
-
-/**
- * Corresponds to providing a <code>.layout.xml</code> file for the domain object's class.
- */
-public interface ObjectLayoutMetadataFacet extends Facet {
-
-    /**
-     * Will have been {@link org.apache.isis.applib.services.layout.ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class) normalized}.
-     */
-    ObjectLayoutMetadata getMetadata();
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java
deleted file mode 100644
index 05d3cc8..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java
+++ /dev/null
@@ -1,65 +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.core.metamodel.facets.object.layoutxml;
-
-import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
-import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-
-public class ObjectLayoutMetadataFacetDefault
-            extends FacetAbstract
-            implements ObjectLayoutMetadataFacet {
-
-    private final ObjectLayoutMetadata metadata;
-    private final ObjectLayoutMetadataService objectLayoutMetadataService;
-
-    public static Class<? extends Facet> type() {
-        return ObjectLayoutMetadataFacet.class;
-    }
-
-
-    public static ObjectLayoutMetadataFacet create(
-            final FacetHolder facetHolder,
-            final ObjectLayoutMetadata objectLayoutMetadata,
-            final ObjectLayoutMetadataService objectLayoutMetadataService) {
-        if(objectLayoutMetadata == null) {
-            return null;
-        }
-        return new ObjectLayoutMetadataFacetDefault(facetHolder, objectLayoutMetadata, objectLayoutMetadataService);
-    }
-
-    private ObjectLayoutMetadataFacetDefault(
-            final FacetHolder facetHolder,
-            final ObjectLayoutMetadata metadata,
-            final ObjectLayoutMetadataService objectLayoutMetadataService) {
-        super(ObjectLayoutMetadataFacetDefault.type(), facetHolder, Derivation.NOT_DERIVED);
-        this.metadata = metadata;
-        this.objectLayoutMetadataService = objectLayoutMetadataService;
-    }
-
-
-    public ObjectLayoutMetadata getMetadata() {
-        final ObjectSpecification objectSpecification = (ObjectSpecification) getFacetHolder();
-        return objectLayoutMetadataService.normalize(metadata, objectSpecification.getCorrespondingClass());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java
index c9daf91..294531a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java
@@ -68,6 +68,7 @@ import org.apache.isis.core.metamodel.facets.collections.layout.NamedFacetForCol
 import org.apache.isis.core.metamodel.facets.collections.layout.PagedFacetForCollectionXml;
 import org.apache.isis.core.metamodel.facets.collections.layout.SortedByFacetForCollectionXml;
 import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetXml;
+import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet;
 import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet;
 import org.apache.isis.core.metamodel.facets.properties.propertylayout.CssClassFacetForPropertyXml;
 import org.apache.isis.core.metamodel.facets.properties.propertylayout.DescribedAsFacetForPropertyXml;
@@ -436,10 +437,18 @@ public class ObjectLayoutMetadataServiceDefault
 
 
     @Override
-    public String toXml(final ObjectLayoutMetadata objectLayoutMetadata) {
-        return jaxbService.toXml(objectLayoutMetadata);
+    public ObjectLayoutMetadata toMetadata(final Object domainObject) {
+        return toMetadata(domainObject.getClass());
     }
 
+    @Override
+    public ObjectLayoutMetadata toMetadata(final Class<?> domainClass) {
+        final ObjectSpecification objectSpec = specificationLookup.loadSpecification(domainClass);
+        final ObjectLayoutMetadataFacet facet = objectSpec.getFacet(ObjectLayoutMetadataFacet.class);
+        return facet != null? facet.getMetadata(): null;
+    }
+
+
 
     //region > injected dependencies
     private DeploymentCategory deploymentCategory;

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java
new file mode 100644
index 0000000..fadfae2
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java
@@ -0,0 +1,150 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.core.metamodel.services.metamodel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Collection;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.activation.MimeType;
+import javax.activation.MimeTypeParseException;
+import javax.inject.Inject;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+
+import org.apache.isis.applib.FatalException;
+import org.apache.isis.applib.IsisApplibModule;
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.DomainServiceLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.NatureOfService;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.RestrictTo;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
+import org.apache.isis.applib.value.Blob;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpiAware;
+
+@DomainService(
+        nature = NatureOfService.VIEW_MENU_ONLY
+)
+@DomainServiceLayout(
+        named = "Prototyping",
+        menuBar = DomainServiceLayout.MenuBar.SECONDARY,
+        menuOrder = "500.400"
+)
+public class MetadataMenu implements SpecificationLoaderSpiAware {
+
+    public static abstract class ActionDomainEvent extends IsisApplibModule.ActionDomainEvent<MetadataMenu> {
+    }
+
+    // //////////////////////////////////////
+
+
+    private final MimeType mimeTypeApplicationZip;
+
+    public MetadataMenu() {
+        try {
+            mimeTypeApplicationZip = new MimeType("application", "zip");
+        } catch (final MimeTypeParseException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+
+    // //////////////////////////////////////
+
+    public static class DownloadLayoutsDomainEvent extends ActionDomainEvent {
+    }
+
+    @Action(
+            domainEvent = DownloadLayoutsDomainEvent.class,
+            semantics = SemanticsOf.SAFE,
+            restrictTo = RestrictTo.PROTOTYPING
+    )
+    @ActionLayout(
+            cssClassFa = "fa-download"
+    )
+    @MemberOrder(sequence="500.400.1")
+    public Blob downloadLayouts() {
+        final Collection<ObjectSpecification> allSpecs = specificationLoader.allSpecifications();
+        final Collection<ObjectSpecification> domainObjectSpecs = Collections2
+                .filter(allSpecs, new Predicate<ObjectSpecification>(){
+                    @Override
+                    public boolean apply(final ObjectSpecification input) {
+                        return  !input.isAbstract() &&
+                                !input.isService() &&
+                                !input.isValue() &&
+                                !input.isParentedOrFreeCollection();
+                    }});
+        try {
+            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            final ZipOutputStream zos = new ZipOutputStream(baos);
+            final OutputStreamWriter writer = new OutputStreamWriter(zos);
+            for (final ObjectSpecification objectSpec : domainObjectSpecs) {
+                final Class<?> domainClass = objectSpec.getCorrespondingClass();
+                final ObjectLayoutMetadata metadata = objectLayoutMetadataService.toMetadata(domainClass);
+                if(metadata != null) {
+                    zos.putNextEntry(new ZipEntry(zipEntryNameFor(objectSpec)));
+                    String xml = jaxbService.toXml(metadata);
+                    writer.write(xml);
+                    writer.flush();
+                    zos.closeEntry();
+                }
+            }
+            writer.close();
+            return new Blob("layouts.zip", mimeTypeApplicationZip, baos.toByteArray());
+        } catch (final IOException ex) {
+            throw new FatalException("Unable to create zip of layouts", ex);
+        }
+    }
+
+    private static String zipEntryNameFor(final ObjectSpecification objectSpec) {
+        final String fqn = objectSpec.getFullIdentifier();
+        return fqn.replace(".", File.separator)+".layout.xml";
+    }
+
+
+    // //////////////////////////////////////
+
+    @Inject
+    ObjectLayoutMetadataService objectLayoutMetadataService;
+
+    @Inject
+    JaxbService jaxbService;
+
+    private SpecificationLoaderSpi specificationLoader;
+
+    @Programmatic
+    @Override
+    public void setSpecificationLoaderSpi(final SpecificationLoaderSpi specificationLoader) {
+        this.specificationLoader = specificationLoader;
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/Util.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/Util.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/Util.java
new file mode 100644
index 0000000..810de04
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/Util.java
@@ -0,0 +1,33 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.core.metamodel.services.metamodel;
+
+class Util {
+
+    private Util(){}
+
+    static String withSuffix(String fileName, String suffix) {
+        if(!suffix.startsWith(".")) {
+            suffix = "." + suffix;
+        }
+        if(!fileName.endsWith(suffix)) {
+            fileName += suffix;
+        }
+        return fileName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index 9fc19be..b17cebe 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -108,7 +108,7 @@ import org.apache.isis.core.metamodel.facets.object.ignore.jdo.RemoveJdoEnhancem
 import org.apache.isis.core.metamodel.facets.object.ignore.jdo.RemoveJdoPrefixedMethodsFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.immutable.immutableannot.CopyImmutableFacetOntoMembersFactory;
 import org.apache.isis.core.metamodel.facets.object.immutable.immutablemarkerifc.ImmutableFacetMarkerInterfaceFactory;
-import org.apache.isis.core.metamodel.facets.object.layoutxml.LayoutXmlFacetFactory;
+import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.mask.annotation.MaskFacetOnTypeAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.object.maxlen.annotation.MaxLengthFacetOnTypeAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.object.membergroups.annotprop.MemberGroupLayoutFacetFactory;
@@ -391,7 +391,7 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
         // must come after DomainObjectAnnotationFacetFactory & MixinFacetFactory
         addFactory(NotContributedFacetDerivedFromMixinFacetFactory.class);
 
-        addFactory(LayoutXmlFacetFactory.class);
+        addFactory(ObjectLayoutMetadataFacetFactory.class);
 
         addFactory(DomainServiceLayoutFacetFactory.class);
         addFactory(DomainObjectLayoutFacetFactory.class);

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
index 1602ff0..32c0900 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java
@@ -22,7 +22,7 @@ package org.apache.isis.viewer.wicket.ui.components.entity.combined;
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.core.metamodel.facets.object.layoutxml.ObjectLayoutMetadataFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
index cce3292..6f49a68 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanel.java
@@ -37,7 +37,7 @@ import org.apache.isis.applib.layout.v1_0.TabGroup;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
-import org.apache.isis.core.metamodel.facets.object.layoutxml.ObjectLayoutMetadataFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
index 05e3b68..4171d89 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroups/EntityTabGroupsPanelFactory.java
@@ -22,7 +22,7 @@ package org.apache.isis.viewer.wicket.ui.components.entity.tabgroups;
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.core.metamodel.facets.object.layoutxml.ObjectLayoutMetadataFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;

http://git-wip-us.apache.org/repos/asf/isis/blob/2cb78cf0/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
index 8d69476..a50bdcf 100644
--- a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
+++ b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
@@ -16,24 +16,23 @@
             </left>
             <middle span="4">
             </middle>
-            <right span="4">
-                <propertyGroup name="Metadata">
+        </tab>
+        <tab name="Metadata">
+            <left span="4">
+                <propertyGroup name="Persistence">
                     <actions>
                         <action id="downloadJdoMetadata"/>
+                        <action id="downloadLayoutXml"/>
                     </actions>
                     <property id="versionSequence"/>
                 </propertyGroup>
-            </right>
-        </tab>
-        <tab name="Other">
-            <left span="4">
             </left>
         </tab>
     </tabGroup>
     <tabGroup>
         <tab name="Similar To">
             <left span="12">
-                <collection id="similarTox"/>
+                <collection id="similarTo"/>
             </left>
         </tab>
     </tabGroup>


[2/4] isis git commit: ISIS-993: factored out LayoutMetadataService, renamed the metadata classes

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/HiddenFacetForActionLayoutXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/HiddenFacetForActionLayoutXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/HiddenFacetForActionLayoutXml.java
index c0b98da1..05ffb10 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/HiddenFacetForActionLayoutXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/HiddenFacetForActionLayoutXml.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.metamodel.facets.actions.layout;
 
 import org.apache.isis.applib.annotation.When;
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.layout.v1_0.Action;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
@@ -29,7 +29,7 @@ import org.apache.isis.core.metamodel.facets.members.hidden.HiddenFacetAbstract;
 
 public class HiddenFacetForActionLayoutXml extends HiddenFacetAbstract {
 
-    public static HiddenFacet create(final Action actionLayout, final FacetHolder holder) {
+    public static HiddenFacet create(final ActionLayoutMetadata actionLayout, final FacetHolder holder) {
         if (actionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/NamedFacetForActionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/NamedFacetForActionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/NamedFacetForActionXml.java
index c96fa2a..efa4191 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/NamedFacetForActionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/NamedFacetForActionXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.actions.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Action;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacetAbstract;
 
 public class NamedFacetForActionXml extends NamedFacetAbstract {
 
-    public static NamedFacet create(final Action actionLayout, final FacetHolder holder) {
+    public static NamedFacet create(final ActionLayoutMetadata actionLayout, final FacetHolder holder) {
         if(actionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/CssClassFacetForCollectionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/CssClassFacetForCollectionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/CssClassFacetForCollectionXml.java
index c75d5a7..c2ffd02 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/CssClassFacetForCollectionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/CssClassFacetForCollectionXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.collections.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Collection;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacetAbstract;
 
 public class CssClassFacetForCollectionXml extends CssClassFacetAbstract {
 
-    public static CssClassFacet create(Collection collectionLayout, FacetHolder holder) {
+    public static CssClassFacet create(CollectionLayoutMetadata collectionLayout, FacetHolder holder) {
         if(collectionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DefaultViewFacetForCollectionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DefaultViewFacetForCollectionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DefaultViewFacetForCollectionXml.java
index 594bca0..5802d5d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DefaultViewFacetForCollectionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DefaultViewFacetForCollectionXml.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.metamodel.facets.collections.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Collection;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet;
 import org.apache.isis.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacetAbstract;
@@ -32,7 +32,7 @@ public class DefaultViewFacetForCollectionXml extends DefaultViewFacetAbstract {
         super(value, holder);
     }
 
-    public static DefaultViewFacet create(Collection collectionLayout, FacetHolder holder) {
+    public static DefaultViewFacet create(CollectionLayoutMetadata collectionLayout, FacetHolder holder) {
         if (collectionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DescribedAsFacetForCollectionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DescribedAsFacetForCollectionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DescribedAsFacetForCollectionXml.java
index a159fc2..b9561f4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DescribedAsFacetForCollectionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/DescribedAsFacetForCollectionXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.collections.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Collection;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacetAbstract;
 
 public class DescribedAsFacetForCollectionXml extends DescribedAsFacetAbstract {
 
-    public static DescribedAsFacet create(Collection collectionLayout, FacetHolder holder) {
+    public static DescribedAsFacet create(CollectionLayoutMetadata collectionLayout, FacetHolder holder) {
         if(collectionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/HiddenFacetForCollectionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/HiddenFacetForCollectionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/HiddenFacetForCollectionXml.java
index 8a52c8e..a76ab13 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/HiddenFacetForCollectionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/HiddenFacetForCollectionXml.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.metamodel.facets.collections.layout;
 
 import org.apache.isis.applib.annotation.When;
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.layout.v1_0.Collection;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
@@ -29,7 +29,7 @@ import org.apache.isis.core.metamodel.facets.members.hidden.HiddenFacetAbstract;
 
 public class HiddenFacetForCollectionXml extends HiddenFacetAbstract {
 
-    public static HiddenFacet create(final Collection collectionLayout, final FacetHolder holder) {
+    public static HiddenFacet create(final CollectionLayoutMetadata collectionLayout, final FacetHolder holder) {
         if (collectionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/NamedFacetForCollectionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/NamedFacetForCollectionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/NamedFacetForCollectionXml.java
index 295cbc9..9509253 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/NamedFacetForCollectionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/NamedFacetForCollectionXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.collections.layout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Collection;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacetAbstract;
 
 public class NamedFacetForCollectionXml extends NamedFacetAbstract {
 
-    public static NamedFacet create(Collection collectionLayout, FacetHolder holder) {
+    public static NamedFacet create(CollectionLayoutMetadata collectionLayout, FacetHolder holder) {
         if(collectionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/PagedFacetForCollectionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/PagedFacetForCollectionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/PagedFacetForCollectionXml.java
index eee8838..6b577c0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/PagedFacetForCollectionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/PagedFacetForCollectionXml.java
@@ -19,14 +19,14 @@
 
 package org.apache.isis.core.metamodel.facets.collections.layout;
 
-import org.apache.isis.applib.layout.v1_0.Collection;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.paged.PagedFacet;
 import org.apache.isis.core.metamodel.facets.object.paged.PagedFacetAbstract;
 
 public class PagedFacetForCollectionXml extends PagedFacetAbstract {
 
-    public static PagedFacet create(Collection collectionLayout, FacetHolder holder) {
+    public static PagedFacet create(CollectionLayoutMetadata collectionLayout, FacetHolder holder) {
         if(collectionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/SortedByFacetForCollectionXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/SortedByFacetForCollectionXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/SortedByFacetForCollectionXml.java
index dbba9dd..72410ce 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/SortedByFacetForCollectionXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/layout/SortedByFacetForCollectionXml.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.metamodel.facets.collections.layout;
 
 import java.util.Comparator;
 
-import org.apache.isis.applib.layout.v1_0.Collection;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
 import org.apache.isis.core.commons.lang.ClassUtil;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.collections.sortedby.SortedByFacet;
@@ -29,7 +29,7 @@ import org.apache.isis.core.metamodel.facets.collections.sortedby.SortedByFacetA
 
 public class SortedByFacetForCollectionXml extends SortedByFacetAbstract {
 
-    public static SortedByFacet create(Collection collectionLayout, FacetHolder holder) {
+    public static SortedByFacet create(CollectionLayoutMetadata collectionLayout, FacetHolder holder) {
         if(collectionLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacet.java
deleted file mode 100644
index 608abbe..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacet.java
+++ /dev/null
@@ -1,32 +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.core.metamodel.facets.object.layoutxml;
-
-
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.applib.layout.v1_0.DomainObject;
-
-/**
- * Corresponds to providing a <code>.layout.xml</code> file for the domain object's class.
- */
-public interface LayoutXmlFacet extends Facet {
-
-    public DomainObject getLayoutMetadata();
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java
deleted file mode 100644
index eedda94..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java
+++ /dev/null
@@ -1,381 +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.core.metamodel.facets.object.layoutxml;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import org.apache.isis.applib.layout.v1_0.Action;
-import org.apache.isis.applib.layout.v1_0.ActionHolder;
-import org.apache.isis.applib.layout.v1_0.Collection;
-import org.apache.isis.applib.layout.v1_0.Column;
-import org.apache.isis.applib.layout.v1_0.DomainObject;
-import org.apache.isis.applib.layout.v1_0.Property;
-import org.apache.isis.applib.layout.v1_0.PropertyGroup;
-import org.apache.isis.applib.layout.v1_0.Tab;
-import org.apache.isis.applib.layout.v1_0.TabGroup;
-import org.apache.isis.applib.services.i18n.TranslationService;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.FacetUtil;
-import org.apache.isis.core.metamodel.facets.actions.layout.ActionPositionFacetForActionXml;
-import org.apache.isis.core.metamodel.facets.actions.layout.BookmarkPolicyFacetForActionXml;
-import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFaFacetForActionXml;
-import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFacetForActionXml;
-import org.apache.isis.core.metamodel.facets.actions.layout.DescribedAsFacetForActionXml;
-import org.apache.isis.core.metamodel.facets.actions.layout.HiddenFacetForActionLayoutXml;
-import org.apache.isis.core.metamodel.facets.actions.layout.NamedFacetForActionXml;
-import org.apache.isis.core.metamodel.facets.collections.layout.CssClassFacetForCollectionXml;
-import org.apache.isis.core.metamodel.facets.collections.layout.DefaultViewFacetForCollectionXml;
-import org.apache.isis.core.metamodel.facets.collections.layout.DescribedAsFacetForCollectionXml;
-import org.apache.isis.core.metamodel.facets.collections.layout.HiddenFacetForCollectionXml;
-import org.apache.isis.core.metamodel.facets.collections.layout.NamedFacetForCollectionXml;
-import org.apache.isis.core.metamodel.facets.collections.layout.PagedFacetForCollectionXml;
-import org.apache.isis.core.metamodel.facets.collections.layout.SortedByFacetForCollectionXml;
-import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetXml;
-import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.CssClassFacetForPropertyXml;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.DescribedAsFacetForPropertyXml;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.HiddenFacetForPropertyXml;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.LabelAtFacetForPropertyXml;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.MultiLineFacetForPropertyXml;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.NamedFacetForPropertyXml;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.RenderedAdjustedFacetForPropertyXml;
-import org.apache.isis.core.metamodel.facets.properties.propertylayout.TypicalLengthFacetForPropertyXml;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.spec.feature.Contributed;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
-import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-
-public class LayoutXmlFacetDefault
-            extends FacetAbstract
-            implements LayoutXmlFacet {
-
-    private final DomainObject metadata;
-    private final TranslationService translationService;
-
-    public static Class<? extends Facet> type() {
-        return LayoutXmlFacet.class;
-    }
-
-
-    public static LayoutXmlFacet create(
-            final FacetHolder facetHolder,
-            final DomainObject domainObject,
-            final TranslationService translationService) {
-        if(domainObject == null) {
-            return null;
-        }
-        return new LayoutXmlFacetDefault(facetHolder, domainObject, translationService);
-    }
-
-    private LayoutXmlFacetDefault(
-            final FacetHolder facetHolder,
-            final DomainObject metadata,
-            final TranslationService translationService) {
-        super(LayoutXmlFacetDefault.type(), facetHolder, Derivation.NOT_DERIVED);
-        this.metadata = metadata;
-        this.translationService = translationService;
-    }
-
-
-    private boolean derived;
-
-    public DomainObject getLayoutMetadata() {
-        //return derived ? metadata : deriveAndOverwrite(metadata);
-        return deriveAndOverwrite(metadata);
-    }
-
-    private  DomainObject deriveAndOverwrite(final DomainObject metadata) {
-        synchronized (metadata) {
-            doDeriveAndOverwrite(metadata);
-            derived = true;
-        }
-        return metadata;
-    }
-
-    private void doDeriveAndOverwrite(final DomainObject metadata) {
-
-        final ObjectSpecification objectSpec = (ObjectSpecification) getFacetHolder();
-        final Map<String, OneToOneAssociation> oneToOneAssociationById =
-                ObjectMember.Util.mapById(getOneToOneAssociations(objectSpec));
-        final Map<String, OneToManyAssociation> oneToManyAssociationById =
-                ObjectMember.Util.mapById(getOneToManyAssociations(objectSpec));
-        final Map<String, ObjectAction> objectActionById =
-                ObjectMember.Util.mapById(objectSpec.getObjectActions(Contributed.INCLUDED));
-
-        derive(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById);
-        overwrite(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById);
-    }
-
-    /**
-     * Ensures that all object members (properties, collections and actions) are in the metadata.
-     *
-     * <p>
-     *     If they are missing then they will be added to default tabs (created on the fly if need be).
-     * </p>
-     */
-    private static void derive(
-            final DomainObject metadata,
-            final Map<String, OneToOneAssociation> oneToOneAssociationById,
-            final Map<String, OneToManyAssociation> oneToManyAssociationById,
-            final Map<String, ObjectAction> objectActionById) {
-        final List<String> propertyIds = Lists.newArrayList();
-        final List<String> collectionIds = Lists.newArrayList();
-        final List<String> actionIds = Lists.newArrayList();
-        final AtomicReference<PropertyGroup> defaultPropertyGroupRef = new AtomicReference<>();
-        final AtomicReference<Column> firstColumnRef = new AtomicReference<>();
-        final AtomicReference<TabGroup> lastTabGroupRef = new AtomicReference<>();
-
-        // catalog which property, collection and action Ids appear (anywhere) in the metadata
-        metadata.visit(new DomainObject.VisitorAdapter() {
-            @Override
-            public void visit(final Property property) {
-                propertyIds.add(property.getId());
-            }
-            @Override
-            public void visit(final Collection collection) {
-                collectionIds.add(collection.getId());
-            }
-            @Override
-            public void visit(final Action action) {
-                actionIds.add(action.getId());
-            }
-        });
-
-        // capture the first column, and also
-        // capture the first property group (if any) with the default name ('General')
-        metadata.visit(new DomainObject.VisitorAdapter() {
-            @Override
-            public void visit(final Column column) {
-                firstColumnRef.compareAndSet(null, column);
-            }
-            @Override
-            public void visit(final PropertyGroup propertyGroup) {
-                if(MemberGroupLayoutFacet.DEFAULT_GROUP.equals(propertyGroup.getName())) {
-                    defaultPropertyGroupRef.compareAndSet(null, propertyGroup);
-                }
-            }
-            @Override
-            public void visit(final TabGroup tabGroup) {
-                lastTabGroupRef.set(tabGroup);
-            }
-        });
-
-        // any missing properties will be added to the (first) 'General' property group found
-        // if there is no default ('General') property group
-        // then one will be added to the first Column of the first Tab.
-        final List<String> missingPropertyIds = Lists.newArrayList(oneToOneAssociationById.keySet());
-        missingPropertyIds.removeAll(propertyIds);
-
-        if(!missingPropertyIds.isEmpty()) {
-            // ensure that there is a property group to use
-            boolean wasSet = defaultPropertyGroupRef.compareAndSet(null, new PropertyGroup(MemberGroupLayoutFacet.DEFAULT_GROUP));
-            final PropertyGroup defaultPropertyGroup = defaultPropertyGroupRef.get();
-            if(wasSet) {
-                firstColumnRef.get().getPropertyGroups().add(defaultPropertyGroup);
-            }
-            Iterables.removeAll(propertyIds, oneToOneAssociationById.keySet());
-            for (final String propertyId : missingPropertyIds) {
-                defaultPropertyGroup.getProperties().add(new Property(propertyId));
-            }
-        }
-
-        // any missing collections will be added as tabs to the last TabGroup.
-        // If there is only a single tab group then a new TabGroup will be added first
-        final List<String> missingCollectionIds = Lists.newArrayList(oneToManyAssociationById.keySet());
-        missingCollectionIds.removeAll(collectionIds);
-
-        if(!missingCollectionIds.isEmpty()) {
-            while(metadata.getTabGroups().size() < 2) {
-                final TabGroup tabGroup = new TabGroup();
-                metadata.getTabGroups().add(tabGroup);
-                lastTabGroupRef.set(tabGroup);
-            }
-            final TabGroup lastTabGroup = lastTabGroupRef.get();
-            for (final String collectionId : missingCollectionIds) {
-                final Tab tab = new Tab();
-                lastTabGroup.getTabs().add(tab);
-                Column left = new Column(12);
-                tab.setLeft(left);
-                left.getCollections().add(new Collection(collectionId));
-            }
-        }
-
-        // any missing actions will be added as domain object actions (in the header)
-        final List<String> missingActionIds = Lists.newArrayList(objectActionById.keySet());
-        missingActionIds.removeAll(actionIds);
-
-        if(!missingActionIds.isEmpty()) {
-            for (String actionId : missingActionIds) {
-                metadata.getActions().add(new Action(actionId));
-            }
-        }
-    }
-
-    private void overwrite(
-            final DomainObject metadata,
-            final Map<String, OneToOneAssociation> oneToOneAssociationById,
-            final Map<String, OneToManyAssociation> oneToManyAssociationById,
-            final Map<String, ObjectAction> objectActionById) {
-
-        metadata.visit(new DomainObject.VisitorAdapter() {
-            private final Map<String, int[]> propertySequenceByGroup = Maps.newHashMap();
-            private int actionDomainObjectSequence = 1;
-            private int actionPropertyGroupSequence = 1;
-            private int actionPropertySequence = 1;
-            private int actionCollectionSequence = 1;
-
-            @Override
-            public void visit(final Action action) {
-                final ActionHolder actionHolder = action.getOwner();
-                final ObjectAction objectAction = objectActionById.get(action.getId());
-                final String memberOrderName;
-                final int memberOrderSequence;
-                if(actionHolder instanceof PropertyGroup) {
-                    final PropertyGroup propertyGroup = (PropertyGroup) actionHolder;
-                    final List<Property> properties = propertyGroup.getProperties();
-                    final Property property = properties.get(0); // any will do
-                    memberOrderName = property.getId();
-                    memberOrderSequence = actionPropertyGroupSequence++;
-                } else if(actionHolder instanceof Property) {
-                    final Property property = (Property) actionHolder;
-                    memberOrderName = property.getId();
-                    memberOrderSequence = actionPropertySequence++;
-                } else if(actionHolder instanceof Collection) {
-                    final Collection collection = (Collection) actionHolder;
-                    memberOrderName = collection.getId();
-                    memberOrderSequence = actionCollectionSequence++;
-                } else {
-                    // DomainObject
-                    memberOrderName = null;
-                    memberOrderSequence = actionDomainObjectSequence++;
-                }
-                FacetUtil.addFacet(
-                    new MemberOrderFacetXml(memberOrderName, ""+memberOrderSequence, translationService, objectAction));
-
-
-                if(actionHolder instanceof PropertyGroup) {
-                    if(action.getPosition() == null ||
-                       action.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.BELOW ||
-                       action.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.RIGHT) {
-                       action.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.PANEL);
-                    }
-                } else if(actionHolder instanceof Property) {
-                    if(action.getPosition() == null ||
-                       action.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL_DROPDOWN ||
-                       action.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL) {
-                       action.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.BELOW);
-                    }
-                } else {
-                    // doesn't do anything for DomainObject or Collection
-                    action.setPosition(null);
-                }
-
-                FacetUtil.addFacet(ActionPositionFacetForActionXml.create(action, objectAction));
-                FacetUtil.addFacet(BookmarkPolicyFacetForActionXml.create(action, objectAction));
-                FacetUtil.addFacet(CssClassFacetForActionXml.create(action, objectAction));
-                FacetUtil.addFacet(CssClassFaFacetForActionXml.create(action, objectAction));
-                FacetUtil.addFacet(DescribedAsFacetForActionXml.create(action, objectAction));
-                FacetUtil.addFacet(HiddenFacetForActionLayoutXml.create(action, objectAction));
-                FacetUtil.addFacet(NamedFacetForActionXml.create(action, objectAction));
-            }
-
-            @Override
-            public void visit(final Property property) {
-
-                final OneToOneAssociation oneToOneAssociation = oneToOneAssociationById.get(property.getId());
-                FacetUtil.addFacet(CssClassFacetForPropertyXml.create(property, oneToOneAssociation));
-                FacetUtil.addFacet(DescribedAsFacetForPropertyXml.create(property, oneToOneAssociation));
-                FacetUtil.addFacet(HiddenFacetForPropertyXml.create(property, oneToOneAssociation));
-                FacetUtil.addFacet(LabelAtFacetForPropertyXml.create(property, oneToOneAssociation));
-                FacetUtil.addFacet(MultiLineFacetForPropertyXml.create(property, oneToOneAssociation));
-                FacetUtil.addFacet(NamedFacetForPropertyXml.create(property, oneToOneAssociation));
-                FacetUtil.addFacet(RenderedAdjustedFacetForPropertyXml.create(property, oneToOneAssociation));
-                FacetUtil.addFacet(TypicalLengthFacetForPropertyXml.create(property, oneToOneAssociation));
-
-                // @MemberOrder#name based on owning property group, @MemberOrder#sequence monotonically increasing
-                final PropertyGroup propertyGroup = property.getOwner();
-                final String groupName = propertyGroup.getName();
-                final String sequence = nextInSequenceFor(groupName);
-                FacetUtil.addFacet(
-                        new MemberOrderFacetXml(groupName, sequence, translationService, oneToOneAssociation));
-            }
-
-            @Override
-            public void visit(final Collection collection) {
-                final OneToManyAssociation oneToManyAssociation = oneToManyAssociationById.get(collection.getId());
-
-                FacetUtil.addFacet(CssClassFacetForCollectionXml.create(collection, oneToManyAssociation));
-                FacetUtil.addFacet(DefaultViewFacetForCollectionXml.create(collection, oneToManyAssociation));
-                FacetUtil.addFacet(DescribedAsFacetForCollectionXml.create(collection, oneToManyAssociation));
-                FacetUtil.addFacet(HiddenFacetForCollectionXml.create(collection, oneToManyAssociation));
-                FacetUtil.addFacet(NamedFacetForCollectionXml.create(collection, oneToManyAssociation));
-                FacetUtil.addFacet(PagedFacetForCollectionXml.create(collection, oneToManyAssociation));
-                FacetUtil.addFacet(SortedByFacetForCollectionXml.create(collection, oneToManyAssociation));
-
-                // @MemberOrder#name based on the collection's id (so that each has a single "member group")
-                final String groupName = collection.getId();
-                final String sequence = nextInSequenceFor(groupName);
-                FacetUtil.addFacet(
-                        new MemberOrderFacetXml(groupName, sequence, translationService, oneToManyAssociation));
-
-                // if there is only a single column and no other contents, then copy the collection Id onto the tab'
-                final Column column = collection.getOwner();
-                final Tab tab = column.getOwner();
-                if(tab.getContents().size() == 1) {
-                    tab.setName(collection.getId());
-                }
-            }
-
-            private String nextInSequenceFor(final String propertyGroupName) {
-                synchronized (propertySequenceByGroup) {
-                    int[] holder = propertySequenceByGroup.get(propertyGroupName);
-                    if(holder == null) {
-                        holder = new int[]{0};
-                        propertySequenceByGroup.put(propertyGroupName, holder);
-                    }
-                    holder[0]++;
-                    return ""+holder[0];
-                }
-            }
-        });
-
-    }
-
-    private static List<OneToOneAssociation> getOneToOneAssociations(final ObjectSpecification objectSpec) {
-        List associations = objectSpec
-                .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.PROPERTIES);
-        return associations;
-    }
-    private static List<OneToManyAssociation> getOneToManyAssociations(final ObjectSpecification objectSpec) {
-        List associations = objectSpec
-                .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.COLLECTIONS);
-        return associations;
-    }
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
index 606f34a..f898f61 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
@@ -16,22 +16,15 @@
  * under the License. */
 package org.apache.isis.core.metamodel.facets.object.layoutxml;
 
-import java.io.IOException;
-import java.util.Set;
-
-import com.google.common.collect.Sets;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.isis.applib.services.i18n.TranslationService;
-import org.apache.isis.applib.services.jaxb.JaxbService;
-import org.apache.isis.core.commons.lang.ClassExtensions;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.applib.layout.v1_0.DomainObject;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjectorAware;
 
@@ -48,46 +41,14 @@ public class LayoutXmlFacetFactory extends FacetFactoryAbstract implements Servi
         final Class<?> cls = processClassContext.getCls();
         final FacetHolder facetHolder = processClassContext.getFacetHolder();
 
-        final TranslationService translationService = servicesInjector.lookupService(TranslationService.class);
-        FacetUtil.addFacet(LayoutXmlFacetDefault.create(facetHolder, readMetadata(cls), translationService));
+        final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class);
+        FacetUtil.addFacet(
+                ObjectLayoutMetadataFacetDefault.create(facetHolder, readMetadata(cls), objectLayoutMetadataService));
     }
 
-    private final Set<Class<?>> blacklisted = Sets.newConcurrentHashSet();
-
-    private DomainObject readMetadata(final Class<?> domainClass) {
-
-        if(blacklisted.contains(domainClass)) {
-            return null;
-        }
-        final String xml;
-
-        final String resourceName = domainClass.getSimpleName() + ".layout.xml";
-        try {
-            xml = ClassExtensions.resourceContentOf(domainClass, resourceName);
-        } catch (IOException | IllegalArgumentException ex) {
-
-            blacklisted.add(domainClass);
-            final String message = String .format(
-                    "Failed to locate file %s (relative to %s.class); ex: %s)",
-                    resourceName, domainClass.getName(), ex.getMessage());
-
-            LOG.debug(message);
-            return null;
-        }
-
-        try {
-            final JaxbService jaxbService = servicesInjector.lookupService(JaxbService.class);
-            final DomainObject metadata = jaxbService.fromXml(DomainObject.class, xml);
-            return metadata;
-        } catch(Exception ex) {
-
-            // note that we don't blacklist if the file exists but couldn't be parsed;
-            // the developer might fix so we will want to retry.
-            final String message = "Failed to parse " + resourceName + " file (" + ex.getMessage() + ")";
-            LOG.warn(message);
-
-            return null;
-        }
+    private ObjectLayoutMetadata readMetadata(final Class<?> domainClass) {
+        final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class);
+        return objectLayoutMetadataService.fromXml(domainClass);
     }
 
     private ServicesInjector servicesInjector;

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java
new file mode 100644
index 0000000..7285fc0
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacet.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.facets.object.layoutxml;
+
+
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+
+/**
+ * Corresponds to providing a <code>.layout.xml</code> file for the domain object's class.
+ */
+public interface ObjectLayoutMetadataFacet extends Facet {
+
+    /**
+     * Will have been {@link org.apache.isis.applib.services.layout.ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class) normalized}.
+     */
+    ObjectLayoutMetadata getMetadata();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java
new file mode 100644
index 0000000..05d3cc8
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/ObjectLayoutMetadataFacetDefault.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.facets.object.layoutxml;
+
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+public class ObjectLayoutMetadataFacetDefault
+            extends FacetAbstract
+            implements ObjectLayoutMetadataFacet {
+
+    private final ObjectLayoutMetadata metadata;
+    private final ObjectLayoutMetadataService objectLayoutMetadataService;
+
+    public static Class<? extends Facet> type() {
+        return ObjectLayoutMetadataFacet.class;
+    }
+
+
+    public static ObjectLayoutMetadataFacet create(
+            final FacetHolder facetHolder,
+            final ObjectLayoutMetadata objectLayoutMetadata,
+            final ObjectLayoutMetadataService objectLayoutMetadataService) {
+        if(objectLayoutMetadata == null) {
+            return null;
+        }
+        return new ObjectLayoutMetadataFacetDefault(facetHolder, objectLayoutMetadata, objectLayoutMetadataService);
+    }
+
+    private ObjectLayoutMetadataFacetDefault(
+            final FacetHolder facetHolder,
+            final ObjectLayoutMetadata metadata,
+            final ObjectLayoutMetadataService objectLayoutMetadataService) {
+        super(ObjectLayoutMetadataFacetDefault.type(), facetHolder, Derivation.NOT_DERIVED);
+        this.metadata = metadata;
+        this.objectLayoutMetadataService = objectLayoutMetadataService;
+    }
+
+
+    public ObjectLayoutMetadata getMetadata() {
+        final ObjectSpecification objectSpecification = (ObjectSpecification) getFacetHolder();
+        return objectLayoutMetadataService.normalize(metadata, objectSpecification.getCorrespondingClass());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/CssClassFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/CssClassFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/CssClassFacetForPropertyXml.java
index 065e80c..e16cad5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/CssClassFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/CssClassFacetForPropertyXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacetAbstract;
 
 public class CssClassFacetForPropertyXml extends CssClassFacetAbstract {
 
-    public static CssClassFacet create(Property propertyLayout, FacetHolder holder) {
+    public static CssClassFacet create(PropertyLayoutMetadata propertyLayout, FacetHolder holder) {
         if(propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/DescribedAsFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/DescribedAsFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/DescribedAsFacetForPropertyXml.java
index 2c9f6f6..e2c6bb6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/DescribedAsFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/DescribedAsFacetForPropertyXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacetAbstract;
 
 public class DescribedAsFacetForPropertyXml extends DescribedAsFacetAbstract {
 
-    public static DescribedAsFacet create(Property propertyLayout, FacetHolder holder) {
+    public static DescribedAsFacet create(PropertyLayoutMetadata propertyLayout, FacetHolder holder) {
         if(propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/HiddenFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/HiddenFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/HiddenFacetForPropertyXml.java
index 4ee7f1d..83d15ab 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/HiddenFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/HiddenFacetForPropertyXml.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
 import org.apache.isis.applib.annotation.When;
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
@@ -29,7 +29,7 @@ import org.apache.isis.core.metamodel.facets.members.hidden.HiddenFacetAbstract;
 
 public class HiddenFacetForPropertyXml extends HiddenFacetAbstract {
 
-    public static HiddenFacet create(final Property propertyLayout, final FacetHolder holder) {
+    public static HiddenFacet create(final PropertyLayoutMetadata propertyLayout, final FacetHolder holder) {
         if (propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/LabelAtFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/LabelAtFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/LabelAtFacetForPropertyXml.java
index ba512a9..fc55c5d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/LabelAtFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/LabelAtFacetForPropertyXml.java
@@ -20,14 +20,14 @@
 package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
 import org.apache.isis.applib.annotation.LabelPosition;
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacetAbstract;
 
 public class LabelAtFacetForPropertyXml extends LabelAtFacetAbstract {
 
-    public static LabelAtFacet create(final Property propertyLayout, FacetHolder holder) {
+    public static LabelAtFacet create(final PropertyLayoutMetadata propertyLayout, FacetHolder holder) {
         if (propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/MultiLineFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/MultiLineFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/MultiLineFacetForPropertyXml.java
index 9a48271..599ceba 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/MultiLineFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/MultiLineFacetForPropertyXml.java
@@ -19,14 +19,14 @@
 
 package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.objectvalue.multiline.MultiLineFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.multiline.MultiLineFacetAbstract;
 
 public class MultiLineFacetForPropertyXml extends MultiLineFacetAbstract {
 
-    public static MultiLineFacet create(Property propertyLayout, FacetHolder holder) {
+    public static MultiLineFacet create(PropertyLayoutMetadata propertyLayout, FacetHolder holder) {
         if(propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/NamedFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/NamedFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/NamedFacetForPropertyXml.java
index 392a152..8f2ea3a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/NamedFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/NamedFacetForPropertyXml.java
@@ -21,14 +21,14 @@ package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
 import com.google.common.base.Strings;
 
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacetAbstract;
 
 public class NamedFacetForPropertyXml extends NamedFacetAbstract {
 
-    public static NamedFacet create(Property propertyLayout, FacetHolder holder) {
+    public static NamedFacet create(PropertyLayoutMetadata propertyLayout, FacetHolder holder) {
         if(propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/RenderedAdjustedFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/RenderedAdjustedFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/RenderedAdjustedFacetForPropertyXml.java
index 63a3e4a..1947070 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/RenderedAdjustedFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/RenderedAdjustedFacetForPropertyXml.java
@@ -19,14 +19,14 @@
 
 package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.objectvalue.renderedadjusted.RenderedAdjustedFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.renderedadjusted.RenderedAdjustedFacetAbstract;
 
 public class RenderedAdjustedFacetForPropertyXml extends RenderedAdjustedFacetAbstract {
 
-    public static RenderedAdjustedFacet create(final Property propertyLayout, FacetHolder holder) {
+    public static RenderedAdjustedFacet create(final PropertyLayoutMetadata propertyLayout, FacetHolder holder) {
         if(propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/TypicalLengthFacetForPropertyXml.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/TypicalLengthFacetForPropertyXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/TypicalLengthFacetForPropertyXml.java
index 1a193e5..dfbfb79 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/TypicalLengthFacetForPropertyXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/propertylayout/TypicalLengthFacetForPropertyXml.java
@@ -19,14 +19,14 @@
 
 package org.apache.isis.core.metamodel.facets.properties.propertylayout;
 
-import org.apache.isis.applib.layout.v1_0.Property;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacetAbstract;
 
 public class TypicalLengthFacetForPropertyXml extends TypicalLengthFacetAbstract {
 
-    public static TypicalLengthFacet create(Property propertyLayout, FacetHolder holder) {
+    public static TypicalLengthFacet create(PropertyLayoutMetadata propertyLayout, FacetHolder holder) {
         if(propertyLayout == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java
new file mode 100644
index 0000000..c9daf91
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java
@@ -0,0 +1,468 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.core.metamodel.services.layout;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.inject.Inject;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.io.Resources;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.NatureOfService;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.layout.v1_0.ActionHolder;
+import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.Column;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.PropertyGroup;
+import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.Tab;
+import org.apache.isis.applib.layout.v1_0.TabGroup;
+import org.apache.isis.applib.services.i18n.TranslationService;
+import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
+import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
+import org.apache.isis.core.metamodel.deployment.DeploymentCategoryAware;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facets.actions.layout.ActionPositionFacetForActionXml;
+import org.apache.isis.core.metamodel.facets.actions.layout.BookmarkPolicyFacetForActionXml;
+import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFaFacetForActionXml;
+import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFacetForActionXml;
+import org.apache.isis.core.metamodel.facets.actions.layout.DescribedAsFacetForActionXml;
+import org.apache.isis.core.metamodel.facets.actions.layout.HiddenFacetForActionLayoutXml;
+import org.apache.isis.core.metamodel.facets.actions.layout.NamedFacetForActionXml;
+import org.apache.isis.core.metamodel.facets.collections.layout.CssClassFacetForCollectionXml;
+import org.apache.isis.core.metamodel.facets.collections.layout.DefaultViewFacetForCollectionXml;
+import org.apache.isis.core.metamodel.facets.collections.layout.DescribedAsFacetForCollectionXml;
+import org.apache.isis.core.metamodel.facets.collections.layout.HiddenFacetForCollectionXml;
+import org.apache.isis.core.metamodel.facets.collections.layout.NamedFacetForCollectionXml;
+import org.apache.isis.core.metamodel.facets.collections.layout.PagedFacetForCollectionXml;
+import org.apache.isis.core.metamodel.facets.collections.layout.SortedByFacetForCollectionXml;
+import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetXml;
+import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.CssClassFacetForPropertyXml;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.DescribedAsFacetForPropertyXml;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.HiddenFacetForPropertyXml;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.LabelAtFacetForPropertyXml;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.MultiLineFacetForPropertyXml;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.NamedFacetForPropertyXml;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.RenderedAdjustedFacetForPropertyXml;
+import org.apache.isis.core.metamodel.facets.properties.propertylayout.TypicalLengthFacetForPropertyXml;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderAware;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+
+@DomainService(nature = NatureOfService.DOMAIN)
+public class ObjectLayoutMetadataServiceDefault
+        implements ObjectLayoutMetadataService, DeploymentCategoryAware , SpecificationLoaderAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ObjectLayoutMetadataServiceDefault.class);
+
+    private final Set<Class<?>> blacklisted = Sets.newConcurrentHashSet();
+
+    @Programmatic
+    public ObjectLayoutMetadata fromXml(Class<?> domainClass) {
+
+        if(blacklisted.contains(domainClass)) {
+            return null;
+        }
+
+        final String xml;
+        final String resourceName = domainClass.getSimpleName() + ".layout.xml";
+        try {
+            xml = resourceContentOf(domainClass, resourceName);
+        } catch (IOException | IllegalArgumentException ex) {
+
+            blacklisted.add(domainClass);
+            final String message = String .format(
+                    "Failed to locate file %s (relative to %s.class); ex: %s)",
+                    resourceName, domainClass.getName(), ex.getMessage());
+
+            LOG.debug(message);
+            return null;
+        }
+
+        try {
+            final ObjectLayoutMetadata metadata = jaxbService.fromXml(ObjectLayoutMetadata.class, xml);
+            return metadata;
+        } catch(Exception ex) {
+
+            // note that we don't blacklist if the file exists but couldn't be parsed;
+            // the developer might fix so we will want to retry.
+            final String message = "Failed to parse " + resourceName + " file (" + ex.getMessage() + ")";
+            LOG.warn(message);
+
+            return null;
+        }
+    }
+
+    private static String resourceContentOf(final Class<?> cls, final String resourceName) throws IOException {
+        final URL url = Resources.getResource(cls, resourceName);
+        return Resources.toString(url, Charset.defaultCharset());
+    }
+
+
+    @Override
+    public ObjectLayoutMetadata normalize(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass) {
+        // caching (of whether validated) is enabled only in production.
+        return objectLayoutMetadata.isNormalized() && deploymentCategory.isProduction()
+                ? objectLayoutMetadata
+                : deriveAndOverwrite(objectLayoutMetadata, domainClass);
+    }
+
+    private ObjectLayoutMetadata deriveAndOverwrite(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass) {
+        synchronized (objectLayoutMetadata) {
+            final ObjectSpecification objectSpec = specificationLookup.loadSpecification(domainClass);
+            doDeriveAndOverwrite(objectLayoutMetadata, objectSpec);
+            objectLayoutMetadata.setNormalized(true);
+        }
+        return objectLayoutMetadata;
+    }
+
+    private void doDeriveAndOverwrite(final ObjectLayoutMetadata metadata, final ObjectSpecification objectSpec) {
+
+        final Map<String, OneToOneAssociation> oneToOneAssociationById =
+                ObjectMember.Util.mapById(getOneToOneAssociations(objectSpec));
+        final Map<String, OneToManyAssociation> oneToManyAssociationById =
+                ObjectMember.Util.mapById(getOneToManyAssociations(objectSpec));
+        final Map<String, ObjectAction> objectActionById =
+                ObjectMember.Util.mapById(objectSpec.getObjectActions(Contributed.INCLUDED));
+
+        derive(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById);
+        overwrite(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById);
+    }
+
+    /**
+     * Ensures that all object members (properties, collections and actions) are in the metadata.
+     *
+     * <p>
+     *     If they are missing then they will be added to default tabs (created on the fly if need be).
+     * </p>
+     */
+    private static void derive(
+            final ObjectLayoutMetadata metadata,
+            final Map<String, OneToOneAssociation> oneToOneAssociationById,
+            final Map<String, OneToManyAssociation> oneToManyAssociationById,
+            final Map<String, ObjectAction> objectActionById) {
+
+        final LinkedHashMap<String, PropertyLayoutMetadata> propertyIds = metadata.getAllPropertiesById();
+        final LinkedHashMap<String, CollectionLayoutMetadata> collectionIds = metadata.getAllCollectionsById();
+        final LinkedHashMap<String, ActionLayoutMetadata> actionIds = metadata.getAllActionsById();
+
+        final AtomicReference<PropertyGroup> defaultPropertyGroupRef = new AtomicReference<>();
+        final AtomicReference<Column> firstColumnRef = new AtomicReference<>();
+        final AtomicReference<TabGroup> lastTabGroupRef = new AtomicReference<>();
+
+        // capture the first column, and also
+        // capture the first property group (if any) with the default name ('General')
+        metadata.visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            @Override
+            public void visit(final Column column) {
+                firstColumnRef.compareAndSet(null, column);
+            }
+            @Override
+            public void visit(final PropertyGroup propertyGroup) {
+                if(MemberGroupLayoutFacet.DEFAULT_GROUP.equals(propertyGroup.getName())) {
+                    defaultPropertyGroupRef.compareAndSet(null, propertyGroup);
+                }
+            }
+            @Override
+            public void visit(final TabGroup tabGroup) {
+                lastTabGroupRef.set(tabGroup);
+            }
+        });
+
+        // any missing properties will be added to the (first) 'General' property group found
+        // if there is no default ('General') property group
+        // then one will be added to the first Column of the first Tab.
+        final List<String>[] propertyIdTuple = surplusAndMissing(propertyIds.keySet(), oneToOneAssociationById.keySet());
+        final List<String> surplusPropertyIds = propertyIdTuple[0];
+        final List<String> missingPropertyIds = propertyIdTuple[1];
+
+        for (String surplusPropertyId : surplusPropertyIds) {
+            propertyIds.get(surplusPropertyId).setMetadataError("No such property");
+        }
+
+        if(!missingPropertyIds.isEmpty()) {
+            // ensure that there is a property group to use
+            boolean wasSet = defaultPropertyGroupRef.compareAndSet(null, new PropertyGroup(MemberGroupLayoutFacet.DEFAULT_GROUP));
+            final PropertyGroup defaultPropertyGroup = defaultPropertyGroupRef.get();
+            if(wasSet) {
+                firstColumnRef.get().getPropertyGroups().add(defaultPropertyGroup);
+            }
+            for (final String propertyId : missingPropertyIds) {
+                defaultPropertyGroup.getProperties().add(new PropertyLayoutMetadata(propertyId));
+            }
+        }
+
+
+        // any missing collections will be added as tabs to the last TabGroup.
+        // If there is only a single tab group then a new TabGroup will be added first
+        final List<String>[] collectionIdTuple = surplusAndMissing(collectionIds.keySet(), oneToManyAssociationById.keySet());
+        final List<String> surplusCollectionIds = collectionIdTuple[0];
+        final List<String> missingCollectionIds = collectionIdTuple[1];
+
+        for (String surplusCollectionId : surplusCollectionIds) {
+            collectionIds.get(surplusCollectionId).setMetadataError("No such collection");
+        }
+
+        if(!missingCollectionIds.isEmpty()) {
+            while(metadata.getTabGroups().size() < 2) {
+                final TabGroup tabGroup = new TabGroup();
+                metadata.getTabGroups().add(tabGroup);
+                lastTabGroupRef.set(tabGroup);
+            }
+            final TabGroup lastTabGroup = lastTabGroupRef.get();
+            for (final String collectionId : missingCollectionIds) {
+                final Tab tab = new Tab();
+                lastTabGroup.getTabs().add(tab);
+                Column left = new Column(12);
+                tab.setLeft(left);
+                left.getCollections().add(new CollectionLayoutMetadata(collectionId));
+            }
+        }
+
+        // any missing actions will be added as domain object actions (in the header)
+        final List<String>[] actionIdTuple = surplusAndMissing(actionIds.keySet(), objectActionById.keySet());
+        final List<String> surplusActionIds = actionIdTuple[0];
+        final List<String> missingActionIds = actionIdTuple[1];
+
+        for (String surplusActionId : surplusActionIds) {
+            actionIds.get(surplusActionId).setMetadataError("No such action");
+        }
+
+        if(!missingActionIds.isEmpty()) {
+            for (String actionId : missingActionIds) {
+                metadata.getActions().add(new ActionLayoutMetadata(actionId));
+            }
+        }
+    }
+
+    /**
+     * Returns a 2-element array (a tuple) of [first-second, second-first]
+     */
+    static <T> List<T>[] surplusAndMissing(final java.util.Collection<T> first, final java.util.Collection<T> second){
+        final List<T> firstNotSecond = Lists.newArrayList(first);
+        firstNotSecond.removeAll(second);
+        final List<T> secondNotFirst = Lists.newArrayList(second);
+        secondNotFirst.removeAll(first);
+        return new List[]{ firstNotSecond, secondNotFirst };
+    }
+
+    private void overwrite(
+            final ObjectLayoutMetadata metadata,
+            final Map<String, OneToOneAssociation> oneToOneAssociationById,
+            final Map<String, OneToManyAssociation> oneToManyAssociationById,
+            final Map<String, ObjectAction> objectActionById) {
+
+        metadata.visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            private final Map<String, int[]> propertySequenceByGroup = Maps.newHashMap();
+            private int actionDomainObjectSequence = 1;
+            private int actionPropertyGroupSequence = 1;
+            private int actionPropertySequence = 1;
+            private int actionCollectionSequence = 1;
+
+            @Override
+            public void visit(final ActionLayoutMetadata actionLayoutMetadata) {
+                final ActionHolder actionHolder = actionLayoutMetadata.getOwner();
+                final ObjectAction objectAction = objectActionById.get(actionLayoutMetadata.getId());
+                if(objectAction == null) {
+                    return;
+                }
+
+                final String memberOrderName;
+                final int memberOrderSequence;
+                if(actionHolder instanceof PropertyGroup) {
+                    final PropertyGroup propertyGroup = (PropertyGroup) actionHolder;
+                    final List<PropertyLayoutMetadata> properties = propertyGroup.getProperties();
+                    final PropertyLayoutMetadata propertyLayoutMetadata = properties.get(0); // any will do
+                    memberOrderName = propertyLayoutMetadata.getId();
+                    memberOrderSequence = actionPropertyGroupSequence++;
+                } else if(actionHolder instanceof PropertyLayoutMetadata) {
+                    final PropertyLayoutMetadata propertyLayoutMetadata = (PropertyLayoutMetadata) actionHolder;
+                    memberOrderName = propertyLayoutMetadata.getId();
+                    memberOrderSequence = actionPropertySequence++;
+                } else if(actionHolder instanceof CollectionLayoutMetadata) {
+                    final CollectionLayoutMetadata collectionLayoutMetadata = (CollectionLayoutMetadata) actionHolder;
+                    memberOrderName = collectionLayoutMetadata.getId();
+                    memberOrderSequence = actionCollectionSequence++;
+                } else {
+                    // DomainObject
+                    memberOrderName = null;
+                    memberOrderSequence = actionDomainObjectSequence++;
+                }
+                FacetUtil.addFacet(
+                        new MemberOrderFacetXml(memberOrderName, ""+memberOrderSequence, translationService, objectAction));
+
+
+                if(actionHolder instanceof PropertyGroup) {
+                    if(actionLayoutMetadata.getPosition() == null ||
+                            actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.BELOW ||
+                            actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.RIGHT) {
+                        actionLayoutMetadata.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.PANEL);
+                    }
+                } else if(actionHolder instanceof PropertyLayoutMetadata) {
+                    if(actionLayoutMetadata.getPosition() == null ||
+                            actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL_DROPDOWN ||
+                            actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL) {
+                        actionLayoutMetadata.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.BELOW);
+                    }
+                } else {
+                    // doesn't do anything for DomainObject or Collection
+                    actionLayoutMetadata.setPosition(null);
+                }
+
+                FacetUtil.addFacet(ActionPositionFacetForActionXml.create(actionLayoutMetadata, objectAction));
+                FacetUtil.addFacet(BookmarkPolicyFacetForActionXml.create(actionLayoutMetadata, objectAction));
+                FacetUtil.addFacet(CssClassFacetForActionXml.create(actionLayoutMetadata, objectAction));
+                FacetUtil.addFacet(CssClassFaFacetForActionXml.create(actionLayoutMetadata, objectAction));
+                FacetUtil.addFacet(DescribedAsFacetForActionXml.create(actionLayoutMetadata, objectAction));
+                FacetUtil.addFacet(HiddenFacetForActionLayoutXml.create(actionLayoutMetadata, objectAction));
+                FacetUtil.addFacet(NamedFacetForActionXml.create(actionLayoutMetadata, objectAction));
+            }
+
+            @Override
+            public void visit(final PropertyLayoutMetadata propertyLayoutMetadata) {
+                final OneToOneAssociation oneToOneAssociation = oneToOneAssociationById.get(propertyLayoutMetadata.getId());
+                if(oneToOneAssociation == null) {
+                    return;
+                }
+
+                FacetUtil.addFacet(CssClassFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+                FacetUtil.addFacet(DescribedAsFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+                FacetUtil.addFacet(HiddenFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+                FacetUtil.addFacet(LabelAtFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+                FacetUtil.addFacet(MultiLineFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+                FacetUtil.addFacet(NamedFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+                FacetUtil.addFacet(RenderedAdjustedFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+                FacetUtil.addFacet(TypicalLengthFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation));
+
+                // @MemberOrder#name based on owning property group, @MemberOrder#sequence monotonically increasing
+                final PropertyGroup propertyGroup = propertyLayoutMetadata.getOwner();
+                final String groupName = propertyGroup.getName();
+                final String sequence = nextInSequenceFor(groupName);
+                FacetUtil.addFacet(
+                        new MemberOrderFacetXml(groupName, sequence, translationService, oneToOneAssociation));
+            }
+
+            @Override
+            public void visit(final CollectionLayoutMetadata collectionLayoutMetadata) {
+                final OneToManyAssociation oneToManyAssociation = oneToManyAssociationById.get(collectionLayoutMetadata.getId());
+                if(oneToManyAssociation == null) {
+                    return;
+                }
+
+                FacetUtil.addFacet(CssClassFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation));
+                FacetUtil.addFacet(DefaultViewFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation));
+                FacetUtil.addFacet(DescribedAsFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation));
+                FacetUtil.addFacet(HiddenFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation));
+                FacetUtil.addFacet(NamedFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation));
+                FacetUtil.addFacet(PagedFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation));
+                FacetUtil.addFacet(SortedByFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation));
+
+                // @MemberOrder#name based on the collection's id (so that each has a single "member group")
+                final String groupName = collectionLayoutMetadata.getId();
+                final String sequence = nextInSequenceFor(groupName);
+                FacetUtil.addFacet(
+                        new MemberOrderFacetXml(groupName, sequence, translationService, oneToManyAssociation));
+
+                // if there is only a single column and no other contents, then copy the collection Id onto the tab'
+                final Column column = collectionLayoutMetadata.getOwner();
+                final Tab tab = column.getOwner();
+                if(tab.getContents().size() == 1) {
+                    tab.setName(collectionLayoutMetadata.getNamed());
+                }
+            }
+
+            private String nextInSequenceFor(final String propertyGroupName) {
+                synchronized (propertySequenceByGroup) {
+                    int[] holder = propertySequenceByGroup.get(propertyGroupName);
+                    if(holder == null) {
+                        holder = new int[]{0};
+                        propertySequenceByGroup.put(propertyGroupName, holder);
+                    }
+                    holder[0]++;
+                    return ""+holder[0];
+                }
+            }
+        });
+    }
+
+    private static List<OneToOneAssociation> getOneToOneAssociations(final ObjectSpecification objectSpec) {
+        List associations = objectSpec
+                .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.PROPERTIES);
+        return associations;
+    }
+    private static List<OneToManyAssociation> getOneToManyAssociations(final ObjectSpecification objectSpec) {
+        List associations = objectSpec
+                .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.COLLECTIONS);
+        return associations;
+    }
+
+
+    @Override
+    public String toXml(final ObjectLayoutMetadata objectLayoutMetadata) {
+        return jaxbService.toXml(objectLayoutMetadata);
+    }
+
+
+    //region > injected dependencies
+    private DeploymentCategory deploymentCategory;
+
+    @Override
+    public void setDeploymentCategory(final DeploymentCategory deploymentCategory) {
+        this.deploymentCategory = deploymentCategory;
+    }
+
+    private SpecificationLoader specificationLookup;
+
+    @Override
+    public void setSpecificationLoader(final SpecificationLoader specificationLookup) {
+        this.specificationLookup = specificationLookup;
+    }
+
+
+    @Inject
+    JaxbService jaxbService;
+
+    @Inject
+    TranslationService translationService;
+
+    //endregion
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/4da8f960/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
index 8b56996..9a23a1d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
@@ -48,7 +48,6 @@ public class MetaModelServiceDefault implements MetaModelService, SpecificationL
     private final static Logger LOG = LoggerFactory.getLogger(MetaModelServiceDefault.class);
 
 
-
     //region > fromObjectType, toObjectType
     @Programmatic
     public Class<?> fromObjectType(final String objectType) {