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/06 10:00:05 UTC

[1/4] isis git commit: ISIS-1295: removed IsisContextStatic and ContextCategory, folded IsisContextThreadLocal into IsisContext

Repository: isis
Updated Branches:
  refs/heads/ISIS-993 [created] 599e179d8


ISIS-1295: removed IsisContextStatic and ContextCategory, folded IsisContextThreadLocal into IsisContext


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

Branch: refs/heads/ISIS-993
Commit: ee58bb0c07d6b3cd897751e2c9e0e5d55f6528df
Parents: 9fe8b0b
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Mon Jan 4 18:38:19 2016 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Mon Jan 4 18:38:19 2016 +0000

----------------------------------------------------------------------
 .../core/runtime/system/ContextCategory.java    |  79 --------
 .../core/runtime/system/DeploymentType.java     |  38 +---
 .../runtime/system/context/IsisContext.java     | 132 +++++++++++--
 .../system/context/IsisContextStatic.java       | 137 --------------
 .../system/context/IsisContextThreadLocal.java  | 183 -------------------
 .../core/runtime/context/IsisContextTest.java   | 140 --------------
 .../isis/DeploymentTypeAbstract.java            |   8 +-
 7 files changed, 128 insertions(+), 589 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/ee58bb0c/core/runtime/src/main/java/org/apache/isis/core/runtime/system/ContextCategory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/ContextCategory.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/ContextCategory.java
deleted file mode 100644
index 90ac5de..0000000
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/ContextCategory.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.runtime.system;
-
-import java.util.List;
-
-import org.apache.isis.core.runtime.system.context.IsisContextStatic;
-import org.apache.isis.core.runtime.system.context.IsisContextThreadLocal;
-import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
-
-/**
- * @see DeploymentType
- */
-public abstract class ContextCategory {
-
-    public static ContextCategory STATIC_RELAXED = new ContextCategory() {
-        @Override
-        public void initContext(final IsisSessionFactory sessionFactory) {
-            IsisContextStatic.createRelaxedInstance(sessionFactory);
-        }
-
-        @Override
-        public boolean canSpecifyViewers(final List<String> viewers) {
-            // no more than one
-            return viewers.size() <= 1;
-        }
-    };
-
-    public static ContextCategory STATIC = new ContextCategory() {
-        @Override
-        public void initContext(final IsisSessionFactory sessionFactory) {
-            IsisContextStatic.createInstance(sessionFactory);
-        }
-
-        @Override
-        public boolean canSpecifyViewers(final List<String> viewers) {
-            // no more than one
-            return viewers.size() == 1;
-        }
-    };
-    public static ContextCategory THREADLOCAL = new ContextCategory() {
-        @Override
-        public void initContext(final IsisSessionFactory sessionFactory) {
-            IsisContextThreadLocal.createInstance(sessionFactory);
-        }
-
-        @Override
-        public boolean canSpecifyViewers(final List<String> viewers) {
-            // as many as you like
-            return true;
-        }
-    };
-
-    public abstract void initContext(IsisSessionFactory sessionFactory);
-
-    /**
-     * Whether the list of connector names provided is compatible with this
-     * {@link ContextCategory}.
-     */
-    public abstract boolean canSpecifyViewers(List<String> viewers);
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee58bb0c/core/runtime/src/main/java/org/apache/isis/core/runtime/system/DeploymentType.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/DeploymentType.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/DeploymentType.java
index 1371ec5..153d426 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/DeploymentType.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/DeploymentType.java
@@ -27,41 +27,20 @@ import org.apache.isis.core.commons.debug.DebugBuilder;
 import org.apache.isis.core.commons.debug.DebuggableWithTitle;
 import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
 import org.apache.isis.core.metamodel.deployment.DeploymentCategoryProviderAbstract;
+import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 
 /**
  * Whether running on client or server side etc.
- * 
- * <p>
- * Previously this was an <tt>enum</tt>, but it is now a regular class. The
- * change has been made to provide more flexibility in setting up the
- * <tt>IsisContext</tt> lookup.
- * 
- * <p>
- * To use this capability:
- * <ul>
- * <li>Write your new implementation of <tt>IsisContext</tt>, along with a
- * static factory method (cf
- * <tt>IsisContextStatic#createInstance(IsisSessionFactory)</tt>)
- * <li>Create a new subclass of {@link ContextCategory} (also now a regular
- * class rather than an <tt>enum</tt>); this is where your code goes to
- * instantiate your <tt>IsisContext</tt> implementation</li>
- * <li>Create a new subclass of {@link DeploymentType}, passing in the custom
- * {@link ContextCategory} in its constructor</li>
- * <li>In your bootstrap code, instantiate your new {@link DeploymentType}
- * subclass</li>
- * <li>When you run your app, don't forget to specify your custom
- * {@link DeploymentType}, eg using the <tt>--type</tt> command line arg</li>
- * </ul>
  */
 public class DeploymentType extends DeploymentCategoryProviderAbstract {
 
     private static List<DeploymentType> deploymentTypes = Lists.newArrayList();
 
-    public static DeploymentType SERVER = new DeploymentType("SERVER", DeploymentCategory.PRODUCTION, ContextCategory.THREADLOCAL);
-    public static DeploymentType SERVER_EXPLORATION = new DeploymentType("SERVER_EXPLORATION", DeploymentCategory.EXPLORING, ContextCategory.THREADLOCAL);
-    public static DeploymentType SERVER_PROTOTYPE = new DeploymentType("SERVER_PROTOTYPE", DeploymentCategory.PROTOTYPING, ContextCategory.THREADLOCAL);
-    public static DeploymentType UNIT_TESTING = new DeploymentType("UNIT_TESTING", DeploymentCategory.PRODUCTION, ContextCategory.STATIC_RELAXED);
+    public static DeploymentType SERVER = new DeploymentType("SERVER", DeploymentCategory.PRODUCTION);
+    public static DeploymentType SERVER_EXPLORATION = new DeploymentType("SERVER_EXPLORATION", DeploymentCategory.EXPLORING);
+    public static DeploymentType SERVER_PROTOTYPE = new DeploymentType("SERVER_PROTOTYPE", DeploymentCategory.PROTOTYPING);
+    public static DeploymentType UNIT_TESTING = new DeploymentType("UNIT_TESTING", DeploymentCategory.PRODUCTION);
 
     /**
      * Look up {@link DeploymentType} by their {@link #name()}.
@@ -84,12 +63,10 @@ public class DeploymentType extends DeploymentCategoryProviderAbstract {
 
     private final String name;
     private final DeploymentCategory deploymentCategory;
-    private final ContextCategory contextCategory;
 
     public DeploymentType(
-            final String name, final DeploymentCategory category, final ContextCategory contextCategory) {
+            final String name, final DeploymentCategory category) {
         this.deploymentCategory = category;
-        this.contextCategory = contextCategory;
         this.name = name;
         deploymentTypes.add(this);
     }
@@ -100,7 +77,6 @@ public class DeploymentType extends DeploymentCategoryProviderAbstract {
             @Override
             public void debugData(final DebugBuilder debug) {
                 debug.appendln("Category", deploymentCategory);
-                debug.appendln("Context", contextCategory);
                 debug.appendln();
                 debug.appendln("Name", friendlyName());
                 debug.appendln("Should monitor", shouldMonitor());
@@ -114,7 +90,7 @@ public class DeploymentType extends DeploymentCategoryProviderAbstract {
     }
 
     public void initContext(final IsisSessionFactory sessionFactory) {
-        contextCategory.initContext(sessionFactory);
+        IsisContext.createInstance(sessionFactory);
     }
 
     public boolean shouldMonitor() {

http://git-wip-us.apache.org/repos/asf/isis/blob/ee58bb0c/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
index 0d49e9b..9fe9b17 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
@@ -19,7 +19,9 @@
 
 package org.apache.isis.core.runtime.system.context;
 
+import java.util.IdentityHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.Callable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -55,7 +57,7 @@ import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
  * <p>
  * Somewhat analogous to (the static methods in) <tt>HibernateUtil</tt>.
  */
-public abstract class IsisContext implements DebuggableWithTitle {
+public class IsisContext implements DebuggableWithTitle {
 
     private static final Logger LOG = LoggerFactory.getLogger(IsisContext.class);
 
@@ -114,6 +116,7 @@ public abstract class IsisContext implements DebuggableWithTitle {
         NOT_REPLACEABLE, REPLACEABLE
     }
 
+
     /**
      * Creates a new instance of the {@link IsisSession} holder.
      * 
@@ -131,6 +134,13 @@ public abstract class IsisContext implements DebuggableWithTitle {
         this.replacePolicy = replacePolicy;
     }
 
+
+    protected IsisContext(final IsisSessionFactory sessionFactory) {
+        this(ContextReplacePolicy.NOT_REPLACEABLE, SessionClosePolicy.AUTO_CLOSE, sessionFactory);
+    }
+
+
+
     protected void shutdownInstance() {
         this.sessionFactory.shutdown();
     }
@@ -194,10 +204,39 @@ public abstract class IsisContext implements DebuggableWithTitle {
     /**
      * Creates a new {@link IsisSession} and binds into the current context.
      * 
+     * Is only intended to be called through
+     * {@link IsisContext#openSession(AuthenticationSession)}.
+     *
+     * <p>
+     * Implementation note: an alternative design would have just been to bind
+     * onto a thread local.
+     *
      * @throws IllegalStateException
      *             if already opened.
      */
-    public abstract IsisSession openSessionInstance(AuthenticationSession session);
+    public IsisSession openSessionInstance(final AuthenticationSession authenticationSession) {
+        final Thread thread = Thread.currentThread();
+        synchronized (sessionsByThread) {
+            applySessionClosePolicy();
+            final IsisSession session = getSessionFactoryInstance().openSession(authenticationSession);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("  opening session " + session + " (count " + sessionsByThread.size() + ") for " + authenticationSession.getUserName());
+            }
+            saveSession(thread, session);
+            session.open();
+            return session;
+        }
+    }
+
+    private IsisSession saveSession(final Thread thread, final IsisSession session) {
+        synchronized (sessionsByThread) {
+            sessionsByThread.put(thread, session);
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("  saving session " + session + "; now have " + sessionsByThread.size() + " sessions");
+        }
+        return session;
+    }
 
     /**
      * Closes the {@link IsisSession} for the current context.
@@ -230,32 +269,43 @@ public abstract class IsisContext implements DebuggableWithTitle {
      * already have been {@link IsisSession#close() closed}.
      */
     protected void doClose() {
+        sessionsByThread.remove(Thread.currentThread());
     }
 
     /**
      * Shutdown the application.
      */
-    protected abstract void closeAllSessionsInstance();
+    public void closeAllSessionsInstance() {
+        shutdownAllThreads();
+    }
+
 
-    
 
     // ///////////////////////////////////////////////////////////
     // getSession()
     // ///////////////////////////////////////////////////////////
 
     /**
-     * Locates the current {@link IsisSession}.
-     * 
-     * <p>
-     * This might just be a singleton (eg {@link IsisContextStatic}), or could
-     * be retrieved from the thread (eg {@link IsisContextThreadLocal}).
+     * Locates the current {@link IsisSession} from the threadlocal.
+     *
+     * @see #openSessionInstance(AuthenticationSession)
      */
-    public abstract IsisSession getSessionInstance();
+    public IsisSession getSessionInstance() {
+        final Thread thread = Thread.currentThread();
+        return sessionsByThread.get(thread);
+    }
 
     /**
      * The {@link IsisSession} for specified {@link IsisSession#getId()}.
      */
-    protected abstract IsisSession getSessionInstance(String sessionId);
+    protected IsisSession getSessionInstance(final String executionContextId) {
+        for (final IsisSession data : sessionsByThread.values()) {
+            if (data.getId().equals(executionContextId)) {
+                return data;
+            }
+        }
+        return null;
+    }
 
     /**
      * All known session Ids.
@@ -263,7 +313,14 @@ public abstract class IsisContext implements DebuggableWithTitle {
      * <p>
      * Provided primarily for debugging.
      */
-    public abstract String[] allSessionIds();
+    public String[] allSessionIds() {
+        final String[] ids = new String[sessionsByThread.size()];
+        int i = 0;
+        for (final IsisSession data  : sessionsByThread.values()) {
+            ids[i++] = data.getId();
+        }
+        return ids;
+    }
 
     // ///////////////////////////////////////////////////////////
     // Static Convenience methods (session management)
@@ -517,6 +574,12 @@ public abstract class IsisContext implements DebuggableWithTitle {
     @Override
     public void debugData(final DebugBuilder debug) {
         debug.appendln("context ", this);
+        debug.appendTitle("Threads based Contexts");
+        for (final Map.Entry<Thread, IsisSession> entry : sessionsByThread.entrySet()) {
+            final Thread thread = entry.getKey();
+            final IsisSession data = entry.getValue();
+            debug.appendln(thread.toString(), data);
+        }
     }
 
     /**
@@ -562,4 +625,49 @@ public abstract class IsisContext implements DebuggableWithTitle {
             }
         }
     }
+
+
+
+    public static IsisContext createInstance(final IsisSessionFactory sessionFactory) {
+        return new IsisContext(sessionFactory);
+    }
+
+    // TODO: could convert this to a regular ThreadLocal, I think; except for the closeAllSessionsInstance() method...; is that method really needed?
+    private final Map<Thread, IsisSession> sessionsByThread = new IdentityHashMap<>();
+
+
+
+
+    // /////////////////////////////////////////////////////////
+    // Session
+    // /////////////////////////////////////////////////////////
+
+
+    protected void shutdownAllThreads() {
+        synchronized (sessionsByThread) {
+            for (final Map.Entry<Thread, IsisSession> entry : sessionsByThread.entrySet()) {
+                LOG.info("Shutting down thread: {}", entry.getKey().getName());
+                final IsisSession data = entry.getValue();
+                data.closeAll();
+            }
+        }
+    }
+
+
+
+    // /////////////////////////////////////////////////////////
+    // Debugging
+    // /////////////////////////////////////////////////////////
+
+    @Override
+    public String debugTitle() {
+        return "Isis (by thread) " + Thread.currentThread().getName();
+    }
+
+
+
+
+
+
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/ee58bb0c/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextStatic.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextStatic.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextStatic.java
deleted file mode 100644
index 165d23e..0000000
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextStatic.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.runtime.system.context;
-
-import org.apache.isis.core.commons.authentication.AuthenticationSession;
-import org.apache.isis.core.commons.debug.DebugBuilder;
-import org.apache.isis.core.commons.debug.DebuggableWithTitle;
-import org.apache.isis.core.runtime.system.DeploymentType;
-import org.apache.isis.core.runtime.system.session.IsisSession;
-import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
-
-/**
- * Provides <i>access to</i> the current {@link IsisSession} in a single-user
- * {@link DeploymentType deployment} (and thus implemented as a <tt>static</tt>
- * singleton).
- */
-public class IsisContextStatic extends IsisContext {
-
-    private IsisSession session;
-
-    // //////////////////////////////////////////////
-    // Singleton & Constructor
-    // //////////////////////////////////////////////
-
-    public static IsisContext createInstance(final IsisSessionFactory sessionFactory) {
-        return new IsisContextStatic(ContextReplacePolicy.NOT_REPLACEABLE, SessionClosePolicy.EXPLICIT_CLOSE, sessionFactory);
-    }
-
-    /**
-     * Intended for testing; the singleton can be replaced and sessions are
-     * autoclosed.
-     */
-    public static IsisContext createRelaxedInstance(final IsisSessionFactory sessionFactory) {
-        return new IsisContextStatic(ContextReplacePolicy.REPLACEABLE, SessionClosePolicy.AUTO_CLOSE, sessionFactory);
-    }
-
-    protected IsisContextStatic(final ContextReplacePolicy replacePolicy, final SessionClosePolicy sessionClosePolicy, final IsisSessionFactory sessionFactory) {
-        super(replacePolicy, sessionClosePolicy, sessionFactory);
-    }
-
-    @Override
-    public IsisSession getSessionInstance() {
-        return session;
-    }
-
-    // //////////////////////////////////////////////
-    // open, close
-    // //////////////////////////////////////////////
-
-    @Override
-    public IsisSession openSessionInstance(final AuthenticationSession authenticationSession) {
-        applySessionClosePolicy();
-        session = getSessionFactoryInstance().openSession(authenticationSession);
-        session.open();
-        return session;
-    }
-
-    @Override
-    public void doClose() {
-        session = null;
-    }
-
-    // //////////////////////////////////////////////
-    // sessionId(s)
-    // //////////////////////////////////////////////
-
-    @Override
-    protected IsisSession getSessionInstance(final String sessionId) {
-        return getSessionInstance();
-    }
-
-    @Override
-    public String[] allSessionIds() {
-        return new String[] { getSessionInstance().getId() };
-    }
-
-    // //////////////////////////////////////////////
-    // Session
-    // //////////////////////////////////////////////
-
-    @Override
-    public void closeAllSessionsInstance() {
-        final IsisSession sessionInstance = getSessionInstance();
-        if (sessionInstance != null) {
-            sessionInstance.closeAll();
-        }
-    }
-
-    // //////////////////////////////////////////////
-    // Debugging
-    // //////////////////////////////////////////////
-
-    @Override
-    public String debugTitle() {
-        return "Static Context";
-    }
-
-    public void debug(final DebugBuilder debug) {
-        debug.appendAsHexln("hash", hashCode());
-        session.debugState(debug);
-    }
-
-    public void debugAll(final DebugBuilder debug) {
-        debug(debug);
-        debug.appendln();
-
-        debug(debug, getPersistenceSession());
-    }
-
-    private void debug(final DebugBuilder debug, final Object object) {
-        if (object instanceof DebuggableWithTitle) {
-            final DebuggableWithTitle d = (DebuggableWithTitle) object;
-            debug.appendTitle(d.debugTitle());
-            d.debugData(debug);
-        } else {
-            debug.appendln("no debug for " + object);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee58bb0c/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextThreadLocal.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextThreadLocal.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextThreadLocal.java
deleted file mode 100644
index 1e25e5e..0000000
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContextThreadLocal.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.runtime.system.context;
-
-import java.util.IdentityHashMap;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.core.commons.authentication.AuthenticationSession;
-import org.apache.isis.core.commons.debug.DebugBuilder;
-import org.apache.isis.core.runtime.system.session.IsisSession;
-import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
-
-/**
- * Multi-user implementation of {@link IsisContext} that stores a set of components for
- * each thread in use.
- */
-public class IsisContextThreadLocal extends IsisContext {
-
-    private static final Logger LOG = LoggerFactory.getLogger(IsisContextThreadLocal.class);
-
-    public static IsisContext createInstance(final IsisSessionFactory sessionFactory) {
-        return new IsisContextThreadLocal(sessionFactory);
-    }
-
-    // TODO: could convert this to a regular ThreadLocal, I think; except for the closeAllSessionsInstance() method...; is that method really needed?
-    private final Map<Thread, IsisSession> sessionsByThread = new IdentityHashMap<>();
-
-    
-    // //////////////////////////////////////////////
-    // Constructor
-    // //////////////////////////////////////////////
-
-    protected IsisContextThreadLocal(final IsisSessionFactory sessionFactory) {
-        this(ContextReplacePolicy.NOT_REPLACEABLE, SessionClosePolicy.AUTO_CLOSE, sessionFactory);
-    }
-
-    protected IsisContextThreadLocal(final ContextReplacePolicy contextReplacePolicy, final SessionClosePolicy sessionClosePolicy, final IsisSessionFactory sessionFactory) {
-        super(contextReplacePolicy, sessionClosePolicy, sessionFactory);
-    }
-
-
-    // /////////////////////////////////////////////////////////
-    // Session
-    // /////////////////////////////////////////////////////////
-
-    @Override
-    public void closeAllSessionsInstance() {
-        shutdownAllThreads();
-    }
-
-    protected void shutdownAllThreads() {
-        synchronized (sessionsByThread) {
-            for (final Map.Entry<Thread, IsisSession> entry : sessionsByThread.entrySet()) {
-                LOG.info("Shutting down thread: {}", entry.getKey().getName());
-                final IsisSession data = entry.getValue();
-                data.closeAll();
-            }
-        }
-    }
-
-    @Override
-    protected void doClose() {
-        sessionsByThread.remove(Thread.currentThread());
-    }
-
-    // /////////////////////////////////////////////////////////
-    // Execution Context Ids
-    // /////////////////////////////////////////////////////////
-
-    @Override
-    public String[] allSessionIds() {
-        final String[] ids = new String[sessionsByThread.size()];
-        int i = 0;
-        for (final IsisSession data  : sessionsByThread.values()) {
-            ids[i++] = data.getId();
-        }
-        return ids;
-    }
-
-    // /////////////////////////////////////////////////////////
-    // Debugging
-    // /////////////////////////////////////////////////////////
-
-    @Override
-    public String debugTitle() {
-        return "Isis (by thread) " + Thread.currentThread().getName();
-    }
-
-    @Override
-    public void debugData(final DebugBuilder debug) {
-        super.debugData(debug);
-        debug.appendTitle("Threads based Contexts");
-        for (final Map.Entry<Thread, IsisSession> entry : sessionsByThread.entrySet()) {
-            final Thread thread = entry.getKey();
-            final IsisSession data = entry.getValue();
-            debug.appendln(thread.toString(), data);
-        }
-    }
-
-
-    // /////////////////////////////////////////////////////////
-    // open, close
-    // /////////////////////////////////////////////////////////
-
-    @Override
-    protected IsisSession getSessionInstance(final String executionContextId) {
-        for (final IsisSession data : sessionsByThread.values()) {
-            if (data.getId().equals(executionContextId)) {
-                return data;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Is only intended to be called through
-     * {@link IsisContext#openSession(AuthenticationSession)}.
-     * 
-     * <p>
-     * Implementation note: an alternative design would have just been to bind
-     * onto a thread local.
-     */
-    @Override
-    public IsisSession openSessionInstance(final AuthenticationSession authenticationSession) {
-        final Thread thread = Thread.currentThread();
-        synchronized (sessionsByThread) {
-            applySessionClosePolicy();
-            final IsisSession session = getSessionFactoryInstance().openSession(authenticationSession);
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("  opening session " + session + " (count " + sessionsByThread.size() + ") for " + authenticationSession.getUserName());
-            }
-            saveSession(thread, session);
-            session.open();
-            return session;
-        }
-    }
-
-    private IsisSession saveSession(final Thread thread, final IsisSession session) {
-        synchronized (sessionsByThread) {
-            sessionsByThread.put(thread, session);
-        }
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("  saving session " + session + "; now have " + sessionsByThread.size() + " sessions");
-        }
-        return session;
-    }
-
-    // /////////////////////////////////////////////////////////
-    // getCurrent() (Hook)
-    // /////////////////////////////////////////////////////////
-
-    /**
-     * Get {@link IsisSession execution context} used by the current thread.
-     * 
-     * @see #openSessionInstance(AuthenticationSession)
-     */
-    @Override
-    public IsisSession getSessionInstance() {
-        final Thread thread = Thread.currentThread();
-        return sessionsByThread.get(thread);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee58bb0c/core/runtime/src/test/java/org/apache/isis/core/runtime/context/IsisContextTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/context/IsisContextTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/context/IsisContextTest.java
deleted file mode 100644
index 51afc3a..0000000
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/context/IsisContextTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.runtime.context;
-
-import java.util.Collections;
-import java.util.List;
-import org.jmock.Expectations;
-import org.jmock.auto.Mock;
-import org.junit.*;
-import org.apache.isis.applib.DomainObjectContainer;
-import org.apache.isis.core.commons.authentication.AuthenticationSession;
-import org.apache.isis.core.commons.config.IsisConfiguration;
-import org.apache.isis.core.commons.config.IsisConfigurationDefault;
-import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
-import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
-import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
-import org.apache.isis.core.runtime.authentication.AuthenticationManager;
-import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
-import org.apache.isis.core.runtime.authorization.AuthorizationManager;
-import org.apache.isis.core.runtime.system.persistence.PersistenceSessionFactory;
-import org.apache.isis.core.runtime.system.DeploymentType;
-import org.apache.isis.core.runtime.system.context.IsisContext;
-import org.apache.isis.core.runtime.system.context.IsisContextStatic;
-import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
-import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
-
-public class IsisContextTest {
-
-    @Rule
-    public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
-    
-
-    private IsisConfiguration configuration;
-    
-    @Mock
-    private PersistenceSession mockPersistenceSession;
-    
-    @Mock
-    private SpecificationLoaderSpi mockSpecificationLoader;
-
-    @Mock
-    protected ServicesInjectorSpi mockServicesInjector;
-    @Mock
-    protected PersistenceSessionFactory mockPersistenceSessionFactory;
-    @Mock
-    protected AuthenticationManager mockAuthenticationManager;
-    @Mock
-    protected AuthorizationManager mockAuthorizationManager;
-
-    @Mock
-    protected DomainObjectContainer mockContainer;
-    
-    protected OidMarshaller oidMarshaller;
-
-    private List<Object> servicesList;
-
-
-    private AuthenticationSession authSession;
-
-
-    private IsisSessionFactory sessionFactory;
-
-    @Before
-    public void setUp() throws Exception {
-        IsisContext.testReset();
-
-        servicesList = Collections.emptyList();
-
-        configuration = new IsisConfigurationDefault();
-        
-        oidMarshaller = new OidMarshaller();
-        
-        context.ignoring(
-                mockPersistenceSession,
-                mockSpecificationLoader,
-                mockAuthenticationManager,
-                mockAuthorizationManager,
-                mockContainer);
-
-        sessionFactory = new IsisSessionFactory(DeploymentType.UNIT_TESTING, configuration, mockServicesInjector,
-                mockSpecificationLoader, mockAuthenticationManager, mockAuthorizationManager, mockPersistenceSessionFactory);
-        authSession = new SimpleSession("tester", Collections.<String>emptyList());
-        
-        IsisContext.setConfiguration(configuration);
-    }
-    
-    @After
-    public void tearDown() throws Exception {
-        if(IsisContext.inSession()) {
-            IsisContext.closeSession();
-        }
-    }
-    
-    @Test
-    public void getConfiguration() {
-        IsisContextStatic.createRelaxedInstance(sessionFactory);
-
-        Assert.assertEquals(configuration, IsisContext.getConfiguration());
-    }
-
-    @Test
-    public void openSession_getSpecificationLoader() {
-        IsisContextStatic.createRelaxedInstance(sessionFactory);
-
-        // expecting
-        context.checking(new Expectations() {{
-            one(mockPersistenceSessionFactory)
-                    .createPersistenceSession(mockServicesInjector, mockSpecificationLoader, authSession);
-            will(returnValue(mockPersistenceSession));
-        }});
-
-        IsisContext.openSession(authSession);
-
-        Assert.assertEquals(mockSpecificationLoader, IsisContext.getSpecificationLoader());
-        Assert.assertEquals(authSession, IsisContext.getAuthenticationSession());
-        final PersistenceSession persistenceSession = IsisContext.getPersistenceSession();
-        Assert.assertNotNull(persistenceSession);
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/ee58bb0c/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/isis/DeploymentTypeAbstract.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/isis/DeploymentTypeAbstract.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/isis/DeploymentTypeAbstract.java
index cfca7c6..7076e5a 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/isis/DeploymentTypeAbstract.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/isis/DeploymentTypeAbstract.java
@@ -20,18 +20,12 @@
 package org.apache.isis.viewer.wicket.viewer.integration.isis;
 
 import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
-import org.apache.isis.core.runtime.system.ContextCategory;
 import org.apache.isis.core.runtime.system.DeploymentType;
 
-/**
- * Simple adapter for Isis' {@link DeploymentType} class, specifying that the
- * {@link ContextCategory#THREADLOCAL} is used as the
- * {@link ContextCategory}.
- */
 public abstract class DeploymentTypeAbstract extends DeploymentType {
 
     public DeploymentTypeAbstract(final String name, final DeploymentCategory category) {
-        super(name, category, ContextCategory.THREADLOCAL);
+        super(name, category);
     }
 
 }


[4/4] isis git commit: ISIS-993: metadata classes, facet factory, starting on the wicket component

Posted by da...@apache.org.
ISIS-993: metadata classes, facet factory, starting on the wicket component


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

Branch: refs/heads/ISIS-993
Commit: 599e179d8146ab08a394dd9796d7c90568344de6
Parents: e86e7ad
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Wed Jan 6 08:59:52 2016 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Wed Jan 6 08:59:52 2016 +0000

----------------------------------------------------------------------
 .../schema/applib/layout/layout-1.0.xsd         | 210 +++++++++++++++++++
 .../asciidoc/schema/applib/layout/layout.xsd    | 210 +++++++++++++++++++
 .../isis/applib/annotation/ActionLayout.java    |   8 +
 .../isis/applib/annotation/BookmarkPolicy.java  |   5 +
 .../applib/annotation/CollectionLayout.java     |   4 +-
 .../isis/applib/annotation/Contributed.java     |   5 +
 .../isis/applib/annotation/LabelPosition.java   |   5 +
 .../isis/applib/annotation/RenderType.java      |   5 +
 .../apache/isis/applib/annotation/Where.java    |   5 +
 .../isis/applib/annotation/package-info.java    |  31 ---
 .../apache/isis/applib/layout/v1_0/Action.java  |  62 ++++++
 .../isis/applib/layout/v1_0/ActionLayout.java   | 161 ++++++++++++++
 .../isis/applib/layout/v1_0/Collection.java     |  79 +++++++
 .../applib/layout/v1_0/CollectionLayout.java    | 148 +++++++++++++
 .../apache/isis/applib/layout/v1_0/Column.java  |  76 +++++++
 .../isis/applib/layout/v1_0/DomainObject.java   |  69 ++++++
 .../isis/applib/layout/v1_0/Property.java       |  77 +++++++
 .../isis/applib/layout/v1_0/PropertyGroup.java  |  86 ++++++++
 .../isis/applib/layout/v1_0/PropertyLayout.java | 147 +++++++++++++
 .../org/apache/isis/applib/layout/v1_0/Tab.java |  81 +++++++
 .../isis/applib/layout/v1_0/TabGroup.java       |  46 ++++
 .../isis/applib/layout/v1_0/package-info.java   |  25 +++
 .../jaxb/CatalogingSchemaOutputResolver.java    |  83 ++++++++
 .../isis/applib/services/jaxb/JaxbService.java  | 152 +++++++++++++-
 .../services/jaxb/StreamResultWithWriter.java   |  45 ++++
 .../DomainServiceLayoutFacetFactory.java        |  84 ++++++++
 .../DomainServiceLayoutFactory.java             |  84 --------
 .../facets/object/layoutxml/LayoutXmlFacet.java |  32 +++
 .../object/layoutxml/LayoutXmlFacetDefault.java |  85 ++++++++
 .../object/layoutxml/LayoutXmlFacetFactory.java |  98 +++++++++
 .../dflt/ProgrammingModelFacetsJava5.java       |   7 +-
 .../DomainServiceLayoutFacetFactoryTest.java    | 129 ++++++++++++
 .../DomainServiceLayoutFactoryTest.java         | 129 ------------
 .../layoutxml/v1_0/DomainObjectTest.java        | 101 +++++++++
 .../jaxb/CatalogingSchemaOutputResolver.java    |  85 --------
 .../services/jaxb/JaxbServiceDefault.java       | 111 +---------
 .../services/jaxb/StreamResultWithWriter.java   |  45 ----
 .../ComponentFactoryRegistrarDefault.java       |  28 ++-
 .../entity/EntityComponentFactoryAbstract.java  |  14 +-
 .../entity/tabbed/EntityTabbedPanel.html        |  27 +++
 .../entity/tabbed/EntityTabbedPanel.java        |  59 ++++++
 .../entity/tabbed/EntityTabbedPanelFactory.java |  56 +++++
 .../dom/simple/SimpleObject.layout.xml          |  44 ++++
 43 files changed, 2557 insertions(+), 486 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..97ab131
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout-1.0.xsd
@@ -0,0 +1,210 @@
+<?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:complexType name="domainObject">
+    <xs:sequence>
+      <xs:element name="actions">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="tabGroups">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="tabGroup" type="tns:tabGroup" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="action">
+    <xs:sequence>
+      <xs:element name="layout" type="tns:actionLayout"/>
+    </xs:sequence>
+    <xs:attribute name="identifier" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="actionLayout">
+    <xs:sequence>
+      <xs:element name="bookmarking" type="tns:bookmarkPolicy" default="NEVER" minOccurs="0"/>
+      <xs:element name="cssClass" type="xs:string" minOccurs="0"/>
+      <xs:element name="cssClassFa" type="xs:string" minOccurs="0"/>
+      <xs:element name="cssClassFaPosition" type="tns:cssClassFaPosition" minOccurs="0"/>
+      <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="hidden" type="tns:where" minOccurs="0"/>
+      <xs:element name="named" type="xs:string" minOccurs="0"/>
+      <xs:element name="namedEscaped" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="position" type="tns:position" default="BELOW"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="tabGroup">
+    <xs:sequence>
+      <xs:element name="tabs">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="tab" type="tns:tab" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="tab">
+    <xs:sequence>
+      <xs:element name="name" type="xs:string" minOccurs="0"/>
+      <xs:element name="left" type="tns:column"/>
+      <xs:element name="middle" type="tns:column" minOccurs="0"/>
+      <xs:element name="right" type="tns:column" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="column">
+    <xs:sequence>
+      <xs:element name="span" type="xs:int" default="4"/>
+      <xs:element name="propertyGroups">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="propertyGroup" type="tns:propertyGroup" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="collections">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="collection" type="tns:collection" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="propertyGroup">
+    <xs:sequence>
+      <xs:element name="actions">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="properties">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="property" type="tns:property" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="name" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="property">
+    <xs:sequence>
+      <xs:element name="layout" type="tns:propertyLayout"/>
+      <xs:element name="actions" minOccurs="0">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="identifier" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="propertyLayout">
+    <xs:sequence>
+      <xs:element name="cssClass" type="xs:string" minOccurs="0"/>
+      <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="hidden" type="tns:where" minOccurs="0"/>
+      <xs:element name="labelPosition" type="tns:labelPosition" default="LEFT"/>
+      <xs:element name="multiLine" type="xs:int" minOccurs="0"/>
+      <xs:element name="named" type="xs:string" minOccurs="0"/>
+      <xs:element name="namedEscaped" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="renderedAsDayBefore" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="typicalLength" type="xs:int" default="-1"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="collection">
+    <xs:sequence>
+      <xs:element name="layout" type="tns:collectionLayout"/>
+      <xs:element name="actions">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="identifier" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="collectionLayout">
+    <xs:sequence>
+      <xs:element name="cssClass" type="xs:string" minOccurs="0"/>
+      <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="defaultView" type="xs:string" default="table"/>
+      <xs:element name="hidden" type="tns:where" minOccurs="0"/>
+      <xs:element name="named" type="xs:string" minOccurs="0"/>
+      <xs:element name="namedEscaped" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="paged" type="xs:int" minOccurs="0"/>
+      <xs:element name="sortedBy" type="xs:string" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:simpleType name="bookmarkPolicy">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="AS_ROOT"/>
+      <xs:enumeration value="AS_CHILD"/>
+      <xs:enumeration value="NEVER"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="cssClassFaPosition">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="LEFT"/>
+      <xs:enumeration value="RIGHT"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="where">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="EVERYWHERE"/>
+      <xs:enumeration value="ANYWHERE"/>
+      <xs:enumeration value="OBJECT_FORMS"/>
+      <xs:enumeration value="REFERENCES_PARENT"/>
+      <xs:enumeration value="PARENTED_TABLES"/>
+      <xs:enumeration value="STANDALONE_TABLES"/>
+      <xs:enumeration value="ALL_TABLES"/>
+      <xs:enumeration value="ALL_EXCEPT_STANDALONE_TABLES"/>
+      <xs:enumeration value="NOWHERE"/>
+      <xs:enumeration value="NOT_SPECIFIED"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="position">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="BELOW"/>
+      <xs:enumeration value="RIGHT"/>
+      <xs:enumeration value="PANEL"/>
+      <xs:enumeration value="PANEL_DROPDOWN"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="labelPosition">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="DEFAULT"/>
+      <xs:enumeration value="LEFT"/>
+      <xs:enumeration value="RIGHT"/>
+      <xs:enumeration value="TOP"/>
+      <xs:enumeration value="NONE"/>
+    </xs:restriction>
+  </xs:simpleType>
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..97ab131
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/schema/applib/layout/layout.xsd
@@ -0,0 +1,210 @@
+<?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:complexType name="domainObject">
+    <xs:sequence>
+      <xs:element name="actions">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="tabGroups">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="tabGroup" type="tns:tabGroup" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="action">
+    <xs:sequence>
+      <xs:element name="layout" type="tns:actionLayout"/>
+    </xs:sequence>
+    <xs:attribute name="identifier" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="actionLayout">
+    <xs:sequence>
+      <xs:element name="bookmarking" type="tns:bookmarkPolicy" default="NEVER" minOccurs="0"/>
+      <xs:element name="cssClass" type="xs:string" minOccurs="0"/>
+      <xs:element name="cssClassFa" type="xs:string" minOccurs="0"/>
+      <xs:element name="cssClassFaPosition" type="tns:cssClassFaPosition" minOccurs="0"/>
+      <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="hidden" type="tns:where" minOccurs="0"/>
+      <xs:element name="named" type="xs:string" minOccurs="0"/>
+      <xs:element name="namedEscaped" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="position" type="tns:position" default="BELOW"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="tabGroup">
+    <xs:sequence>
+      <xs:element name="tabs">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="tab" type="tns:tab" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="tab">
+    <xs:sequence>
+      <xs:element name="name" type="xs:string" minOccurs="0"/>
+      <xs:element name="left" type="tns:column"/>
+      <xs:element name="middle" type="tns:column" minOccurs="0"/>
+      <xs:element name="right" type="tns:column" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="column">
+    <xs:sequence>
+      <xs:element name="span" type="xs:int" default="4"/>
+      <xs:element name="propertyGroups">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="propertyGroup" type="tns:propertyGroup" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="collections">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="collection" type="tns:collection" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="propertyGroup">
+    <xs:sequence>
+      <xs:element name="actions">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="properties">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="property" type="tns:property" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="name" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="property">
+    <xs:sequence>
+      <xs:element name="layout" type="tns:propertyLayout"/>
+      <xs:element name="actions" minOccurs="0">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="identifier" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="propertyLayout">
+    <xs:sequence>
+      <xs:element name="cssClass" type="xs:string" minOccurs="0"/>
+      <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="hidden" type="tns:where" minOccurs="0"/>
+      <xs:element name="labelPosition" type="tns:labelPosition" default="LEFT"/>
+      <xs:element name="multiLine" type="xs:int" minOccurs="0"/>
+      <xs:element name="named" type="xs:string" minOccurs="0"/>
+      <xs:element name="namedEscaped" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="renderedAsDayBefore" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="typicalLength" type="xs:int" default="-1"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="collection">
+    <xs:sequence>
+      <xs:element name="layout" type="tns:collectionLayout"/>
+      <xs:element name="actions">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="action" type="tns:action" minOccurs="0" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="identifier" type="xs:string" use="required"/>
+  </xs:complexType>
+
+  <xs:complexType name="collectionLayout">
+    <xs:sequence>
+      <xs:element name="cssClass" type="xs:string" minOccurs="0"/>
+      <xs:element name="describedAs" type="xs:string" minOccurs="0"/>
+      <xs:element name="defaultView" type="xs:string" default="table"/>
+      <xs:element name="hidden" type="tns:where" minOccurs="0"/>
+      <xs:element name="named" type="xs:string" minOccurs="0"/>
+      <xs:element name="namedEscaped" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="paged" type="xs:int" minOccurs="0"/>
+      <xs:element name="sortedBy" type="xs:string" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:simpleType name="bookmarkPolicy">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="AS_ROOT"/>
+      <xs:enumeration value="AS_CHILD"/>
+      <xs:enumeration value="NEVER"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="cssClassFaPosition">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="LEFT"/>
+      <xs:enumeration value="RIGHT"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="where">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="EVERYWHERE"/>
+      <xs:enumeration value="ANYWHERE"/>
+      <xs:enumeration value="OBJECT_FORMS"/>
+      <xs:enumeration value="REFERENCES_PARENT"/>
+      <xs:enumeration value="PARENTED_TABLES"/>
+      <xs:enumeration value="STANDALONE_TABLES"/>
+      <xs:enumeration value="ALL_TABLES"/>
+      <xs:enumeration value="ALL_EXCEPT_STANDALONE_TABLES"/>
+      <xs:enumeration value="NOWHERE"/>
+      <xs:enumeration value="NOT_SPECIFIED"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="position">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="BELOW"/>
+      <xs:enumeration value="RIGHT"/>
+      <xs:enumeration value="PANEL"/>
+      <xs:enumeration value="PANEL_DROPDOWN"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="labelPosition">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="DEFAULT"/>
+      <xs:enumeration value="LEFT"/>
+      <xs:enumeration value="RIGHT"/>
+      <xs:enumeration value="TOP"/>
+      <xs:enumeration value="NONE"/>
+    </xs:restriction>
+  </xs:simpleType>
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java
index 52a652f..d8255c5 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java
@@ -25,6 +25,8 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import javax.xml.bind.annotation.XmlType;
+
 /**
  * Layout hints for actions.
  */
@@ -72,6 +74,9 @@ public @interface ActionLayout {
      */
     CssClassFaPosition cssClassFaPosition() default CssClassFaPosition.LEFT;
 
+    @XmlType(
+            namespace = "http://isis.apache.org/schema/applib/layout"
+    )
     enum CssClassFaPosition {
         LEFT, RIGHT
     }
@@ -109,6 +114,9 @@ public @interface ActionLayout {
      */
     Position position() default Position.BELOW;
 
+    @XmlType(
+            namespace = "http://isis.apache.org/schema/applib/layout"
+    )
     enum Position {
         BELOW,
         RIGHT,

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/BookmarkPolicy.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/BookmarkPolicy.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/BookmarkPolicy.java
index 83a90f3..b6b1fb3 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/BookmarkPolicy.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/BookmarkPolicy.java
@@ -19,6 +19,11 @@
 
 package org.apache.isis.applib.annotation;
 
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(
+        namespace = "http://isis.apache.org/schema/applib/layout"
+)
 public enum BookmarkPolicy {
     /**
      * Can be bookmarked, and is a top-level 'root' (or parent) bookmark.

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/CollectionLayout.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/CollectionLayout.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/CollectionLayout.java
index 8216c66..d73f3c6 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/CollectionLayout.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/CollectionLayout.java
@@ -103,7 +103,7 @@ public @interface CollectionLayout {
      * If annotated on a type, then the page size refers to standalone
      * collections (eg as returned from a repository query).
      */
-    public int paged() default -1;
+    int paged() default -1;
 
 
     // //////////////////////////////////////
@@ -124,7 +124,7 @@ public @interface CollectionLayout {
      * There is some similarity between this concept and that of eager-loading as supported by some object stores.
      * </p>
      */
-    public RenderType render() default RenderType.LAZILY;
+    RenderType render() default RenderType.LAZILY;
 
 
     // //////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/Contributed.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Contributed.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Contributed.java
index 88c46ea..81821bb 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Contributed.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Contributed.java
@@ -19,9 +19,14 @@
 
 package org.apache.isis.applib.annotation;
 
+import javax.xml.bind.annotation.XmlType;
+
 /**
  * The means by which a domain service action will be contributed to a domain object.
  */
+@XmlType(
+    namespace = "http://isis.apache.org/schema/applib/layout"
+)
 public enum Contributed {
     /**
      * Default: contributed as both an action and also (if takes a single argument and has safe semantics) as an association

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/LabelPosition.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/LabelPosition.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/LabelPosition.java
index c4cdc10..a91d280 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/LabelPosition.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/LabelPosition.java
@@ -18,12 +18,17 @@
  */
 package org.apache.isis.applib.annotation;
 
+import javax.xml.bind.annotation.XmlType;
+
 /**
  * The positioning of a label for a property or action parameter.
  *
  * @see org.apache.isis.applib.annotation.PropertyLayout
  * @see org.apache.isis.applib.annotation.ParameterLayout
  */
+@XmlType(
+        namespace = "http://isis.apache.org/schema/applib/layout"
+)
 public enum LabelPosition {
     DEFAULT,
     LEFT,

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/RenderType.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/RenderType.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/RenderType.java
index 776f8f6..5363b38 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/RenderType.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/RenderType.java
@@ -18,6 +18,11 @@
  */
 package org.apache.isis.applib.annotation;
 
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(
+        namespace = "http://isis.apache.org/schema/applib/layout"
+)
 public enum RenderType {
     EAGERLY,
     LAZILY;

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/Where.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Where.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Where.java
index 5dbbded..e89403d 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Where.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Where.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.applib.annotation;
 
+import javax.xml.bind.annotation.XmlType;
+
 import org.apache.isis.applib.util.Enums;
 
 /**
@@ -38,6 +40,9 @@ import org.apache.isis.applib.util.Enums;
  * This enum is also used internally within the framework.  When rendering an element,
  * the framework developer should only use those values that represent concrete locations.  
  */
+@XmlType(
+        namespace = "http://isis.apache.org/schema/applib/layout"
+)
 public enum Where {
     /**
      * The member should be disabled/hidden everywhere.

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/annotation/package-info.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/package-info.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/package-info.java
deleted file mode 100644
index fbea3bc..0000000
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/package-info.java
+++ /dev/null
@@ -1,31 +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.
- */
-
-/**
- * This package defines all of the annotations that are recognized within
- * the default Isis programming model.
- * 
- * <p>
- * For example, {@link org.apache.isis.applib.annotation.Optional} is used to
- * indicate that a property or a parameter is optional rather than mandatory.
- * The {@link org.apache.isis.applib.annotation.MaxLength} annotation is used
- * to indicate the maximum length allowable for a (string) property or
- * parameter, or to indicate the maximum length of a (string-based) value type.
- */
-package org.apache.isis.applib.annotation;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..9037c04
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Action.java
@@ -0,0 +1,62 @@
+/*
+ *  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 javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(
+        propOrder = {
+                "identifier"
+                , "layout"
+        }
+)
+public class Action {
+
+
+    private String identifier;
+    /**
+     * Method name.
+     *
+     * <p>
+     *     Overloaded methods are not supported.
+     * </p>
+     */
+    @XmlAttribute(required = true)
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+
+
+    private ActionLayout layout = new ActionLayout();
+    @XmlElement(required = true)
+    public ActionLayout getLayout() {
+        return layout;
+    }
+
+    public void setLayout(ActionLayout layout) {
+        this.layout = layout;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayout.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayout.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayout.java
new file mode 100644
index 0000000..4fb4934
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ActionLayout.java
@@ -0,0 +1,161 @@
+/**
+ *  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 javax.xml.bind.annotation.XmlElement;
+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 = {
+                "bookmarking"
+                , "cssClass"
+                , "cssClassFa"
+                , "cssClassFaPosition"
+                , "describedAs"
+                , "hidden"
+                , "named"
+                , "namedEscaped"
+                , "position"
+        }
+)
+public class ActionLayout {
+
+    private BookmarkPolicy bookmarking = BookmarkPolicy.NEVER;
+
+    @XmlElement(required = false, defaultValue = "NEVER")
+    public BookmarkPolicy getBookmarking() {
+        return bookmarking;
+    }
+
+    public void setBookmarking(BookmarkPolicy bookmarking) {
+        this.bookmarking = bookmarking;
+    }
+
+
+    private String cssClass;
+
+    @XmlElement(required = false)
+    public String getCssClass() {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass) {
+        this.cssClass = cssClass;
+    }
+
+
+    private String cssClassFa;
+
+    @XmlElement(required = false)
+    public String getCssClassFa() {
+        return cssClassFa;
+    }
+
+    public void setCssClassFa(String cssClassFa) {
+        this.cssClassFa = cssClassFa;
+    }
+
+
+
+    private org.apache.isis.applib.annotation.ActionLayout.CssClassFaPosition cssClassFaPosition;
+
+    @XmlElement(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;
+
+    @XmlElement(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;
+
+    @XmlElement(required = false)
+    public Boolean getNamedEscaped() {
+        return namedEscaped;
+    }
+
+    public void setNamedEscaped(Boolean namedEscaped) {
+        this.namedEscaped = namedEscaped;
+    }
+
+
+
+    private org.apache.isis.applib.annotation.ActionLayout.Position position = org.apache.isis.applib.annotation.ActionLayout.Position.BELOW;
+
+    @XmlElement(required = true, defaultValue = "BELOW")
+    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;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..3796f5f
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Collection.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.layout.v1_0;
+
+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.XmlType;
+
+import com.google.common.collect.Lists;
+
+@XmlType(
+        propOrder = {
+                "identifier"
+                , "layout"
+                , "actions"
+        }
+)
+public class Collection {
+
+    private String identifier;
+
+    /**
+     * Collection identifier, being the getter method without "get" prefix, first letter lower cased.
+     */
+    @XmlAttribute(required = true)
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+
+
+    private CollectionLayout layout = new CollectionLayout();
+
+    @XmlElement(required = true)
+    public CollectionLayout getLayout() {
+        return layout;
+    }
+
+    public void setLayout(CollectionLayout layout) {
+        this.layout = layout;
+    }
+
+
+
+    private List<Action> actions = Lists.newArrayList();
+
+    @XmlElementWrapper(required = true)
+    @XmlElement(name = "action", required = false)
+    public List<Action> getActions() {
+        return actions;
+    }
+
+    public void setActions(List<Action> actions) {
+        this.actions = actions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayout.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayout.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayout.java
new file mode 100644
index 0000000..21c9273
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/CollectionLayout.java
@@ -0,0 +1,148 @@
+/**
+ *  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 javax.xml.bind.annotation.XmlElement;
+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 = {
+                "cssClass"
+                ,"describedAs"
+                ,"defaultView"
+                ,"hidden"
+                ,"named"
+                ,"namedEscaped"
+                ,"paged"
+                ,"sortedBy"
+        }
+)
+public class CollectionLayout {
+
+    private String cssClass;
+
+    @XmlElement(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 = "table";
+
+    /**
+     * 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>.
+     */
+    @XmlElement(required = true, defaultValue = "table")
+    public String getDefaultView() {
+        return defaultView;
+    }
+
+    public void setDefaultView(String defaultView) {
+        this.defaultView = defaultView;
+    }
+
+
+    private Where hidden;
+
+    @XmlElement(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;
+
+    @XmlElement(required = false)
+    public Boolean getNamedEscaped() {
+        return namedEscaped;
+    }
+
+    public void setNamedEscaped(Boolean namedEscaped) {
+        this.namedEscaped = namedEscaped;
+    }
+
+
+    private Integer paged;
+
+    @XmlElement(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;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..84534c0
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Column.java
@@ -0,0 +1,76 @@
+/*
+ *  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.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlType;
+
+import com.google.common.collect.Lists;
+
+@XmlType(
+        propOrder = {
+                "span"
+                , "propertyGroups"
+                , "collections"
+        }
+)
+public class Column {
+
+    private int span = 4;
+
+    @XmlElement(required = true, defaultValue = "4")
+    public int getSpan() {
+        return span;
+    }
+
+    public void setSpan(final int span) {
+        this.span = span;
+    }
+
+
+
+    private List<PropertyGroup> propertyGroups = Lists.newArrayList();
+
+    @XmlElementWrapper(required = true)
+    @XmlElement(name = "propertyGroup", required = false)
+    public List<PropertyGroup> getPropertyGroups() {
+        return propertyGroups;
+    }
+
+    public void setPropertyGroups(List<PropertyGroup> propertyGroups) {
+        this.propertyGroups = propertyGroups;
+    }
+
+
+
+    private List<Collection> collections = Lists.newArrayList();
+
+    @XmlElementWrapper(required = true)
+    @XmlElement(name = "collection", required = false)
+    public List<Collection> getCollections() {
+        return collections;
+    }
+
+    public void setCollections(List<Collection> collections) {
+        this.collections = collections;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..2ac2e54
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/DomainObject.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.layout.v1_0;
+
+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 com.google.common.collect.Lists;
+
+import org.apache.isis.applib.services.dto.Dto;
+
+@XmlRootElement
+@XmlType(
+        propOrder = {
+                "actions"
+                , "tabGroups"
+        }
+)
+public class DomainObject implements Dto {
+
+    private List<Action> actions = Lists.newArrayList();
+
+    @XmlElementWrapper(required = true)
+    @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());
+    }};
+
+    @XmlElementWrapper(required = true)
+    @XmlElement(name = "tabGroup", required = true)
+    public List<TabGroup> getTabGroups() {
+        return tabGroups;
+    }
+
+    public void setTabGroups(List<TabGroup> tabGroups) {
+        this.tabGroups = tabGroups;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..ed08541
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Property.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.layout.v1_0;
+
+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.XmlType;
+
+import com.google.common.collect.Lists;
+
+@XmlType(
+        propOrder = {
+                "identifier"
+                , "layout"
+                , "actions"
+        }
+)
+public class Property  {
+
+    private String identifier;
+
+    /**
+     * Property identifier, being the getter method without "get" or "is" prefix, first letter lower cased.
+     */
+    @XmlAttribute(required = true)
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+
+    private PropertyLayout layout = new PropertyLayout();
+
+    @XmlElement(required = true)
+    public PropertyLayout getLayout() {
+        return layout;
+    }
+
+    public void setLayout(PropertyLayout layout) {
+        this.layout = layout;
+    }
+
+
+    private List<Action> actions = Lists.newArrayList();
+
+    @XmlElementWrapper(required = false)
+    @XmlElement(name = "action", required = true)
+    public List<Action> getActions() {
+        return actions;
+    }
+
+    public void setActions(List<Action> actions) {
+        this.actions = actions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..f62c316
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java
@@ -0,0 +1,86 @@
+/*
+ *  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.util.ArrayList;
+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.XmlType;
+
+import com.google.common.collect.Lists;
+
+import org.apache.isis.applib.annotation.MemberOrder;
+
+@XmlType(
+        propOrder = {
+                "name"
+                , "actions"
+                , "properties"
+        }
+)
+public class PropertyGroup {
+
+    private String name;
+
+    /**
+     * Corresponds to the {@link MemberOrder#name()} (when applied to properties).
+     */
+    @XmlAttribute(required = true)
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+
+    private List<Action> actions = Lists.newArrayList();
+
+    @XmlElementWrapper(required = true)
+    @XmlElement(name = "action", required = false)
+    public List<Action> getActions() {
+        return actions;
+    }
+
+    public void setActions(List<Action> actions) {
+        this.actions = actions;
+    }
+
+
+
+    // must be at least one property in the property group
+    private List<Property> properties = new ArrayList<Property>() {{
+        add(new Property());
+    }};
+
+    @XmlElementWrapper(required = true)
+    @XmlElement(name = "property", required = true)
+    public List<Property> getProperties() {
+        return properties;
+    }
+
+    public void setProperties(List<Property> properties) {
+        this.properties = properties;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayout.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayout.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayout.java
new file mode 100644
index 0000000..0728c1f
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyLayout.java
@@ -0,0 +1,147 @@
+/**
+ *  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 javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.isis.applib.annotation.LabelPosition;
+import org.apache.isis.applib.annotation.Where;
+
+@XmlType(
+        propOrder = {
+                "cssClass"
+                , "describedAs"
+                , "hidden"
+                , "labelPosition"
+                , "multiLine"
+                , "named"
+                , "namedEscaped"
+                , "renderedAsDayBefore"
+                , "typicalLength"
+        }
+)
+public class PropertyLayout {
+
+    private String cssClass;
+
+    @XmlElement(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;
+
+    @XmlElement(required = false)
+    public Where getHidden() {
+        return hidden;
+    }
+
+    public void setHidden(Where hidden) {
+        this.hidden = hidden;
+    }
+
+
+    private LabelPosition labelPosition = LabelPosition.LEFT;
+
+    @XmlElement(required = true, defaultValue = "LEFT")
+    public LabelPosition getLabelPosition() {
+        return labelPosition;
+    }
+
+    public void setLabelPosition(LabelPosition labelPosition) {
+        this.labelPosition = labelPosition;
+    }
+
+
+    private Integer multiLine;
+
+    @XmlElement(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;
+
+    @XmlElement(required = false)
+    public Boolean getNamedEscaped() {
+        return namedEscaped;
+    }
+
+    public void setNamedEscaped(Boolean namedEscaped) {
+        this.namedEscaped = namedEscaped;
+    }
+
+
+    private Boolean renderedAsDayBefore;
+
+    @XmlElement(required = false)
+    public Boolean getRenderedAsDayBefore() {
+        return renderedAsDayBefore;
+    }
+
+    public void setRenderedAsDayBefore(Boolean renderedAsDayBefore) {
+        this.renderedAsDayBefore = renderedAsDayBefore;
+    }
+
+
+    private Integer typicalLength = -1;
+
+    @XmlElement(required = true, defaultValue = "-1")
+    public Integer getTypicalLength() {
+        return typicalLength;
+    }
+
+    public void setTypicalLength(Integer typicalLength) {
+        this.typicalLength = typicalLength;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..b8b311a
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/Tab.java
@@ -0,0 +1,81 @@
+/*
+ *  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 javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(
+        propOrder = {
+                "name"
+                , "left"
+                , "middle"
+                , "right"
+        }
+)
+public class Tab {
+
+    private String name;
+
+    @XmlElement(required = false)
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+
+    private Column left = new Column();
+
+    @XmlElement(required = true)
+    public Column getLeft() {
+        return left;
+    }
+
+    public void setLeft(final Column left) {
+        this.left = left;
+    }
+
+
+    private Column middle;
+
+    @XmlElement(required = false)
+    public Column getMiddle() {
+        return middle;
+    }
+
+    public void setMiddle(final Column middle) {
+        this.middle = middle;
+    }
+
+
+    private Column right;
+
+    @XmlElement(required = false)
+    public Column getRight() {
+        return right;
+    }
+
+    public void setRight(final Column right) {
+        this.right = right;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/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
new file mode 100644
index 0000000..3d57c19
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/TabGroup.java
@@ -0,0 +1,46 @@
+/*
+ *  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.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(
+        propOrder = {"tabs"}
+) public class TabGroup  {
+
+    // must be at least one tab.
+    private List<Tab> tabs = new ArrayList<Tab>(){{
+        add(new Tab());
+    }};
+
+    @XmlElementWrapper(required = true)
+    @XmlElement(name = "tab", required = true)
+    public List<Tab> getTabs() {
+        return tabs;
+    }
+
+    public void setTabs(List<Tab> tabs) {
+        this.tabs = tabs;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/package-info.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/package-info.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/package-info.java
new file mode 100644
index 0000000..f187ff2
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/package-info.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+@javax.xml.bind.annotation.XmlSchema(
+        namespace = "http://isis.apache.org/schema/applib/layout",
+        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED
+        // specifying the location seems to cause JaxbService#toXsd() to not generate the schema; not sure why...
+        //, location = "http://isis.apache.org/schema/metamodel/layout/layout-1.0.xsd"
+)
+package org.apache.isis.applib.layout.v1_0;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/CatalogingSchemaOutputResolver.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/CatalogingSchemaOutputResolver.java b/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/CatalogingSchemaOutputResolver.java
new file mode 100644
index 0000000..5d16c95
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/CatalogingSchemaOutputResolver.java
@@ -0,0 +1,83 @@
+/**
+ *  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.jaxb;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * An implementation of {@link SchemaOutputResolver} that keeps track of all the schemas for which it has
+ * {@link #createOutput(String, String) created} an output {@link StreamResult} containing the content of the schema.
+ */
+class CatalogingSchemaOutputResolver extends SchemaOutputResolver
+{
+    private final JaxbService.IsisSchemas isisSchemas;
+    private List<String> namespaceUris = Lists.newArrayList();
+
+    public CatalogingSchemaOutputResolver(final JaxbService.IsisSchemas isisSchemas) {
+        this.isisSchemas = isisSchemas;
+    }
+
+    public List<String> getNamespaceUris() {
+        return namespaceUris;
+    }
+
+    private Map<String, StreamResultWithWriter> schemaResultByNamespaceUri = Maps.newLinkedHashMap();
+
+    public String getSchemaTextFor(final String namespaceUri) {
+        final StreamResultWithWriter streamResult = schemaResultByNamespaceUri.get(namespaceUri);
+        return streamResult != null? streamResult.asString(): null;
+    }
+
+    @Override
+    public Result createOutput(
+            final String namespaceUri, final String suggestedFileName) throws IOException {
+
+        final StreamResultWithWriter result = new StreamResultWithWriter();
+
+        result.setSystemId(namespaceUri);
+
+        if (isisSchemas.shouldIgnore(namespaceUri)) {
+            // skip
+        } else {
+            namespaceUris.add(namespaceUri);
+            schemaResultByNamespaceUri.put(namespaceUri, result);
+        }
+
+        return result;
+    }
+
+    public Map<String, String> asMap() {
+        final Map<String,String> map = Maps.newLinkedHashMap();
+        final List<String> namespaceUris = getNamespaceUris();
+
+        for (String namespaceUri : namespaceUris) {
+            map.put(namespaceUri, getSchemaTextFor(namespaceUri));
+        }
+
+        return Collections.unmodifiableMap(map);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/JaxbService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/JaxbService.java b/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/JaxbService.java
index ed42609..ae0be24 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/JaxbService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/JaxbService.java
@@ -16,8 +16,27 @@
  */
 package org.apache.isis.applib.services.jaxb;
 
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.util.List;
 import java.util.Map;
 
+import javax.inject.Inject;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+
+import org.apache.isis.applib.ApplicationException;
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.NonRecoverableException;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.dto.Dto_downloadXsd;
 
@@ -26,7 +45,14 @@ public interface JaxbService {
     @Programmatic
     <T> T fromXml(Class<T> domainClass, String xml);
 
-    @Programmatic String toXml(final Object domainObject);
+    @Programmatic
+    <T> T fromXml(Class<T> domainClass, String xml, Map<String,Object> unmarshallerProperties);
+
+    @Programmatic
+    String toXml(final Object domainObject);
+
+    @Programmatic
+    String toXml(final Object domainObject, Map<String,Object> marshallerProperties);
 
 
     /**
@@ -60,4 +86,128 @@ public interface JaxbService {
 
     @Programmatic
     Map<String, String> toXsd(final Object domainObject, final IsisSchemas isisSchemas);
+
+
+    public static class Simple implements JaxbService {
+
+        @Override
+        public <T> T fromXml(final Class<T> domainClass, final String xml) {
+            return fromXml(domainClass, xml, Maps.<String,Object>newHashMap());
+        }
+        @Override
+        public <T> T fromXml(final Class<T> domainClass, final String xml, final Map<String, Object> unmarshallerProperties) {
+            try {
+                final JAXBContext context = JAXBContext.newInstance(domainClass);
+
+                final Unmarshaller unmarshaller = context.createUnmarshaller();
+
+                for (Map.Entry<String, Object> entry : unmarshallerProperties.entrySet()) {
+                    unmarshaller.setProperty(entry.getKey(), entry.getValue());
+                }
+
+                configure(unmarshaller);
+
+                final Object unmarshal = unmarshaller.unmarshal(new StringReader(xml));
+                return (T) unmarshal;
+
+            } catch (final JAXBException ex) {
+                throw new NonRecoverableException("Error unmarshalling domain object from XML; domain object class is '" + domainClass.getName() + "'", ex);
+            }
+        }
+
+        @Override
+        public String toXml(final Object domainObject) {
+            return toXml(domainObject, Maps.<String,Object>newHashMap());
+        }
+
+        @Override
+        public String toXml(final Object domainObject, final Map<String, Object> marshallerProperties)  {
+
+            final Class<?> domainClass = domainObject.getClass();
+            try {
+                final JAXBContext context = JAXBContext.newInstance(domainClass);
+
+                final Marshaller marshaller = context.createMarshaller();
+
+                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+                for (Map.Entry<String, Object> entry : marshallerProperties.entrySet()) {
+                    marshaller.setProperty(entry.getKey(), entry.getValue());
+                }
+
+                configure(marshaller);
+
+                final StringWriter sw = new StringWriter();
+                marshaller.marshal(domainObject, sw);
+                final String xml = sw.toString();
+
+                return xml;
+
+            } catch (final JAXBException ex) {
+                final Class<? extends JAXBException> exClass = ex.getClass();
+
+                final String name = exClass.getName();
+                if(name.equals("com.sun.xml.bind.v2.runtime.IllegalAnnotationsException")) {
+                    // report a better error if possible
+                    // this is done reflectively so as to not have to bring in a new Maven dependency
+                    List<? extends Exception> errors = null;
+                    String annotationExceptionMessages = null;
+                    try {
+                        final Method getErrorsMethod = exClass.getMethod("getErrors");
+                        errors = (List<? extends Exception>) getErrorsMethod.invoke(ex);
+                        annotationExceptionMessages = ": " + Joiner.on("; ").join(
+                                Iterables.transform(errors, new Function<Exception, String>() {
+                                    @Override public String apply(final Exception e) {
+                                        return e.getMessage();
+                                    }
+                                }));
+                    } catch (Exception e) {
+                        // fall through if we hit any snags, and instead throw the more generic error message.
+                    }
+                    if(errors != null) {
+                        throw new NonRecoverableException(
+                                "Error marshalling domain object to XML, due to illegal annotations on domain object class '"
+                                        + domainClass.getName() + "'; " + errors.size() + " error"
+                                        + (errors.size() == 1? "": "s")
+                                        + " reported" + (!errors
+                                        .isEmpty() ? annotationExceptionMessages : ""), ex);
+                    }
+                }
+
+                throw new NonRecoverableException("Error marshalling domain object to XML; domain object class is '" + domainClass.getName() + "'", ex);
+            }
+        }
+
+        /**
+         * Optional hook
+         */
+        protected void configure(final Unmarshaller unmarshaller) {
+        }
+
+        /**
+         * Optional hook
+         */
+        protected void configure(final Marshaller marshaller) {
+        }
+
+        public Map<String,String> toXsd(final Object domainObject, final IsisSchemas isisSchemas) {
+
+            try {
+                final Class<?> domainClass = domainObject.getClass();
+                final JAXBContext context = JAXBContext.newInstance(domainClass);
+
+                final CatalogingSchemaOutputResolver outputResolver = new CatalogingSchemaOutputResolver(isisSchemas);
+                context.generateSchema(outputResolver);
+
+                return outputResolver.asMap();
+            } catch (final JAXBException | IOException ex) {
+                throw new ApplicationException(ex);
+            }
+        }
+
+
+        @Inject
+        DomainObjectContainer container;
+    }
+
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/StreamResultWithWriter.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/StreamResultWithWriter.java b/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/StreamResultWithWriter.java
new file mode 100644
index 0000000..40db209
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/jaxb/StreamResultWithWriter.java
@@ -0,0 +1,45 @@
+/**
+ *  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.jaxb;
+
+import java.io.StringWriter;
+
+import javax.xml.transform.stream.StreamResult;
+
+/**
+ * A {@link StreamResult} that contains its own writer.
+ *
+ * <p>
+ *     The point is that the writer is only ever queried lazily AFTER the result has been generated.
+ * </p>
+ */
+class StreamResultWithWriter extends StreamResult {
+    private final StringWriter writer;
+
+    public StreamResultWithWriter() {
+        this(new StringWriter());
+    }
+
+    private StreamResultWithWriter(StringWriter writer) {
+        super(writer);
+        this.writer = writer;
+    }
+
+    public String asString() {
+        return writer.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFacetFactory.java
new file mode 100644
index 0000000..f9d75a4
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFacetFactory.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.facets.object.domainservicelayout;
+
+
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.DomainServiceLayout;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.Annotations;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.core.metamodel.facets.object.domainservicelayout.annotation.DomainServiceLayoutFacetAnnotation;
+
+
+public class DomainServiceLayoutFacetFactory extends FacetFactoryAbstract {
+
+    public DomainServiceLayoutFacetFactory() {
+        super(FeatureType.OBJECTS_ONLY);
+    }
+
+    @Override
+    public void process(ProcessClassContext processClassContext) {
+        final Class<?> cls = processClassContext.getCls();
+
+        final FacetHolder facetHolder = processClassContext.getFacetHolder();
+
+        final DomainService domainService = Annotations.getAnnotation(cls, DomainService.class);
+        final DomainServiceLayout domainServiceLayout = Annotations.getAnnotation(cls, DomainServiceLayout.class);
+
+        if (domainService == null && domainServiceLayout == null) {
+            return;
+        }
+
+        final String domainServiceMenuOrder =
+                domainService != null && !domainService.menuOrder().equals("" + Integer.MAX_VALUE)
+                        ? domainService.menuOrder()
+                        : null;
+        final String domainServiceLayoutMenuOrder =
+                domainServiceLayout != null && !domainServiceLayout.menuOrder().equals("" + Integer.MAX_VALUE)
+                        ? domainServiceLayout.menuOrder()
+                        : null;
+        final String menuOrder = coalesce(domainServiceLayoutMenuOrder, domainServiceMenuOrder);
+
+        DomainServiceLayout.MenuBar menuBar =
+                domainServiceLayout != null
+                        ? domainServiceLayout.menuBar()
+                        : DomainServiceLayout.MenuBar.PRIMARY;
+
+        FacetUtil.addFacet(
+                new DomainServiceLayoutFacetAnnotation(
+                        facetHolder,
+                        menuBar, menuOrder));
+
+        FacetUtil.addFacet(NamedFacetForDomainServiceLayoutAnnotation.create(domainServiceLayout, facetHolder));
+    }
+
+
+    private static String coalesce(final String... reasons) {
+        for (final String reason : reasons) {
+            if(reason != null) {
+                return reason;
+            }
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFactory.java
deleted file mode 100644
index 9803198..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/DomainServiceLayoutFactory.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.metamodel.facets.object.domainservicelayout;
-
-
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.annotation.DomainServiceLayout;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.FacetUtil;
-import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facets.Annotations;
-import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.object.domainservicelayout.annotation.DomainServiceLayoutFacetAnnotation;
-
-
-public class DomainServiceLayoutFactory extends FacetFactoryAbstract {
-
-    public DomainServiceLayoutFactory() {
-        super(FeatureType.OBJECTS_ONLY);
-    }
-
-    @Override
-    public void process(ProcessClassContext processClassContext) {
-        final Class<?> cls = processClassContext.getCls();
-
-        final FacetHolder facetHolder = processClassContext.getFacetHolder();
-
-        final DomainService domainService = Annotations.getAnnotation(cls, DomainService.class);
-        final DomainServiceLayout domainServiceLayout = Annotations.getAnnotation(cls, DomainServiceLayout.class);
-
-        if (domainService == null && domainServiceLayout == null) {
-            return;
-        }
-
-        final String domainServiceMenuOrder =
-                domainService != null && !domainService.menuOrder().equals("" + Integer.MAX_VALUE)
-                        ? domainService.menuOrder()
-                        : null;
-        final String domainServiceLayoutMenuOrder =
-                domainServiceLayout != null && !domainServiceLayout.menuOrder().equals("" + Integer.MAX_VALUE)
-                        ? domainServiceLayout.menuOrder()
-                        : null;
-        final String menuOrder = coalesce(domainServiceLayoutMenuOrder, domainServiceMenuOrder);
-
-        DomainServiceLayout.MenuBar menuBar =
-                domainServiceLayout != null
-                        ? domainServiceLayout.menuBar()
-                        : DomainServiceLayout.MenuBar.PRIMARY;
-
-        FacetUtil.addFacet(
-                new DomainServiceLayoutFacetAnnotation(
-                        facetHolder,
-                        menuBar, menuOrder));
-
-        FacetUtil.addFacet(NamedFacetForDomainServiceLayoutAnnotation.create(domainServiceLayout, facetHolder));
-    }
-
-
-    private static String coalesce(final String... reasons) {
-        for (final String reason : reasons) {
-            if(reason != null) {
-                return reason;
-            }
-        }
-        return null;
-    }
-
-}


[2/4] isis git commit: ISIS-1295: removing ContextReplacePolicy since no longer required either

Posted by da...@apache.org.
ISIS-1295: removing ContextReplacePolicy since no longer required either


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

Branch: refs/heads/ISIS-993
Commit: e86e7ad908d11da87b272986a726be81a899bdfc
Parents: ee58bb0
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Mon Jan 4 18:59:24 2016 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Mon Jan 4 18:59:24 2016 +0000

----------------------------------------------------------------------
 .../runtime/system/context/IsisContext.java     | 30 +++++---------------
 1 file changed, 7 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/e86e7ad9/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
index 9fe9b17..238d297 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
@@ -64,7 +64,6 @@ public class IsisContext implements DebuggableWithTitle {
     private static IsisContext singleton;
 
     private final IsisSessionFactory sessionFactory;
-    private final ContextReplacePolicy replacePolicy;
     private final SessionClosePolicy sessionClosePolicy;
 
     private static IsisConfiguration configuration;
@@ -108,35 +107,27 @@ public class IsisContext implements DebuggableWithTitle {
         AUTO_CLOSE
     }
 
-    /**
-     * Whether the {@link IsisContext#getInstance() singleton} itself may be
-     * replaced.
-     */
-    protected static enum ContextReplacePolicy {
-        NOT_REPLACEABLE, REPLACEABLE
-    }
-
 
     /**
      * Creates a new instance of the {@link IsisSession} holder.
      * 
      * <p>
-     * Will throw an exception if an instance has already been created and is
-     * not {@link ContextReplacePolicy#REPLACEABLE}.
+     * Will throw an exception if an instance has already been created.
      */
-    protected IsisContext(final ContextReplacePolicy replacePolicy, final SessionClosePolicy sessionClosePolicy, final IsisSessionFactory sessionFactory) {
-        if (singleton != null && !singleton.isContextReplaceable()) {
-            throw new IsisException("Isis Context already set up and cannot be replaced");
+    protected IsisContext(
+            final SessionClosePolicy sessionClosePolicy,
+            final IsisSessionFactory sessionFactory) {
+        if (singleton != null) {
+            throw new IsisException("Isis Context already set up");
         }
         singleton = this;
         this.sessionFactory = sessionFactory;
         this.sessionClosePolicy = sessionClosePolicy;
-        this.replacePolicy = replacePolicy;
     }
 
 
     protected IsisContext(final IsisSessionFactory sessionFactory) {
-        this(ContextReplacePolicy.NOT_REPLACEABLE, SessionClosePolicy.AUTO_CLOSE, sessionFactory);
+        this(SessionClosePolicy.AUTO_CLOSE, sessionFactory);
     }
 
 
@@ -168,13 +159,6 @@ public class IsisContext implements DebuggableWithTitle {
     // ///////////////////////////////////////////////////////////
 
     /**
-     * Whether a context singleton can simply be replaced or not.
-     */
-    public final boolean isContextReplaceable() {
-        return replacePolicy == ContextReplacePolicy.REPLACEABLE;
-    }
-
-    /**
      * Whether any open session can be automatically
      * {@link #closeSessionInstance() close}d on
      * {@link #openSessionInstance(AuthenticationSession) open}.


[3/4] isis git commit: ISIS-993: metadata classes, facet factory, starting on the wicket component

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

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java
new file mode 100644
index 0000000..3a391d7
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetDefault.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.facets.object.layoutxml;
+
+
+import java.util.List;
+
+import 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.applib.layout.v1_0.DomainObject;
+import org.apache.isis.applib.layout.v1_0.TabGroup;
+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.OneToOneAssociation;
+
+public class LayoutXmlFacetDefault
+            extends FacetAbstract
+            implements LayoutXmlFacet {
+
+    private final DomainObject metadata;
+
+    public static Class<? extends Facet> type() {
+        return LayoutXmlFacet.class;
+    }
+
+
+    public static LayoutXmlFacet create(
+            final FacetHolder facetHolder,
+            final DomainObject domainObject) {
+        if(domainObject == null) {
+            return null;
+        }
+        return new LayoutXmlFacetDefault(facetHolder, domainObject);
+    }
+
+    private LayoutXmlFacetDefault(
+            final FacetHolder facetHolder,
+            final DomainObject metadata) {
+        super(LayoutXmlFacetDefault.type(), facetHolder, Derivation.NOT_DERIVED);
+        this.metadata = metadata;
+    }
+
+
+    private boolean fleshedOut;
+
+    public DomainObject getLayoutMetadata() {
+        return fleshedOut? metadata : fleshOut(metadata);
+    }
+
+    private  DomainObject fleshOut(final DomainObject metadata) {
+        synchronized (metadata) {
+            doFleshOut(metadata);
+            fleshedOut = true;
+        }
+        return metadata;
+    }
+
+    private void doFleshOut(final DomainObject metadata) {
+        ObjectSpecification objectSpec = (ObjectSpecification) getFacetHolder();
+        List<OneToOneAssociation> properties = getProperties(objectSpec);
+        List<TabGroup> tabGroups = metadata.getTabGroups();
+    }
+
+    private List getProperties(final ObjectSpecification objectSpec) {
+        return objectSpec
+                .getAssociations(Contributed.INCLUDED, OneToOneAssociation.Filters.PROPERTIES);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
new file mode 100644
index 0000000..17d4063
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutxml/LayoutXmlFacetFactory.java
@@ -0,0 +1,98 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License. */
+package org.apache.isis.core.metamodel.facets.object.layoutxml;
+
+import java.io.IOException;
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.core.commons.lang.ClassExtensions;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.applib.layout.v1_0.DomainObject;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjectorAware;
+
+public class LayoutXmlFacetFactory extends FacetFactoryAbstract implements ServicesInjectorAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LayoutXmlFacetFactory.class);
+
+    public LayoutXmlFacetFactory() {
+        super(FeatureType.OBJECTS_ONLY);
+    }
+
+    @Override
+    public void process(final ProcessClassContext processClassContext) {
+        final Class<?> cls = processClassContext.getCls();
+        final FacetHolder facetHolder = processClassContext.getFacetHolder();
+
+        FacetUtil.addFacet(LayoutXmlFacetDefault.create(facetHolder, readMetadata(cls)));
+    }
+
+    private final Set<Class<?>> blacklisted = Sets.newConcurrentHashSet();
+
+    private DomainObject readMetadata(final Class<?> domainClass) {
+
+        if(blacklisted.contains(domainClass)) {
+            return null;
+        }
+        final String xml;
+
+        final String resourceName = domainClass.getSimpleName() + ".layout.xml";
+        try {
+            xml = ClassExtensions.resourceContentOf(domainClass, resourceName);
+        } catch (IOException | IllegalArgumentException ex) {
+
+            blacklisted.add(domainClass);
+            final String message = String .format(
+                    "Failed to locate file %s (relative to %s.class); ex: %s)",
+                    resourceName, domainClass.getName(), ex.getMessage());
+
+            LOG.debug(message);
+            return null;
+        }
+
+        try {
+            final JaxbService jaxbService = servicesInjector.lookupService(JaxbService.class);
+            final DomainObject metadata = jaxbService.fromXml(DomainObject.class, xml);
+            return metadata;
+        } catch(Exception ex) {
+
+            // note that we don't blacklist if the file exists but couldn't be parsed;
+            // the developer might fix so we will want to retry.
+            final String message = "Failed to parse " + resourceName + " file (" + ex.getMessage() + ")";
+            LOG.warn(message);
+
+            return null;
+        }
+    }
+
+    private ServicesInjector servicesInjector;
+
+    @Override
+    public void setServicesInjector(final ServicesInjector servicesInjector) {
+        this.servicesInjector = servicesInjector;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index 621b75b..9fc19be 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -82,7 +82,7 @@ import org.apache.isis.core.metamodel.facets.object.disabled.method.DisabledObje
 import org.apache.isis.core.metamodel.facets.object.domainobject.DomainObjectAnnotationFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.domainobjectlayout.DomainObjectLayoutFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.domainservice.annotation.DomainServiceFacetAnnotationFactory;
-import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFactory;
+import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.encodeable.annotcfg.EncodableFacetAnnotationElseConfigurationFactory;
 import org.apache.isis.core.metamodel.facets.object.facets.annotation.FacetsFacetAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.object.fieldorder.annotation.FieldOrderFacetAnnotationFactory;
@@ -108,6 +108,7 @@ import org.apache.isis.core.metamodel.facets.object.ignore.jdo.RemoveJdoEnhancem
 import org.apache.isis.core.metamodel.facets.object.ignore.jdo.RemoveJdoPrefixedMethodsFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.immutable.immutableannot.CopyImmutableFacetOntoMembersFactory;
 import org.apache.isis.core.metamodel.facets.object.immutable.immutablemarkerifc.ImmutableFacetMarkerInterfaceFactory;
+import org.apache.isis.core.metamodel.facets.object.layoutxml.LayoutXmlFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.mask.annotation.MaskFacetOnTypeAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.object.maxlen.annotation.MaxLengthFacetOnTypeAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.object.membergroups.annotprop.MemberGroupLayoutFacetFactory;
@@ -390,7 +391,9 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
         // must come after DomainObjectAnnotationFacetFactory & MixinFacetFactory
         addFactory(NotContributedFacetDerivedFromMixinFacetFactory.class);
 
-        addFactory(DomainServiceLayoutFactory.class);
+        addFactory(LayoutXmlFacetFactory.class);
+
+        addFactory(DomainServiceLayoutFacetFactory.class);
         addFactory(DomainObjectLayoutFacetFactory.class);
         // must come after MultiLine
         addFactory(PropertyLayoutFacetFactory.class);

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFacetFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFacetFactoryTest.java
new file mode 100644
index 0000000..4460313
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFacetFactoryTest.java
@@ -0,0 +1,129 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.metamodel.facets.object.domainservicelayout.annotation;
+
+import org.junit.Assert;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.DomainServiceLayout;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryTest;
+import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessClassContext;
+import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet;
+import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacetFactory;
+
+import static org.hamcrest.Matchers.is;
+
+public class DomainServiceLayoutFacetFactoryTest extends AbstractFacetFactoryTest {
+
+    private DomainServiceLayoutFacetFactory facetFactory;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        facetFactory = new DomainServiceLayoutFacetFactory();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        facetFactory = null;
+        super.tearDown();
+    }
+
+    public void testAnnotationPickedUpOnClass() {
+        class Customer {
+        }
+        @DomainServiceLayout(menuOrder = "123" ,menuBar = DomainServiceLayout.MenuBar.SECONDARY)
+        class Customers {
+        }
+
+        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
+
+        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
+        assertNotNull(facet);
+        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
+        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
+        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
+        Assert.assertThat(domainServiceLayoutFacet.getMenuBar(), is(DomainServiceLayout.MenuBar.SECONDARY));
+
+        assertNoMethodsRemoved();
+    }
+
+
+    public void testDomainServiceMenuOrderAnnotationPickedUpOnClass() {
+        class Customer {
+        }
+        @DomainService(menuOrder = "123")
+        class Customers {
+        }
+
+        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
+
+        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
+        assertNotNull(facet);
+        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
+        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
+        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
+
+        assertNoMethodsRemoved();
+    }
+
+    public void testDomainServiceAndDomainServiceLayoutAnnotationWhenCompatiblePickedUpOnClass() {
+        class Customer {
+        }
+        @DomainService(menuOrder = "123")
+        @DomainServiceLayout(menuBar = DomainServiceLayout.MenuBar.SECONDARY)
+        class Customers {
+        }
+
+        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
+
+        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
+        assertNotNull(facet);
+        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
+        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
+        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
+        Assert.assertThat(domainServiceLayoutFacet.getMenuBar(), is(DomainServiceLayout.MenuBar.SECONDARY));
+
+        assertNoMethodsRemoved();
+    }
+
+    public void testDomainServiceAndDomainServiceLayoutAnnotationWhenIncompatiblePickedUpOnClass() {
+        class Customer {
+        }
+        @DomainService(menuOrder = "1")
+        @DomainServiceLayout(menuOrder = "123", menuBar = DomainServiceLayout.MenuBar.SECONDARY)
+        class Customers {
+        }
+
+        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
+
+        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
+        assertNotNull(facet);
+        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
+        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
+        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
+        Assert.assertThat(domainServiceLayoutFacet.getMenuBar(), is(DomainServiceLayout.MenuBar.SECONDARY));
+
+        assertNoMethodsRemoved();
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFactoryTest.java
deleted file mode 100644
index 6a65145..0000000
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/annotation/DomainServiceLayoutFactoryTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.metamodel.facets.object.domainservicelayout.annotation;
-
-import org.junit.Assert;
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.annotation.DomainServiceLayout;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryTest;
-import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessClassContext;
-import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet;
-import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFactory;
-
-import static org.hamcrest.Matchers.is;
-
-public class DomainServiceLayoutFactoryTest extends AbstractFacetFactoryTest {
-
-    private DomainServiceLayoutFactory facetFactory;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        facetFactory = new DomainServiceLayoutFactory();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        facetFactory = null;
-        super.tearDown();
-    }
-
-    public void testAnnotationPickedUpOnClass() {
-        class Customer {
-        }
-        @DomainServiceLayout(menuOrder = "123" ,menuBar = DomainServiceLayout.MenuBar.SECONDARY)
-        class Customers {
-        }
-
-        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
-
-        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
-        assertNotNull(facet);
-        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
-        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
-        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
-        Assert.assertThat(domainServiceLayoutFacet.getMenuBar(), is(DomainServiceLayout.MenuBar.SECONDARY));
-
-        assertNoMethodsRemoved();
-    }
-
-
-    public void testDomainServiceMenuOrderAnnotationPickedUpOnClass() {
-        class Customer {
-        }
-        @DomainService(menuOrder = "123")
-        class Customers {
-        }
-
-        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
-
-        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
-        assertNotNull(facet);
-        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
-        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
-        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
-
-        assertNoMethodsRemoved();
-    }
-
-    public void testDomainServiceAndDomainServiceLayoutAnnotationWhenCompatiblePickedUpOnClass() {
-        class Customer {
-        }
-        @DomainService(menuOrder = "123")
-        @DomainServiceLayout(menuBar = DomainServiceLayout.MenuBar.SECONDARY)
-        class Customers {
-        }
-
-        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
-
-        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
-        assertNotNull(facet);
-        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
-        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
-        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
-        Assert.assertThat(domainServiceLayoutFacet.getMenuBar(), is(DomainServiceLayout.MenuBar.SECONDARY));
-
-        assertNoMethodsRemoved();
-    }
-
-    public void testDomainServiceAndDomainServiceLayoutAnnotationWhenIncompatiblePickedUpOnClass() {
-        class Customer {
-        }
-        @DomainService(menuOrder = "1")
-        @DomainServiceLayout(menuOrder = "123", menuBar = DomainServiceLayout.MenuBar.SECONDARY)
-        class Customers {
-        }
-
-        facetFactory.process(new ProcessClassContext(Customers.class, null, methodRemover, facetHolder));
-
-        final Facet facet = facetHolder.getFacet(DomainServiceLayoutFacet.class);
-        assertNotNull(facet);
-        assertTrue(facet instanceof DomainServiceLayoutFacetAnnotation);
-        DomainServiceLayoutFacetAnnotation domainServiceLayoutFacet = (DomainServiceLayoutFacetAnnotation) facet;
-        Assert.assertThat(domainServiceLayoutFacet.getMenuOrder(), is("123"));
-        Assert.assertThat(domainServiceLayoutFacet.getMenuBar(), is(DomainServiceLayout.MenuBar.SECONDARY));
-
-        assertNoMethodsRemoved();
-    }
-
-
-}

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

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/CatalogingSchemaOutputResolver.java
----------------------------------------------------------------------
diff --git a/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/CatalogingSchemaOutputResolver.java b/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/CatalogingSchemaOutputResolver.java
deleted file mode 100644
index aac43d7..0000000
--- a/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/CatalogingSchemaOutputResolver.java
+++ /dev/null
@@ -1,85 +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.schema.services.jaxb;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.bind.SchemaOutputResolver;
-import javax.xml.transform.Result;
-import javax.xml.transform.stream.StreamResult;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import org.apache.isis.applib.services.jaxb.JaxbService;
-
-/**
- * An implementation of {@link SchemaOutputResolver} that keeps track of all the schemas for which it has
- * {@link #createOutput(String, String) created} an output {@link StreamResult} containing the content of the schema.
- */
-class CatalogingSchemaOutputResolver extends SchemaOutputResolver
-{
-    private final JaxbService.IsisSchemas isisSchemas;
-    private List<String> namespaceUris = Lists.newArrayList();
-
-    public CatalogingSchemaOutputResolver(final JaxbService.IsisSchemas isisSchemas) {
-        this.isisSchemas = isisSchemas;
-    }
-
-    public List<String> getNamespaceUris() {
-        return namespaceUris;
-    }
-
-    private Map<String, StreamResultWithWriter> schemaResultByNamespaceUri = Maps.newLinkedHashMap();
-
-    public String getSchemaTextFor(final String namespaceUri) {
-        final StreamResultWithWriter streamResult = schemaResultByNamespaceUri.get(namespaceUri);
-        return streamResult != null? streamResult.asString(): null;
-    }
-
-    @Override
-    public Result createOutput(
-            final String namespaceUri, final String suggestedFileName) throws IOException {
-
-        final StreamResultWithWriter result = new StreamResultWithWriter();
-
-        result.setSystemId(namespaceUri);
-
-        if (isisSchemas.shouldIgnore(namespaceUri)) {
-            // skip
-        } else {
-            namespaceUris.add(namespaceUri);
-            schemaResultByNamespaceUri.put(namespaceUri, result);
-        }
-
-        return result;
-    }
-
-    public Map<String, String> asMap() {
-        final Map<String,String> map = Maps.newLinkedHashMap();
-        final List<String> namespaceUris = getNamespaceUris();
-
-        for (String namespaceUri : namespaceUris) {
-            map.put(namespaceUri, getSchemaTextFor(namespaceUri));
-        }
-
-        return Collections.unmodifiableMap(map);
-    }
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/JaxbServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/JaxbServiceDefault.java b/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/JaxbServiceDefault.java
index 2d2bf79..3679fdb 100644
--- a/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/JaxbServiceDefault.java
+++ b/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/JaxbServiceDefault.java
@@ -16,26 +16,11 @@
  */
 package org.apache.isis.schema.services.jaxb;
 
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-
 import javax.inject.Inject;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Iterables;
-
-import org.apache.isis.applib.ApplicationException;
 import org.apache.isis.applib.DomainObjectContainer;
-import org.apache.isis.applib.NonRecoverableException;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.services.jaxb.JaxbService;
@@ -44,98 +29,20 @@ import org.apache.isis.schema.utils.jaxbadapters.PersistentEntityAdapter;
 @DomainService(
         nature = NatureOfService.DOMAIN
 )
-public class JaxbServiceDefault implements JaxbService {
-
-    @Override
-    public <T> T fromXml(final Class<T> domainClass, final String xml) {
-        try {
-            final JAXBContext context = JAXBContext.newInstance(domainClass);
-
-            final PersistentEntityAdapter adapter = new PersistentEntityAdapter();
-            container.injectServicesInto(adapter);
-
-            final Unmarshaller unmarshaller = context.createUnmarshaller();
-            unmarshaller.setAdapter(PersistentEntityAdapter.class, adapter);
-
-            final Object unmarshal = unmarshaller.unmarshal(new StringReader(xml));
-            return (T) unmarshal;
-
-        } catch (final JAXBException ex) {
-            throw new NonRecoverableException("Error unmarshalling domain object from XML; domain object class is '" + domainClass.getName() + "'", ex);
-        }
-    }
-
-    @Override
-    public String toXml(final Object domainObject)  {
-
-        final Class<?> domainClass = domainObject.getClass();
-        try {
-            final JAXBContext context = JAXBContext.newInstance(domainClass);
+public class JaxbServiceDefault extends JaxbService.Simple {
 
-            final PersistentEntityAdapter adapter = new PersistentEntityAdapter();
-            container.injectServicesInto(adapter);
-
-            final Marshaller marshaller = context.createMarshaller();
-            marshaller.setAdapter(PersistentEntityAdapter.class, adapter);
-            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
-
-            final StringWriter sw = new StringWriter();
-            marshaller.marshal(domainObject, sw);
-            final String xml = sw.toString();
-
-            return xml;
-
-        } catch (final JAXBException ex) {
-            final Class<? extends JAXBException> exClass = ex.getClass();
-
-            final String name = exClass.getName();
-            if(name.equals("com.sun.xml.bind.v2.runtime.IllegalAnnotationsException")) {
-                // report a better error if possible
-                // this is done reflectively so as to not have to bring in a new Maven dependency
-                List<? extends Exception> errors = null;
-                String annotationExceptionMessages = null;
-                try {
-                    final Method getErrorsMethod = exClass.getMethod("getErrors");
-                    errors = (List<? extends Exception>) getErrorsMethod.invoke(ex);
-                    annotationExceptionMessages = ": " + Joiner.on("; ").join(
-                            Iterables.transform(errors, new Function<Exception, String>() {
-                                @Override public String apply(final Exception e) {
-                                    return e.getMessage();
-                                }
-                            }));
-                } catch (Exception e) {
-                    // fall through if we hit any snags, and instead throw the more generic error message.
-                }
-                if(errors != null) {
-                    throw new NonRecoverableException(
-                            "Error marshalling domain object to XML, due to illegal annotations on domain object class '"
-                                    + domainClass.getName() + "'; " + errors.size() + " error"
-                                    + (errors.size() == 1? "": "s")
-                                    + " reported" + (!errors
-                                    .isEmpty() ? annotationExceptionMessages : ""), ex);
-                }
-            }
-
-            throw new NonRecoverableException("Error marshalling domain object to XML; domain object class is '" + domainClass.getName() + "'", ex);
-        }
+    protected void configure(final Unmarshaller unmarshaller) {
+        final PersistentEntityAdapter adapter = new PersistentEntityAdapter();
+        container.injectServicesInto(adapter);
+        unmarshaller.setAdapter(PersistentEntityAdapter.class, adapter);
     }
 
-    public Map<String,String> toXsd(final Object domainObject, final IsisSchemas isisSchemas) {
-
-        try {
-            final Class<?> domainClass = domainObject.getClass();
-            final JAXBContext context = JAXBContext.newInstance(domainClass);
-
-            final CatalogingSchemaOutputResolver outputResolver = new CatalogingSchemaOutputResolver(isisSchemas);
-            context.generateSchema(outputResolver);
-
-            return outputResolver.asMap();
-        } catch (final JAXBException | IOException ex) {
-            throw new ApplicationException(ex);
-        }
+    protected void configure(final Marshaller marshaller) {
+        final PersistentEntityAdapter adapter = new PersistentEntityAdapter();
+        container.injectServicesInto(adapter);
+        marshaller.setAdapter(PersistentEntityAdapter.class, adapter);
     }
 
-
     @Inject
     DomainObjectContainer container;
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/StreamResultWithWriter.java
----------------------------------------------------------------------
diff --git a/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/StreamResultWithWriter.java b/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/StreamResultWithWriter.java
deleted file mode 100644
index c07b49b..0000000
--- a/core/schema/src/main/java/org/apache/isis/schema/services/jaxb/StreamResultWithWriter.java
+++ /dev/null
@@ -1,45 +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.schema.services.jaxb;
-
-import java.io.StringWriter;
-
-import javax.xml.transform.stream.StreamResult;
-
-/**
- * A {@link StreamResult} that contains its own writer.
- *
- * <p>
- *     The point is that the writer is only ever queried lazily AFTER the result has been generated.
- * </p>
- */
-class StreamResultWithWriter extends StreamResult {
-    private final StringWriter writer;
-
-    public StreamResultWithWriter() {
-        this(new StringWriter());
-    }
-
-    private StreamResultWithWriter(StringWriter writer) {
-        super(writer);
-        this.writer = writer;
-    }
-
-    public String asString() {
-        return writer.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
index 479b474..f82698f 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
@@ -20,16 +20,18 @@
 package org.apache.isis.viewer.wicket.viewer.registries.components;
 
 import java.util.ServiceLoader;
+
 import com.google.inject.Singleton;
+
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistrar;
 import org.apache.isis.viewer.wicket.ui.components.about.AboutPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actionlink.ActionLinkPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.actionmenu.serviceactions.ServiceActionsPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actionmenu.serviceactions.TertiaryMenuPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionInfoPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionParametersFormPanelFactory;
-import org.apache.isis.viewer.wicket.ui.components.actionmenu.serviceactions.ServiceActionsPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.bookmarkedpages.BookmarkedPagesPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanelFactory;
@@ -44,9 +46,19 @@ import org.apache.isis.viewer.wicket.ui.components.entity.icontitle.EntityIconAn
 import org.apache.isis.viewer.wicket.ui.components.entity.icontitle.EntityIconTitleAndCopyLinkPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.entity.properties.EntityPropertiesPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.entity.selector.links.EntityLinksSelectorPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.entity.tabbed.EntityTabbedPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.footer.FooterPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.header.HeaderPanelFactory;
-import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.*;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisBlobPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisClobPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisColorPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisDatePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisDateTimePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisMoneyPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisPasswordPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisPercentagePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisTimePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisTimeStampPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlDatePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlTimePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlTimestampPanelFactory;
@@ -56,7 +68,14 @@ import org.apache.isis.viewer.wicket.ui.components.scalars.jdkmath.JavaMathBigIn
 import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.JodaDateTimePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.JodaLocalDatePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.JodaLocalDateTimePanelFactory;
-import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.*;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.BooleanPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.BytePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.CharacterPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.DoublePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.FloatPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.IntegerPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.LongPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.ShortPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.reference.ReferencePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.string.StringPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.value.ValuePanelFactory;
@@ -149,7 +168,8 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
 
         // top-level
         componentFactories.add(new EntityCombinedPanelFactory());
-        
+        componentFactories.add(new EntityTabbedPanelFactory()); // last one wins, apparently.
+
         // lower-level
         componentFactories.add(new EntityIconAndTitlePanelFactory());
         componentFactories.add(new EntityIconTitleAndCopyLinkPanelFactory());

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityComponentFactoryAbstract.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityComponentFactoryAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityComponentFactoryAbstract.java
index 6f7fa36..53ed51d 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityComponentFactoryAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityComponentFactoryAbstract.java
@@ -65,7 +65,19 @@ public abstract class EntityComponentFactoryAbstract extends ComponentFactoryAbs
         final ObjectSpecification specification = entityModel.getTypeOfSpecification();
         final boolean isObject = specification.isNotCollection();
         final boolean isValue = specification.containsFacet(ValueFacet.class);
-        return appliesIf(isObject && !isValue);
+        boolean b = isObject && !isValue;
+        if (!b) {
+            return ApplicationAdvice.DOES_NOT_APPLY;
+        }
+
+        return doAppliesTo(entityModel);
+    }
+
+    /**
+     * optional hook.
+     */
+    protected ApplicationAdvice doAppliesTo(final EntityModel entityModel) {
+        return ApplicationAdvice.APPLIES;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html
new file mode 100644
index 0000000..add01ab
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+         http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html xmlns:wicket="http://wicket.apache.org">
+<body>
+<wicket:panel>
+	<div class="entityTabbed">
+	</div>
+</wicket:panel>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java
new file mode 100644
index 0000000..0f23e3b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.entity.tabbed;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+/**
+ * {@link PanelAbstract Panel} to represent an entity on a single page made up
+ * of several &lt;div&gt; regions.
+ */
+public class EntityTabbedPanel extends PanelAbstract<EntityModel> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ID_ENTITY_PROPERTIES_AND_COLLECTIONS = "entityPropertiesAndCollections";
+
+    
+    public EntityTabbedPanel(final String id, final EntityModel entityModel) {
+        super(id, entityModel);
+        buildGui();
+    }
+
+    private void buildGui() {
+        final EntityModel model = getModel();
+        final ObjectAdapter objectAdapter = model.getObject();
+        final CssClassFacet facet = objectAdapter.getSpecification().getFacet(CssClassFacet.class);
+        if(facet != null) {
+            final String cssClass = facet.cssClass(objectAdapter);
+            CssClassAppender.appendCssClassTo(this, cssClass);
+        }
+
+//        addOrReplace(ComponentType.ENTITY_SUMMARY, model);
+//
+//        getComponentFactoryRegistry().addOrReplaceComponent(this, ID_ENTITY_PROPERTIES_AND_COLLECTIONS, ComponentType.ENTITY_PROPERTIES, model);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanelFactory.java
new file mode 100644
index 0000000..db69e65
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanelFactory.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.entity.tabbed;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+
+import org.apache.isis.core.metamodel.facets.object.layoutxml.LayoutXmlFacet;
+import org.apache.isis.core.metamodel.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;
+import org.apache.isis.viewer.wicket.ui.components.entity.EntityComponentFactoryAbstract;
+
+/**
+ * {@link ComponentFactory} for {@link EntityTabbedPanel}.
+ */
+public class EntityTabbedPanelFactory extends EntityComponentFactoryAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String NAME = "combined";
+
+    public EntityTabbedPanelFactory() {
+        super(ComponentType.ENTITY, NAME, EntityTabbedPanel.class);
+    }
+
+    @Override
+    protected ApplicationAdvice doAppliesTo(final EntityModel entityModel) {
+        final ObjectSpecification specification = entityModel.getTypeOfSpecification();
+        return appliesExclusivelyIf(specification.containsDoOpFacet(LayoutXmlFacet.class));
+    }
+
+    @Override
+    public Component createComponent(final String id, final IModel<?> model) {
+        final EntityModel entityModel = (EntityModel) model;
+        return new EntityTabbedPanel(id, entityModel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/599e179d/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
new file mode 100644
index 0000000..6cf4984
--- /dev/null
+++ b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<domainObject xsi:schemaLocation="http://isis.apache.org/schema/applib/layout http://isis.apache.org/schema/applib/layout/layout-1.0.xsd" xmlns="http://isis.apache.org/schema/applib/layout" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <actions>
+        <action identifier="delete">
+            <layout>
+                <bookmarking>NEVER</bookmarking>
+                <position>BELOW</position>
+            </layout>
+        </action>
+    </actions>
+    <tabGroups>
+        <tabGroup>
+            <tabs>
+                <tab>
+                    <left>
+                        <span>4</span>
+                        <propertyGroups>
+                            <propertyGroup name="General">
+                                <actions/>
+                                <properties>
+                                    <property identifier="name">
+                                        <layout>
+                                            <labelPosition>LEFT</labelPosition>
+                                            <typicalLength>-1</typicalLength>
+                                        </layout>
+                                        <actions>
+                                            <action identifier="updateName">
+                                                <layout>
+                                                    <bookmarking>NEVER</bookmarking>
+                                                    <position>BELOW</position>
+                                                </layout>
+                                            </action>
+                                        </actions>
+                                    </property>
+                                </properties>
+                            </propertyGroup>
+                        </propertyGroups>
+                        <collections/>
+                    </left>
+                </tab>
+            </tabs>
+        </tabGroup>
+    </tabGroups>
+</domainObject>