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:02:00 UTC

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

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;
         }