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/25 16:07:53 UTC

[32/50] [abbrv] isis git commit: ISIS-993: working towards getting dynamic reloading working smoothly - not there yet.

ISIS-993: working towards getting dynamic reloading working smoothly - not there yet.

* moved responsibility for reading the XML to ObjectLayoutMetadataFacet (not certain if that was a good idea).
* Update to MedataMenu to switch on/off dynamic layouts.  Don't invalidate entire spec, instead just reload the metadata.
* EntityModel cloning now shares the assocated ScalarModel map (a shallow clone), needed for edit form
* ObjectReflectorDefault only eagerly loads specs for contributed services and mixins, in an attempt to reduce startup time
* EntityTabGroupsPanelFactory now created ether the EntityTabGroupsPanel or the original EntityCombinedPanel, depending on whether there is layout.xml metadata
* added some further convenience methods to ObjectLayoutMetadata.

What I would like to do is to eagerly load up the layout.xml up front rather than lazily.  However, attempting to do that caused a stackoverflow, and not sure why.  As things stand I also have an issue with edit failing for the todoapp if no layout data at all, not sure why.


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

Branch: refs/heads/ISIS-993
Commit: 2e8c094367dcddea351d592ec9f457f802f8b219
Parents: 82d6d64
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Tue Jan 12 18:23:47 2016 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Mon Jan 25 15:06:07 2016 +0000

----------------------------------------------------------------------
 .../layout/v1_0/ObjectLayoutMetadata.java       |  53 ++-
 .../isis/applib/layout/v1_0/PropertyGroup.java  |   9 +-
 .../layout/ObjectLayoutMetadataService.java     |  17 +-
 .../layout/Object_downloadLayoutXml.java        |  13 +-
 .../facetdecorator/FacetDecoratorSet.java       |  11 +-
 .../ObjectLayoutMetadataFacet.java              |  11 +-
 .../ObjectLayoutMetadataFacetDefault.java       | 423 ++++++++++++++++++-
 .../ObjectLayoutMetadataFacetFactory.java       |  12 +-
 .../ObjectLayoutMetadataServiceDefault.java     | 378 +----------------
 .../services/metamodel/MetadataMenu.java        |  45 +-
 .../specloader/ObjectReflectorDefault.java      |  10 +-
 .../specimpl/FacetedMethodsBuilder.java         |   6 +-
 .../specimpl/ObjectActionContributee.java       |   3 +
 .../dflt/ObjectSpecificationDefault.java        |   2 +
 .../v1_0/ObjectLayoutMetadataTest.java          |   5 +-
 .../viewer/wicket/model/models/EntityModel.java |  36 +-
 .../combined/EntityCombinedPanelFactory.java    |   9 +-
 .../entity/properties/EntityColumnMembers.java  |   5 +-
 .../entity/properties/EntityPropertiesForm.java |   4 +-
 .../EntityTabGroupsPanel$EntityTabPanel.html    |   5 +-
 .../entity/tabgroups/EntityTabGroupsPanel.java  |  15 +-
 .../tabgroups/EntityTabGroupsPanelFactory.java  |  14 +-
 .../wicket/ui/pages/entity/EntityPage.java      |  22 +-
 23 files changed, 626 insertions(+), 482 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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
index 2f056a8..4af327c 100644
--- 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
@@ -33,7 +33,6 @@ 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"
@@ -182,62 +181,74 @@ public class ObjectLayoutMetadata implements Dto, ActionHolder, Serializable {
     @Programmatic
     @XmlTransient
     public LinkedHashMap<String, PropertyLayoutMetadata> getAllPropertiesById() {
-        final LinkedHashMap<String, PropertyLayoutMetadata> propertyIds = Maps.newLinkedHashMap();
+        final LinkedHashMap<String, PropertyLayoutMetadata> propertiesById = Maps.newLinkedHashMap();
         visit(new ObjectLayoutMetadata.VisitorAdapter() {
             public void visit(final PropertyLayoutMetadata propertyLayoutMetadata) {
-                propertyIds.put(propertyLayoutMetadata.getId(), propertyLayoutMetadata);
+                propertiesById.put(propertyLayoutMetadata.getId(), propertyLayoutMetadata);
             }
         });
-        return propertyIds;
+        return propertiesById;
     }
 
 
     @Programmatic
     @XmlTransient
     public LinkedHashMap<String, CollectionLayoutMetadata> getAllCollectionsById() {
-        final LinkedHashMap<String, CollectionLayoutMetadata> collectionIds = Maps.newLinkedHashMap();
-        final LinkedHashMap<String, ActionLayoutMetadata> actionIds = Maps.newLinkedHashMap();
+        final LinkedHashMap<String, CollectionLayoutMetadata> collectionsById = Maps.newLinkedHashMap();
 
         visit(new ObjectLayoutMetadata.VisitorAdapter() {
             @Override
             public void visit(final CollectionLayoutMetadata collectionLayoutMetadata) {
-                collectionIds.put(collectionLayoutMetadata.getId(), collectionLayoutMetadata);
+                collectionsById.put(collectionLayoutMetadata.getId(), collectionLayoutMetadata);
             }
         });
-        return collectionIds;
+        return collectionsById;
     }
 
 
     @Programmatic
     @XmlTransient
     public LinkedHashMap<String, ActionLayoutMetadata> getAllActionsById() {
-        final LinkedHashMap<String, ActionLayoutMetadata> actionIds = Maps.newLinkedHashMap();
+        final LinkedHashMap<String, ActionLayoutMetadata> actionsById = Maps.newLinkedHashMap();
 
         visit(new ObjectLayoutMetadata.VisitorAdapter() {
             @Override
             public void visit(final ActionLayoutMetadata actionLayoutMetadata) {
-                actionIds.put(actionLayoutMetadata.getId(), actionLayoutMetadata);
+                actionsById.put(actionLayoutMetadata.getId(), actionLayoutMetadata);
             }
         });
-        return actionIds;
+        return actionsById;
     }
 
 
+    @Programmatic
+    @XmlTransient
+    public LinkedHashMap<String, Tab> getAllTabsByName() {
+        final LinkedHashMap<String, Tab> tabsByName = Maps.newLinkedHashMap();
+
+        visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            @Override
+            public void visit(final Tab tab) {
+                tabsByName.put(tab.getName(), tab);
+            }
+        });
+        return tabsByName;
+    }
 
-    private boolean normalized;
 
-    /**
-     * Whether {@link ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class)}
-     * has been called on this instance.
-     */
     @Programmatic
     @XmlTransient
-    public boolean isNormalized() {
-        return normalized;
-    }
+    public LinkedHashMap<String, PropertyGroup> getAllPropertyGroupsByName() {
+        final LinkedHashMap<String, PropertyGroup> propertyGroupsByName = Maps.newLinkedHashMap();
 
-    public void setNormalized(final boolean normalized) {
-        this.normalized = normalized;
+        visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            @Override
+            public void visit(final PropertyGroup propertyGroup) {
+                propertyGroupsByName.put(propertyGroup.getName(), propertyGroup);
+            }
+        });
+        return propertyGroupsByName;
     }
 
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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 fd7f3c7..2fb52e3 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
@@ -19,7 +19,6 @@
 package org.apache.isis.applib.layout.v1_0;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.List;
 
 import javax.annotation.Nullable;
@@ -30,6 +29,7 @@ import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
 import com.google.common.base.Function;
+import com.google.common.collect.Lists;
 
 import org.apache.isis.applib.annotation.MemberOrder;
 
@@ -67,7 +67,7 @@ public class PropertyGroup implements ColumnContent, ActionHolder, Serializable
 
 
 
-    private List<ActionLayoutMetadata> actions;
+    private List<ActionLayoutMetadata> actions = Lists.newArrayList();
 
     @XmlElementWrapper(required = false)
     @XmlElement(name = "action", required = false)
@@ -81,10 +81,7 @@ public class PropertyGroup implements ColumnContent, ActionHolder, Serializable
 
 
 
-    // must be at least one property in the property group
-    private List<PropertyLayoutMetadata> properties = new ArrayList<PropertyLayoutMetadata>() {{
-        add(new PropertyLayoutMetadata());
-    }};
+    private List<PropertyLayoutMetadata> properties = Lists.newArrayList();
 
     @XmlElement(name = "property", required = true)
     public List<PropertyLayoutMetadata> getProperties() {

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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 f0da669..e29ff47 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
@@ -28,22 +28,21 @@ public interface ObjectLayoutMetadataService {
     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);
-
-    /**
-     * Obtains the layout metadata for the specified domain object.  It will have been {@link #normalize(ObjectLayoutMetadata, Class) normalized} already.
+     * Obtains the layout metadata, if any, for the (domain class of the) specified domain object.
      */
     @Programmatic
     ObjectLayoutMetadata toMetadata(Object domainObject);
 
     /**
-     * Obtains the layout metadata for the specified domain class.  It will have been {@link #normalize(ObjectLayoutMetadata, Class) normalized} already.
+     * Obtains the layout metadata, if any, for the specified domain class.
      */
     @Programmatic
     ObjectLayoutMetadata toMetadata(Class<?> domainClass);
 
+    @Programmatic
+    void toggleDynamicReloading();
+
+    @Programmatic
+    boolean isDynamicReloading();
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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 aca104c..726becf 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
@@ -17,6 +17,9 @@
 package org.apache.isis.applib.services.layout;
 
 import javax.inject.Inject;
+import javax.xml.bind.Marshaller;
+
+import com.google.common.collect.ImmutableMap;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
@@ -32,6 +35,9 @@ import org.apache.isis.applib.value.Clob;
 @Mixin
 public class Object_downloadLayoutXml {
 
+    public static final String TNS = "http://isis.apache.org/schema/applib/layout";
+    public static final String SCHEMA_LOCATION = "http://isis.apache.org/schema/applib/layout/layout-1.0.xsd";
+
     private final Object object;
 
     public Object_downloadLayoutXml(final Object object) {
@@ -53,7 +59,12 @@ public class Object_downloadLayoutXml {
             @ParameterLayout(named = "File name")
             final String fileName) {
         final ObjectLayoutMetadata metadata = getObjectLayoutMetadata();
-        final String xml = jaxbService.toXml(metadata);
+        final String xml = jaxbService.toXml(metadata,
+                ImmutableMap.<String,Object>of(
+                        Marshaller.JAXB_SCHEMA_LOCATION,
+                        TNS + " " + SCHEMA_LOCATION
+                ));
+
         return new Clob(Util.withSuffix(fileName, "xml"), "text/xml", xml);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java
index c540e30..38eb045 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java
@@ -21,7 +21,6 @@ package org.apache.isis.core.metamodel.facetdecorator;
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -81,10 +80,6 @@ public class FacetDecoratorSet implements ApplicationScopedComponent {
         }
     }
 
-    public Set<FacetDecorator> getFacetDecorators() {
-        return Collections.unmodifiableSet(facetDecoratorSet);
-    }
-
     public boolean isEmpty() {
         return facetDecoratorByFacetType.isEmpty();
     }
@@ -114,10 +109,12 @@ public class FacetDecoratorSet implements ApplicationScopedComponent {
         if (isEmpty()) {
             return;
         }
-        final Class<? extends Facet>[] facetTypes = holder.getFacetTypes();
+        final Set<Class<? extends Facet>> facetTypes = facetDecoratorByFacetType.keySet();
         for (final Class<? extends Facet> facetType : facetTypes) {
             final Facet facet = holder.getFacet(facetType);
-            decorateFacet(facet, holder);
+            if(facet != null) {
+                decorateFacet(facet, holder);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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
index 4d8db93..2a63428 100644
--- 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
@@ -19,8 +19,8 @@
 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;
+import org.apache.isis.core.metamodel.facetapi.Facet;
 
 /**
  * Corresponds to providing a <code>.layout.xml</code> file for the domain object's class.
@@ -28,8 +28,13 @@ import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
 public interface ObjectLayoutMetadataFacet extends Facet {
 
     /**
-     * Will have been {@link org.apache.isis.applib.services.layout.ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class) normalized}.
+     * Will have been normalized by framework earlier.
      */
     ObjectLayoutMetadata getMetadata();
 
-}
+    /**
+     * (Re)load, in support of dynamic layout reloading.
+     */
+    void reloadMetadata();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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
index 95e3712..9538e72 100644
--- 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
@@ -18,19 +18,72 @@
  */
 package org.apache.isis.core.metamodel.facets.object.layoutmetadata;
 
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.ColumnHolder;
 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.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.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 ObjectLayoutMetadataFacetDefault
             extends FacetAbstract
             implements ObjectLayoutMetadataFacet {
 
-    private final ObjectLayoutMetadata metadata;
-    private final ObjectLayoutMetadataService objectLayoutMetadataService;
+    private static final Logger LOG = LoggerFactory.getLogger(ObjectLayoutMetadataFacetDefault.class);
+
 
     public static Class<? extends Facet> type() {
         return ObjectLayoutMetadataFacet.class;
@@ -39,27 +92,375 @@ public class ObjectLayoutMetadataFacetDefault
 
     public static ObjectLayoutMetadataFacet create(
             final FacetHolder facetHolder,
-            final ObjectLayoutMetadata objectLayoutMetadata,
+            final TranslationService translationService,
             final ObjectLayoutMetadataService objectLayoutMetadataService) {
-        if(objectLayoutMetadata == null) {
-            return null;
-        }
-        return new ObjectLayoutMetadataFacetDefault(facetHolder, objectLayoutMetadata, objectLayoutMetadataService);
+        return new ObjectLayoutMetadataFacetDefault(facetHolder, translationService, objectLayoutMetadataService);
     }
 
+    private final TranslationService translationService;
+    private final ObjectLayoutMetadataService objectLayoutMetadataService;
+
+    private boolean blacklisted;
+    private ObjectLayoutMetadata metadata;
+
     private ObjectLayoutMetadataFacetDefault(
             final FacetHolder facetHolder,
-            final ObjectLayoutMetadata metadata,
+            final TranslationService translationService,
             final ObjectLayoutMetadataService objectLayoutMetadataService) {
         super(ObjectLayoutMetadataFacetDefault.type(), facetHolder, Derivation.NOT_DERIVED);
-        this.metadata = metadata;
         this.objectLayoutMetadataService = objectLayoutMetadataService;
+        this.translationService = translationService;
     }
 
+    @Override
+    public boolean isNoop() {
+        getMetadata();
+        return blacklisted;
+    }
 
+    @Override
     public ObjectLayoutMetadata getMetadata() {
-        final ObjectSpecification objectSpecification = (ObjectSpecification) getFacetHolder();
-        return objectLayoutMetadataService.normalize(metadata, objectSpecification.getCorrespondingClass());
+        if(blacklisted) {
+            return null;
+        }
+        reloadMetadata();
+        return this.metadata;
+    }
+
+    @Override
+    public void reloadMetadata() {
+        if (metadata != null && !objectLayoutMetadataService.isDynamicReloading()) {
+            return;
+        }
+        final Class<?> domainClass = getSpecification().getCorrespondingClass();
+        final ObjectLayoutMetadata metadata = objectLayoutMetadataService.fromXml(domainClass);
+        this.metadata = normalize(metadata);
+        blacklisted = this.metadata == null;
+    }
+
+    private ObjectLayoutMetadata normalize(final ObjectLayoutMetadata metadata) {
+        if(metadata == null) {
+            return null;
+        }
+        if(LOG.isInfoEnabled()) {
+            LOG.info("Normalizing layout metadata for " + getSpecification().getCorrespondingClass().getName());
+        }
+        doNormalize(metadata, getSpecification());
+        return metadata;
+    }
+
+    private void doNormalize(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 Tuple<List<String>> propertyIdTuple = surplusAndMissing(propertyIds.keySet(), oneToOneAssociationById.keySet());
+        final List<String> surplusPropertyIds = propertyIdTuple.first;
+        final List<String> missingPropertyIds = propertyIdTuple.second;
+
+        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 Tuple<List<String>> collectionIdTuple = surplusAndMissing(collectionIds.keySet(), oneToManyAssociationById.keySet());
+        final List<String> surplusCollectionIds = collectionIdTuple.first;
+        final List<String> missingCollectionIds = collectionIdTuple.second;
+
+        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);
+                final CollectionLayoutMetadata layoutMetadata = new CollectionLayoutMetadata(collectionId);
+                layoutMetadata.setDefaultView("table");
+                left.getCollections().add(layoutMetadata);
+            }
+        }
+
+        // any missing actions will be added as domain object actions (in the header)
+        final Tuple<List<String>> actionIdTuple = surplusAndMissing(actionIds.keySet(), objectActionById.keySet());
+        final List<String> surplusActionIds = actionIdTuple.first;
+        final List<String> missingActionIds = actionIdTuple.second;
+
+        for (String surplusActionId : surplusActionIds) {
+            actionIds.get(surplusActionId).setMetadataError("No such action");
+        }
+
+        if(!missingActionIds.isEmpty()) {
+            for (String actionId : missingActionIds) {
+                List<ActionLayoutMetadata> actions = metadata.getActions();
+                if(actions == null) {
+                    actions = Lists.newArrayList();
+                    metadata.setActions(actions);
+                }
+                actions.add(new ActionLayoutMetadata(actionId));
+            }
+        }
+    }
+
+    static class Tuple<T> {
+        final T first;
+        final T second;
+        private Tuple(final T first, final T second) {
+            this.first = first;
+            this.second = second;
+        }
+        public static <T> Tuple<T> of(final T first, final T second) {
+            return new Tuple<>(first, second);
+        }
+    }
+    /**
+     * Returns a 2-element tuple of [first-second, second-first]
+     */
+    static <T> Tuple<List<T>> surplusAndMissing(final Collection<T> first, final Collection<T> second){
+        final List<T> firstNotSecond = Lists.newArrayList(first);
+        firstNotSecond.removeAll(second);
+        final List<T> secondNotFirst = Lists.newArrayList(second);
+        secondNotFirst.removeAll(first);
+        return Tuple.of(firstNotSecond, secondNotFirst);
+    }
+
+    private void overwrite(
+            final ObjectLayoutMetadata metadata,
+            final Map<String, OneToOneAssociation> oneToOneAssociationById,
+            final Map<String, OneToManyAssociation> oneToManyAssociationById,
+            final Map<String, ObjectAction> objectActionById) {
+
+        final Map<String, int[]> propertySequenceByGroup = Maps.newHashMap();
+
+        metadata.visit(new ObjectLayoutMetadata.VisitorAdapter() {
+            private int collectionSequence = 1;
+            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, propertySequenceByGroup);
+                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 = "" + collectionSequence++;
+                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 ColumnHolder holder = column.getOwner();
+                if(holder instanceof Tab) {
+                    final Tab tab = (Tab) holder;
+                    if(tab.getContents().size() == 1) {
+                        final String collectionName = oneToManyAssociation.getName();
+                        tab.setName(collectionName);
+                    }
+                }
+            }
+        });
     }
 
+    private String nextInSequenceFor(
+            final String key, final Map<String, int[]> seqByKey) {
+        synchronized (seqByKey) {
+            int[] holder = seqByKey.get(key);
+            if(holder == null) {
+                holder = new int[]{0};
+                seqByKey.put(key, 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;
+    }
+
+    private ObjectSpecification getSpecification() {
+        return (ObjectSpecification)getFacetHolder();
+    }
+
+
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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
index 0f1b4e8..479849c 100644
--- 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
@@ -19,7 +19,7 @@ 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.i18n.TranslationService;
 import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
@@ -38,17 +38,13 @@ public class ObjectLayoutMetadataFacetFactory extends FacetFactoryAbstract imple
 
     @Override
     public void process(final ProcessClassContext processClassContext) {
-        final Class<?> cls = processClassContext.getCls();
         final FacetHolder facetHolder = processClassContext.getFacetHolder();
 
+        final TranslationService translationService = servicesInjector.lookupService(TranslationService.class);
         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);
+                ObjectLayoutMetadataFacetDefault.create(facetHolder,
+                        translationService, objectLayoutMetadataService));
     }
 
     private ServicesInjector servicesInjector;

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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 3080769..6431486 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
@@ -19,16 +19,10 @@ 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;
 
@@ -38,60 +32,17 @@ 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.ColumnHolder;
 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.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;
-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 {
+        implements ObjectLayoutMetadataService, SpecificationLoaderAware {
 
     private static final Logger LOG = LoggerFactory.getLogger(ObjectLayoutMetadataServiceDefault.class);
 
@@ -139,316 +90,6 @@ public class ObjectLayoutMetadataServiceDefault
     }
 
 
-    @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);
-                final CollectionLayoutMetadata layoutMetadata = new CollectionLayoutMetadata(collectionId);
-                layoutMetadata.setDefaultView("table");
-                left.getCollections().add(layoutMetadata);
-            }
-        }
-
-        // 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) {
-                List<ActionLayoutMetadata> actions = metadata.getActions();
-                if(actions == null) {
-                    actions = Lists.newArrayList();
-                    metadata.setActions(actions);
-                }
-                actions.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 collectionSequence = 1;
-            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, propertySequenceByGroup);
-                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 = "" + collectionSequence++;
-                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 ColumnHolder holder = column.getOwner();
-                if(holder instanceof Tab) {
-                    final Tab tab = (Tab) holder;
-                    if(tab.getContents().size() == 1) {
-                        final String collectionName = oneToManyAssociation.getName();
-                        tab.setName(collectionName);
-                    }
-                }
-            }
-
-            private String nextInSequenceFor(
-                    final String key, final Map<String, int[]> seqByKey) {
-                synchronized (seqByKey) {
-                    int[] holder = seqByKey.get(key);
-                    if(holder == null) {
-                        holder = new int[]{0};
-                        seqByKey.put(key, 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 ObjectLayoutMetadata toMetadata(final Object domainObject) {
@@ -462,16 +103,22 @@ public class ObjectLayoutMetadataServiceDefault
         return facet != null? facet.getMetadata(): null;
     }
 
+    ////////////////////////////////////////////////////////
 
+    private boolean dynamicReloading;
 
-    //region > injected dependencies
-    private DeploymentCategory deploymentCategory;
+    @Override
+    public void toggleDynamicReloading() {
+        this.dynamicReloading = !this.dynamicReloading;
+    }
 
     @Override
-    public void setDeploymentCategory(final DeploymentCategory deploymentCategory) {
-        this.deploymentCategory = deploymentCategory;
+    public boolean isDynamicReloading() {
+        return this.dynamicReloading;
     }
 
+    //region > injected dependencies
+
     private SpecificationLoader specificationLookup;
 
     @Override
@@ -479,12 +126,9 @@ public class ObjectLayoutMetadataServiceDefault
         this.specificationLookup = specificationLookup;
     }
 
-
     @Inject
     JaxbService jaxbService;
 
-    @Inject
-    TranslationService translationService;
 
     //endregion
 

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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
index fadfae2..900ecc3 100644
--- 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
@@ -132,6 +132,50 @@ public class MetadataMenu implements SpecificationLoaderSpiAware {
 
     // //////////////////////////////////////
 
+    public static class SwitchOnDynamicReloadingOfLayoutsDomainEvent extends ActionDomainEvent {
+    }
+
+    @Action(
+            domainEvent = SwitchOnDynamicReloadingOfLayoutsDomainEvent.class,
+            semantics = SemanticsOf.SAFE,
+            restrictTo = RestrictTo.PROTOTYPING
+    )
+    @ActionLayout(
+            cssClassFa = "fa-check"
+    )
+    @MemberOrder(sequence="500.400.2")
+    public void switchOnDynamicReloadingOfLayouts() {
+        objectLayoutMetadataService.toggleDynamicReloading();
+    }
+    public boolean hideSwitchOnDynamicReloadingOfLayouts() {
+        return objectLayoutMetadataService.isDynamicReloading();
+    }
+
+    // //////////////////////////////////////
+
+    public static class SwitchOffDynamicReloadingOfLayoutsDomainEvent extends ActionDomainEvent {
+    }
+
+    @Action(
+            domainEvent = SwitchOffDynamicReloadingOfLayoutsDomainEvent.class,
+            semantics = SemanticsOf.SAFE,
+            restrictTo = RestrictTo.PROTOTYPING
+    )
+    @ActionLayout(
+            cssClassFa = "fa-times"
+    )
+    @MemberOrder(sequence="500.400.3")
+    public void switchOffDynamicReloadingOfLayouts() {
+        objectLayoutMetadataService.toggleDynamicReloading();
+    }
+    public boolean hideSwitchOffDynamicReloadingOfLayouts() {
+        return !objectLayoutMetadataService.isDynamicReloading();
+    }
+
+
+
+    // //////////////////////////////////////
+
     @Inject
     ObjectLayoutMetadataService objectLayoutMetadataService;
 
@@ -146,5 +190,4 @@ public class MetadataMenu implements SpecificationLoaderSpiAware {
         this.specificationLoader = specificationLoader;
     }
 
-
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
index e4abde8..5f4c0d1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
@@ -33,6 +33,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.isis.applib.AppManifest;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.core.commons.components.ApplicationScopedComponent;
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.commons.debug.DebugBuilder;
@@ -256,7 +258,12 @@ public final class ObjectReflectorDefault
 
     private void loadSpecificationsForServices() {
         for (final Class<?> serviceClass : getServiceClasses()) {
-            internalLoadSpecification(serviceClass);
+            final DomainService domainService = serviceClass.getAnnotation(DomainService.class);
+            if(domainService != null) {
+                if(domainService.nature() == NatureOfService.VIEW || domainService.nature() == NatureOfService.VIEW_CONTRIBUTIONS_ONLY) {
+                    internalLoadSpecification(serviceClass);
+                }
+            }
         }
     }
 
@@ -515,6 +522,7 @@ public final class ObjectReflectorDefault
         facetDecoratorSet.decorate(specSpi);
         specSpi.updateFromFacetValues();
         specSpi.setIntrospectionState(IntrospectionState.INTROSPECTED);
+
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
index 9628a34..a6e71df 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
@@ -49,6 +49,7 @@ import org.apache.isis.core.metamodel.facets.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.FacetedMethodParameter;
 import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
 import org.apache.isis.core.metamodel.facets.object.facets.FacetsFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet;
 import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader;
 import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader.ReaderException;
 import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader2;
@@ -189,13 +190,14 @@ public class FacetedMethodsBuilder {
 
 
     public Properties introspectClass() {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("introspecting " + getClassName() + ": class-level details");
+        if (LOG.isInfoEnabled()) {
+            LOG.info("introspecting " + getClassName() + ": class-level details");
         }
 
         // process facets at object level
         // this will also remove some methods, such as the superclass methods.
 
+        final ObjectLayoutMetadataFacet facet = spec.getFacet(ObjectLayoutMetadataFacet.class);
         final Properties metadataProperties = readMetadataProperties(introspectedClass);
 
         getFacetProcessor().process(introspectedClass, metadataProperties, methodRemover, spec);

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
index 5aa6444..070a88d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
@@ -22,6 +22,9 @@ import java.util.List;
 
 import com.google.common.collect.Lists;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.InvokedOn;

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index 071f760..afd556e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@ -176,6 +176,8 @@ public class ObjectSpecificationDefault extends ObjectSpecificationAbstract impl
             sortCacheAndUpdateActions(actions);
         }
 
+
+
         if(isNotIntrospected()) {
             facetedMethodsBuilder.introspectClassPostProcessing(metadataProperties);    
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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
index 73df1fb..c5e8c1b 100644
--- 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
@@ -77,8 +77,9 @@ public class ObjectLayoutMetadataTest {
         left.getCollections().add(similarToColl);
         similarToColl.setId("similarTo");
 
-        PropertyLayoutMetadata namePropertyLayoutMetadata = leftPropGroup.getProperties().get(0);
-        namePropertyLayoutMetadata.setId("name");
+        left.getPropertyGroups().add(new PropertyGroup("General"));
+        PropertyLayoutMetadata namePropertyLayoutMetadata = new PropertyLayoutMetadata("name");
+        left.getPropertyGroups().get(0).getProperties().add(namePropertyLayoutMetadata);
 
         ActionLayoutMetadata updateNameActionLayoutMetadata = new ActionLayoutMetadata();
         updateNameActionLayoutMetadata.setId("updateName");

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
index bebb67c..559e110 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
@@ -126,11 +126,14 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
         VIEW, EDIT;
     }
 
+    private final Map<PropertyMemento, ScalarModel> propertyScalarModels;
     private ObjectAdapterMemento adapterMemento;
+    private ObjectAdapterMemento contextAdapterIfAny;
+
     private Mode mode = Mode.VIEW;
     private RenderingHint renderingHint = RenderingHint.REGULAR;
-    private final Map<PropertyMemento, ScalarModel> propertyScalarModels = Maps.newHashMap();
     private Hint hint;
+    private final PendingModel pendingModel;
 
     /**
      * Toggled by 'entityDetailsButton'.
@@ -149,7 +152,7 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
     // //////////////////////////////////////////////////////////
 
     public EntityModel() {
-        pendingModel = new PendingModel(this);
+        this((ObjectAdapterMemento)null);
     }
 
     public EntityModel(final PageParameters pageParameters) {
@@ -162,8 +165,13 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
     }
 
     public EntityModel(final ObjectAdapterMemento adapterMemento) {
+        this(adapterMemento, Maps.<PropertyMemento, ScalarModel>newHashMap());
+    }
+
+    public EntityModel(final ObjectAdapterMemento adapterMemento, final Map<PropertyMemento, ScalarModel> propertyScalarModels) {
         this.adapterMemento = adapterMemento;
         this.pendingModel = new PendingModel(this);
+        this.propertyScalarModels = propertyScalarModels;
     }
 
     public static String oidStr(final PageParameters pageParameters) {
@@ -608,8 +616,6 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
         }
     }
     
-    private final PendingModel pendingModel;
-    private ObjectAdapterMemento contextAdapterIfAny;
 
     public ObjectAdapter getPendingElseCurrentAdapter() {
         return pendingModel.getPendingElseCurrentAdapter();
@@ -642,19 +648,27 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
         return tabMetadata;
     }
 
-    public EntityModel withTabMetadata(final Tab tabMetadata) {
-        this.tabMetadata = tabMetadata;
-        return this;
+    /**
+     * Returns a new copy that SHARES the property scalar models (for edit form).
+     */
+    public EntityModel cloneWithTabMetadata(final Tab tabMetadata) {
+        final EntityModel entityModel = new EntityModel(this.adapterMemento, this.propertyScalarModels);
+        entityModel.tabMetadata = tabMetadata;
+        return entityModel;
     }
 
 
     private Column columnMetadata;
     private Column.Hint columnHint;
 
-    public EntityModel withColumnMetadata(final Column columnMetadata, final Column.Hint columnHint) {
-        this.columnMetadata = columnMetadata;
-        this.columnHint = columnHint;
-        return this;
+    /**
+     * Returns a new copy that SHARES the property scalar models (for edit form).
+     */
+    public EntityModel cloneWithColumnMetadata(final Column columnMetadata, final Column.Hint columnHint) {
+        final EntityModel entityModel = new EntityModel(this.adapterMemento, this.propertyScalarModels);
+        entityModel.columnMetadata = columnMetadata;
+        entityModel.columnHint = columnHint;
+        return entityModel;
     }
 
     public Column getColumnMetadata() {

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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 32c0900..004ba23 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,8 +22,6 @@ 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.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;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
@@ -44,14 +42,11 @@ public class EntityCombinedPanelFactory extends EntityComponentFactoryAbstract {
 
     @Override
     protected ApplicationAdvice doAppliesTo(final EntityModel entityModel) {
-        final ObjectSpecification specification = entityModel.getTypeOfSpecification();
-        // opposite to the EntityTabbedPanelFactory
-        return appliesIf(!specification.containsDoOpFacet(ObjectLayoutMetadataFacet.class));
+        return appliesIf(false); // TODO: remove
     }
 
     @Override
     public Component createComponent(final String id, final IModel<?> model) {
-        final EntityModel entityModel = (EntityModel) model;
-        return new EntityCombinedPanel(id, entityModel);
+        throw new IllegalStateException("shouldn't be called"); // TODO: remove
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java
index 3e0cd3f..a294969 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java
@@ -73,14 +73,13 @@ public class EntityColumnMembers extends PanelAbstract<EntityModel> {
             final Component owningPanel) {
 
         super(id, entityModel);
-        this.owningPanel = owningPanel; // for repainting
+        this.owningPanel = owningPanel; // for repainting, perhaps
 
         buildGui();
     }
 
     private void buildGui() {
-        final EntityModel entityModel = (EntityModel) getModel();
-        addPropertiesAndCollections(this, entityModel);
+        addPropertiesAndCollections(this, getModel());
     }
 
     private void addPropertiesAndCollections(

http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/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 24837b6..31c54a1 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
@@ -238,9 +238,7 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
             final Hint hint) {
         final Column columnMetaDataIfAny = hint.from(tabMetaDataIfAny);
 
-        final EntityModel entityModelWithHints =
-                new EntityModel(entityModel.getPageParameters())
-                        .withColumnMetadata(columnMetaDataIfAny, hint);
+        final EntityModel entityModelWithHints = entityModel.cloneWithColumnMetadata(columnMetaDataIfAny, hint);
 
         final EntityColumnMembers columnMembers =
                 new EntityColumnMembers("entityMembers", entityModelWithHints, markupContainer);