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 2015/03/30 17:43:38 UTC

[09/59] [abbrv] isis git commit: ISIS-720: mothballing scimpi

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugAction.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugAction.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugAction.java
new file mode 100644
index 0000000..8e5822d
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugAction.java
@@ -0,0 +1,257 @@
+/*
+ *  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.scimpi.dispatcher.debug;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.debug.DebugString;
+import org.apache.isis.core.commons.debug.DebuggableWithTitle;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.util.Dump;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.scimpi.dispatcher.Action;
+import org.apache.isis.viewer.scimpi.dispatcher.Dispatcher;
+import org.apache.isis.viewer.scimpi.dispatcher.ForbiddenException;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext.Scope;
+
+public class DebugAction implements Action {
+    private final Dispatcher dispatcher;
+
+    public DebugAction(final Dispatcher dispatcher) {
+        this.dispatcher = dispatcher;
+    }
+
+    @Override
+    public String getName() {
+        return "debug";
+    }
+
+    @Override
+    public void debug(final DebugBuilder debug) {
+    }
+
+    @Override
+    public void process(final RequestContext context) throws IOException {
+        if (context.isDebugDisabled()) {
+            throw new ForbiddenException("Can't access debug action when debug is disabled");
+        }
+
+        final String action = context.getParameter("action");
+        if ("list-i18n".equals(action)) {
+            i18n(context, null);
+        } else if ("list-authorization".equals(action)) {
+            authorization(context, null);
+        } else if (context.getParameter("mode") != null) {
+            final boolean isDebugOn = context.getParameter("mode").equals("debug");
+            context.addVariable("debug-on", isDebugOn, Scope.SESSION);
+            // TODO need to use configuration to find path
+            context.setRequestPath("/debug/debug.shtml");
+        } else {
+
+            // TODO remove - replaced by Debug tag
+            final DebugHtmlWriter view = new DebugHtmlWriter(context.getWriter(), true);
+            view.appendln("<div class=\"links\">");
+            view.appendln("<a href=\"debug.app?action=system\">System</a>");
+            view.appendln(" | <a href=\"debug.app?action=specifications\">List specifications</a>");
+            view.appendln(" | <a href=\"debug.app?action=list-i18n\">I18N File</a>");
+            view.appendln(" | <a href=\"debug.app?action=list-authorization\">Authorization File</a>");
+            view.appendln(" | <a href=\"debug.app?action=context\">Context</a>");
+            view.appendln(" | <a href=\"debug.app?action=dispatcher\">Dispatcher</a>");
+            view.appendln("</div>");
+
+            if ("specifications".equals(action)) {
+                listSpecifications(view);
+            } else if ("specification".equals(action)) {
+                // specification(context, view);
+            } else if ("object".equals(action)) {
+                object(context, view);
+            } else if ("system".equals(action)) {
+                system(context, view);
+            } else if ("context".equals(action)) {
+                context.append(view);
+            } else if ("dispatcher".equals(action)) {
+                dispatcher.debug(view);
+            }
+
+            context.clearRequestedPath();
+        }
+    }
+
+    private void object(final RequestContext context, final DebugHtmlWriter view) {
+        final ObjectAdapter object = context.getMappedObjectOrResult(context.getParameter("object"));
+        final DebugString str = new DebugString();
+        Dump.adapter(object, str);
+        Dump.graph(object, IsisContext.getAuthenticationSession(), str);
+        view.appendTitle(object.getSpecification().getFullIdentifier());
+        view.appendln("<pre class=\"debug\">" + str + "</pre>");
+    }
+
+    private void system(final RequestContext context, final DebugHtmlWriter view) {
+        final DebuggableWithTitle[] debug = IsisContext.debugSystem();
+        view.appendTitle("System");
+        for (final DebuggableWithTitle element2 : debug) {
+            final DebugString str = new DebugString();
+            element2.debugData(str);
+            view.appendTitle(element2.debugTitle());
+            view.appendln("<pre class=\"debug\">" + str + "</pre>");
+        }
+    }
+
+    private void i18n(final RequestContext context, final DebugHtmlWriter view) {
+        final Collection<ObjectSpecification> allSpecifications = getSpecificationLoader().allSpecifications();
+        final List<ObjectSpecification> specs = Lists.newArrayList(allSpecifications);
+        Collections.sort(specs, new Comparator<ObjectSpecification>() {
+            @Override
+            public int compare(final ObjectSpecification o1, final ObjectSpecification o2) {
+                return o1.getShortIdentifier().compareTo(o2.getShortIdentifier());
+            }
+        });
+        final Function<ObjectSpecification, String> className = ObjectSpecification.FUNCTION_FULLY_QUALIFIED_CLASS_NAME;
+        final List<String> fullIdentifierList = Lists.newArrayList(Collections2.transform(specs, className));
+        for (final String fullIdentifier : fullIdentifierList) {
+            final ObjectSpecification spec = getSpecificationLoader().loadSpecification(fullIdentifier);
+            if (spec.getAssociations(Contributed.EXCLUDED).size() == 0 && spec.getObjectActions(Contributed.EXCLUDED).size() == 0) {
+                continue;
+            }
+            final String name = spec.getIdentifier().toClassIdentityString();
+            context.getWriter().append("# " + spec.getShortIdentifier() + "\n");
+            for (final ObjectAssociation assoc : spec.getAssociations(Contributed.EXCLUDED)) {
+                context.getWriter().append("#" + name + ".property." + assoc.getId() + ".name" + "=\n");
+                context.getWriter().append("#" + name + ".property." + assoc.getId() + ".description" + "=\n");
+                context.getWriter().append("#" + name + ".property." + assoc.getId() + ".help" + "=\n");
+            }
+            for (final ObjectAction action : spec.getObjectActions(Contributed.EXCLUDED)) {
+                context.getWriter().append("#" + name + ".action." + action.getId() + ".name" + "=\n");
+                context.getWriter().append("#" + name + ".action." + action.getId() + ".description" + "=\n");
+                context.getWriter().append("#" + name + ".action." + action.getId() + ".help" + "=\n");
+            }
+            context.getWriter().append("\n");
+        }
+    }
+
+    private void authorization(final RequestContext context, final DebugHtmlWriter view) {
+        final Collection<ObjectSpecification> allSpecifications = getSpecificationLoader().allSpecifications();
+        final List<ObjectSpecification> specs = Lists.newArrayList(allSpecifications);
+        Collections.sort(specs, new Comparator<ObjectSpecification>() {
+            @Override
+            public int compare(final ObjectSpecification o1, final ObjectSpecification o2) {
+                return o1.getShortIdentifier().compareTo(o2.getShortIdentifier());
+            }
+        });
+        final Function<ObjectSpecification, String> className = ObjectSpecification.FUNCTION_FULLY_QUALIFIED_CLASS_NAME;
+        final List<String> fullIdentifierList = Lists.newArrayList(Collections2.transform(specs, className));
+        
+        for (final String fullIdentifier : fullIdentifierList) {
+            final ObjectSpecification spec = getSpecificationLoader().loadSpecification(fullIdentifier);
+            if (spec.getAssociations(Contributed.EXCLUDED).size() == 0 && spec.getObjectActions(Contributed.EXCLUDED).size() == 0) {
+                continue;
+            }
+            final String name = spec.getIdentifier().toClassIdentityString();
+            boolean isAbstract = spec.isAbstract();
+            context.getWriter().append("### " + spec.getShortIdentifier() + (isAbstract ? " (abstract)" : "") + " ###\n");
+            context.getWriter().append((isAbstract ? "#" : "") + name + ":roles\n\n");
+        }
+        context.getWriter().append("\n\n");
+        
+        for (final String fullIdentifier : fullIdentifierList) {
+            final ObjectSpecification spec = getSpecificationLoader().loadSpecification(fullIdentifier);
+            if (spec.getAssociations(Contributed.EXCLUDED).size() == 0 && spec.getObjectActions(Contributed.EXCLUDED).size() == 0) {
+                continue;
+            }
+            final String name = spec.getIdentifier().toClassIdentityString();
+            boolean isAbstract = spec.isAbstract();
+            context.getWriter().append("### " + spec.getShortIdentifier() + (isAbstract ? " (abstract)" : "") + " ###\n");
+            context.getWriter().append((isAbstract ? "#" : "") + name + ":roles\n");
+            for (final ObjectAssociation assoc : spec.getAssociations(Contributed.EXCLUDED)) {
+                context.getWriter().append("#" + name + "#" + assoc.getId() + ":roles\n");
+                // context.getWriter().append("#" + name + ".property." +
+                // assoc.getId() + ".description" + "=\n");
+                // context.getWriter().append("#" + name + ".property." +
+                // assoc.getId() + ".help" + "=\n");
+            }
+            for (final ObjectAction action : spec.getObjectActions(Contributed.EXCLUDED)) {
+                context.getWriter().append("#" + name + "#" + action.getId() + "():roles\n");
+                // context.getWriter().append("#" + name + ".action." +
+                // action.getId() + ".description" + "=\n");
+                // context.getWriter().append("#" + name + ".action." +
+                // action.getId() + ".help" + "=\n");
+            }
+            context.getWriter().append("\n");
+        }
+    }
+
+    private void listSpecifications(final DebugHtmlWriter view) {
+        final List<ObjectSpecification> fullIdentifierList = new ArrayList<ObjectSpecification>(getSpecificationLoader().allSpecifications());
+        Collections.sort(fullIdentifierList, ObjectSpecification.COMPARATOR_SHORT_IDENTIFIER_IGNORE_CASE);
+        view.appendTitle("Specifications");
+        for (final ObjectSpecification spec : fullIdentifierList) {
+            final String name = spec.getSingularName();
+            view.appendln(name, "");
+            // view.appendln(name, specificationLink(spec));
+        }
+
+        /*
+         * new Comparator<ObjectSpecification>() { public int
+         * compare(ObjectSpecification o1, ObjectSpecification o2) { return
+         * o1.getSingularName().compareTo(o2.getSingularName()); }});
+         * 
+         * /* Collection<ObjectSpecification> allSpecifications =
+         * getSpecificationLoader().allSpecifications(); Collection<String> list
+         * = Collections2.transform(allSpecifications,
+         * ObjectSpecification.COMPARATOR_SHORT_IDENTIFIER_IGNORE_CASE); final
+         * List<String> fullIdentifierList = Lists.newArrayList(list); /*
+         * Collections.sort(fullIdentifierList, new
+         * Comparator<ObjectSpecification>() { public int
+         * compare(ObjectSpecification o1, ObjectSpecification o2) { return
+         * o1.getSingularName().compareTo(o2.getSingularName()); }});
+         */
+        /*
+         * view.divider("Specifications"); for (String fullIdentifier :
+         * fullIdentifierList) { ObjectSpecification spec =
+         * getSpecificationLoader().loadSpecification(fullIdentifier); String
+         * name = spec.getSingularName(); view.appendRow(name,
+         * specificationLink(spec)); }
+         */
+    }
+
+    protected SpecificationLoaderSpi getSpecificationLoader() {
+        return IsisContext.getSpecificationLoader();
+    }
+
+    @Override
+    public void init() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugHtmlWriter.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugHtmlWriter.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugHtmlWriter.java
new file mode 100644
index 0000000..112bc77
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugHtmlWriter.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.viewer.scimpi.dispatcher.debug;
+
+import java.io.PrintWriter;
+
+import org.apache.isis.core.commons.debug.DebugHtmlStringAbstract;
+
+public class DebugHtmlWriter extends DebugHtmlStringAbstract {
+
+    private final PrintWriter writer;
+
+    public DebugHtmlWriter(final PrintWriter writer, final boolean createPage) {
+        super(createPage);
+        this.writer = writer;
+        header();
+    }
+
+    @Override
+    protected void appendHtml(final String html) {
+        writer.println(html);
+    }
+
+    @Override
+    protected void doClose() {
+        footer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUserAction.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUserAction.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUserAction.java
new file mode 100644
index 0000000..461ce84
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUserAction.java
@@ -0,0 +1,71 @@
+/*
+ *  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.scimpi.dispatcher.debug;
+
+import java.io.IOException;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.viewer.scimpi.dispatcher.Action;
+import org.apache.isis.viewer.scimpi.dispatcher.ForbiddenException;
+import org.apache.isis.viewer.scimpi.dispatcher.ScimpiException;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+
+public class DebugUserAction implements Action {
+
+    private final DebugUsers debugUsers;
+
+    public DebugUserAction(final DebugUsers debugUsers) {
+        this.debugUsers = debugUsers;
+    }
+
+    @Override
+    public String getName() {
+        return "debug-user";
+    }
+
+    @Override
+    public void debug(final DebugBuilder debug) {
+    }
+
+    @Override
+    public void process(final RequestContext context) throws IOException {
+        if (context.isDebugDisabled()) {
+            throw new ForbiddenException("Can't access debug action when debug is disabled");
+        }
+
+        final String method = context.getParameter(METHOD);
+        final String name = context.getParameter(NAME);
+        final String view = context.getParameter(VIEW);
+
+        if (method != null && method.equals("add")) {
+            debugUsers.add(name);
+        } else if (method != null && method.equals("remove")) {
+            debugUsers.remove(name);
+        } else {
+            throw new ScimpiException("Invalid debug-user action");
+        }
+
+        context.setRequestPath(view);
+    }
+
+    @Override
+    public void init() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsers.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsers.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsers.java
new file mode 100644
index 0000000..20497cc
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsers.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.viewer.scimpi.dispatcher.debug;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.config.ConfigurationConstants;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.scimpi.dispatcher.ScimpiException;
+
+public class DebugUsers {
+
+    private static Logger LOG = LoggerFactory.getLogger(DebugUsers.class);
+
+    private enum DebugMode {
+        OFF, ON, NAMED, SYSADMIN_ONLY
+    }
+
+    private static List<String> debugUsers = new ArrayList<String>();
+    private static DebugMode debugMode;
+
+    public void initialize() {
+        if (debugMode != null) {
+            throw new ScimpiException("Debug mode is already set up!");
+        }
+
+        final String debugUserEntry = IsisContext.getConfiguration().getString(ConfigurationConstants.ROOT + "scimpi.debug.users", "");
+        final String[] users = debugUserEntry.split("\\|");
+        for (final String name : users) {
+            debugUsers.add(name.trim());
+        }
+
+        final String debugModeEntry = IsisContext.getConfiguration().getString(ConfigurationConstants.ROOT + "scimpi.debug.mode");
+        if (debugModeEntry != null) {
+            try {
+                debugMode = DebugMode.valueOf(debugModeEntry.toUpperCase());
+                LOG.info("Debug mode set to " + debugMode);
+            } catch (final IllegalArgumentException e) {
+                LOG.error("Invalid debug mode - " + debugModeEntry + " - mode set to OFF");
+                debugMode = DebugMode.OFF;
+            }
+        } else {
+            debugMode = DebugMode.OFF;
+        }
+    }
+
+    public boolean isDebugEnabled(final AuthenticationSession session) {
+        if (debugMode == DebugMode.ON) {
+            return true;
+        } else if (session != null && debugMode == DebugMode.SYSADMIN_ONLY && session.getRoles().contains("sysadmin")) {
+            return true;
+        } else if (session != null && debugMode == DebugMode.NAMED && (debugUsers.contains(session.getUserName()) || session.getRoles().contains("sysadmin"))) {
+            return true;
+        }
+        return false;
+    }
+
+    public List<String> getNames() {
+        final ArrayList<String> users = new ArrayList<String>(debugUsers);
+        Collections.sort(users);
+        return users;
+    }
+
+    public void add(final String name) {
+        if (!debugUsers.contains(name)) {
+            debugUsers.add(name);
+            LOG.info("Added '" + debugMode + "' to debug users list");
+        }
+    }
+
+    public void remove(final String name) {
+        debugUsers.remove(name);
+        LOG.info("Removed '" + debugMode + "' from debug users list");
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsersView.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsersView.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsersView.java
new file mode 100644
index 0000000..360c48a
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/DebugUsersView.java
@@ -0,0 +1,50 @@
+/*
+ *  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.scimpi.dispatcher.debug;
+
+import org.apache.isis.viewer.scimpi.dispatcher.AbstractElementProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.Request;
+
+public class DebugUsersView extends AbstractElementProcessor {
+
+    @Override
+    public String getName() {
+        return "debug-users";
+    }
+
+    @Override
+    public void process(final Request request) {
+        final String view = request.getContext().getContextPath() + request.getContext().getResourceParentPath() + request.getContext().getResourceFile();
+
+        request.appendHtml("<form class=\"generic action\" action=\"debug-user.app\" method=\"post\" accept-charset=\"ISO-8859-1\">\n");
+        request.appendHtml("<div class=\"title\">Add Debug User</div>\n");
+        request.appendHtml("<div class=\"field\"><label>User Name:</label><input type=\"text\" name=\"name\" size=\"30\" /></div>\n");
+        request.appendHtml("<input type=\"hidden\" name=\"method\" value=\"add\" />\n");
+        request.appendHtml("<input type=\"hidden\" name=\"view\" value=\"" + view + "\" />\n");
+        request.appendHtml("<input class=\"button\" type=\"submit\" value=\"Add User\" />\n");
+        request.appendHtml("</form>\n");
+
+        request.appendHtml("<table class=\"debug\">\n<tr><th class=\"title\">Name</th><th class=\"title\"></th></tr>\n");
+        for (final String name : request.getContext().getDebugUsers()) {
+            request.appendHtml("<tr><th>" + name + "</th><th><a href=\"debug-user.app?method=remove&name=" + name + "&view=" + view + " \">remove</a></th></tr>\n");
+        }
+        request.appendHtml("</table>\n");
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorDetails.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorDetails.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorDetails.java
new file mode 100644
index 0000000..3049b26
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorDetails.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.scimpi.dispatcher.debug;
+
+import org.apache.isis.viewer.scimpi.dispatcher.AbstractElementProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.Request;
+
+
+public class ErrorDetails extends AbstractElementProcessor {
+
+    public String getName() {
+        return "error-details";
+    }
+
+    public void process(final Request request) {
+        request.appendHtml(request.getContext().getErrorDetails());
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorMessage.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorMessage.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorMessage.java
new file mode 100644
index 0000000..07538ce
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorMessage.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.scimpi.dispatcher.debug;
+
+import org.apache.isis.viewer.scimpi.dispatcher.AbstractElementProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.Request;
+
+
+public class ErrorMessage extends AbstractElementProcessor {
+
+    public String getName() {
+        return "error-message";
+    }
+
+    public void process(final Request request) {
+        request.appendAsHtmlEncoded(request.getContext().getErrorMessage());
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorReference.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorReference.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorReference.java
new file mode 100644
index 0000000..75700cc
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/ErrorReference.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.scimpi.dispatcher.debug;
+
+import org.apache.isis.viewer.scimpi.dispatcher.AbstractElementProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.Request;
+
+
+public class ErrorReference extends AbstractElementProcessor {
+
+    public String getName() {
+        return "error-reference";
+    }
+
+    public void process(final Request request) {
+        request.appendAsHtmlEncoded(request.getContext().getErrorReference());
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/LogAction.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/LogAction.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/LogAction.java
new file mode 100644
index 0000000..6c30c19
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/debug/LogAction.java
@@ -0,0 +1,75 @@
+/*
+ *  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.scimpi.dispatcher.debug;
+
+import java.io.IOException;
+
+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.viewer.scimpi.dispatcher.Action;
+import org.apache.isis.viewer.scimpi.dispatcher.NotLoggedInException;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+
+public class LogAction implements Action {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogAction.class);
+
+    @Override
+    public void process(final RequestContext context) throws IOException {
+
+        final AuthenticationSession session = context.getSession();
+        if (session == null) {
+            throw new NotLoggedInException();
+        }
+
+        final String levelName = (String) context.getVariable("level");
+
+        final org.apache.log4j.Level level = org.apache.log4j.Level.toLevel(levelName);
+        boolean changeLogged = false;
+        if (org.apache.log4j.Level.INFO.isGreaterOrEqual(org.apache.log4j.LogManager.getRootLogger().getLevel())) {
+            LOG.info("log level changed to " + level);
+            changeLogged = true;
+        }
+        org.apache.log4j.LogManager.getRootLogger().setLevel(level);
+        if (!changeLogged) {
+            LOG.info("log level changed to " + level);
+        }
+        final String view = (String) context.getVariable("view");
+        context.setRequestPath(view);
+
+    }
+
+    @Override
+    public String getName() {
+        return "log";
+    }
+
+    @Override
+    public void init() {
+    }
+
+    @Override
+    public void debug(final DebugBuilder debug) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/EditAction.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/EditAction.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/EditAction.java
new file mode 100644
index 0000000..852ccea
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/EditAction.java
@@ -0,0 +1,266 @@
+/*
+ *  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.scimpi.dispatcher.edit;
+
+import java.io.IOException;
+import java.util.List;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.commons.authentication.AnonymousSession;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.authentication.MessageBroker;
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.version.Version;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
+import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
+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.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.scimpi.dispatcher.Action;
+import org.apache.isis.viewer.scimpi.dispatcher.Dispatcher;
+import org.apache.isis.viewer.scimpi.dispatcher.NotLoggedInException;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext.Scope;
+
+public class EditAction implements Action {
+    public static final String ACTION = "edit";
+
+    // REVIEW: should provide this rendering context, rather than hardcoding.
+    // the net effect currently is that class members annotated with 
+    // @Hidden(where=Where.ANYWHERE) or @Disabled(where=Where.ANYWHERE) will indeed
+    // be hidden/disabled, but will be visible/enabled (perhaps incorrectly) 
+    // for any other value for Where
+    private final Where where = Where.ANYWHERE;
+
+    @Override
+    public String getName() {
+        return ACTION;
+    }
+
+    @Override
+    public void process(final RequestContext context) throws IOException {
+        AuthenticationSession session = context.getSession();
+        if (session == null) {
+            session = new AnonymousSession();
+        }
+
+        try {
+            final String objectId = context.getParameter("_" + OBJECT);
+            final String version = context.getParameter("_" + VERSION);
+            final String formId = context.getParameter("_" + FORM_ID);
+            String resultName = context.getParameter("_" + RESULT_NAME);
+            resultName = resultName == null ? RequestContext.RESULT : resultName;
+            final String override = context.getParameter("_" + RESULT_OVERRIDE);
+            String message = context.getParameter("_" + MESSAGE);
+
+            final ObjectAdapter adapter = context.getMappedObject(objectId);
+
+            final List<ObjectAssociation> fields = adapter.getSpecification().getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.dynamicallyVisible(session, adapter, where));
+
+            for (final ObjectAssociation objectAssociation : fields) {
+                if (objectAssociation.isVisible(session, adapter, where).isVetoed()) {
+                    throw new NotLoggedInException();
+                }
+            }
+
+            final FormState entryState = validateObject(context, adapter, fields);
+            final Version adapterVersion = adapter.getVersion();
+            final Version formVersion = context.getVersion(version);
+            if (formVersion != null && adapterVersion.different(formVersion)) {
+
+                IsisContext.getMessageBroker().addMessage("The " + adapter.getSpecification().getSingularName() + " was edited " + "by another user (" + adapterVersion.getUser() + "). Please  make your changes based on their changes.");
+
+                final String view = context.getParameter("_" + ERROR);
+                context.setRequestPath(view, Dispatcher.EDIT);
+
+                entryState.setForm(formId);
+                context.addVariable(ENTRY_FIELDS, entryState, Scope.REQUEST);
+                context.addVariable(resultName, objectId, Scope.REQUEST);
+                if (override != null) {
+                    context.addVariable(resultName, override, Scope.REQUEST);
+                }
+
+            } else if (entryState.isValid()) {
+                changeObject(context, adapter, entryState, fields);
+
+                if (adapter.isTransient()) {
+                    IsisContext.getPersistenceSession().makePersistent(adapter);
+                    context.unmapObject(adapter, Scope.REQUEST);
+                }
+
+                String view = context.getParameter("_" + VIEW);
+
+                final String id = context.mapObject(adapter, Scope.REQUEST);
+                context.addVariable(resultName, id, Scope.REQUEST);
+                if (override != null) {
+                    context.addVariable(resultName, override, Scope.REQUEST);
+                }
+
+                final int questionMark = view == null ? -1 : view.indexOf("?");
+                if (questionMark > -1) {
+                    final String params = view.substring(questionMark + 1);
+                    final int equals = params.indexOf("=");
+                    context.addVariable(params.substring(0, equals), params.substring(equals + 1), Scope.REQUEST);
+                    view = view.substring(0, questionMark);
+                }
+                context.setRequestPath(view);
+                if (message == null) {
+                    message = "Saved changes to " + adapter.getSpecification().getSingularName();
+                } else if (message.equals("")) {
+                    message = null;
+                }
+                if (message != null) {
+                    final MessageBroker messageBroker = IsisContext.getMessageBroker();
+                    messageBroker.addMessage(message);
+                }
+
+            } else {
+                final String view = context.getParameter("_" + ERROR);
+                context.setRequestPath(view, Dispatcher.EDIT);
+
+                entryState.setForm(formId);
+                context.addVariable(ENTRY_FIELDS, entryState, Scope.REQUEST);
+                context.addVariable(resultName, objectId, Scope.REQUEST);
+                if (override != null) {
+                    context.addVariable(resultName, override, Scope.REQUEST);
+                }
+
+                final MessageBroker messageBroker = IsisContext.getMessageBroker();
+                messageBroker.addWarning(entryState.getError());
+            }
+
+        } catch (final RuntimeException e) {
+            IsisContext.getMessageBroker().getMessages();
+            IsisContext.getMessageBroker().getWarnings();
+            throw e;
+        }
+    }
+
+    private FormState validateObject(final RequestContext context, final ObjectAdapter object, final List<ObjectAssociation> fields) {
+        final FormState formState = new FormState();
+        for (int i = 0; i < fields.size(); i++) {
+            final ObjectAssociation field = fields.get(i);
+            final String fieldId = field.getId();
+            String newEntry = context.getParameter(fieldId);
+            if (fields.get(i).isOneToManyAssociation()) {
+                continue;
+            }
+            if (fields.get(i).isVisible(IsisContext.getAuthenticationSession(), object, where).isVetoed()) {
+                continue;
+            }
+            if (field.isUsable(IsisContext.getAuthenticationSession(), object, where).isVetoed()) {
+                continue;
+            }
+
+            if (newEntry != null && newEntry.equals("-OTHER-")) {
+                newEntry = context.getParameter(fieldId + "-other");
+            }
+
+            if (newEntry == null) {
+                // TODO duplicated in EditObject; line 97
+                final ObjectSpecification spec = field.getSpecification();
+                if (spec.isOfType(IsisContext.getSpecificationLoader().loadSpecification(boolean.class)) || spec.isOfType(IsisContext.getSpecificationLoader().loadSpecification(Boolean.class))) {
+                    newEntry = FALSE;
+                } else {
+                    continue;
+                }
+            }
+            final FieldEditState fieldState = formState.createField(fieldId, newEntry);
+
+            Consent consent = null;
+            if (field.isMandatory() && (newEntry.equals("") || newEntry.equals("NULL"))) {
+                consent = new Veto(field.getName() + " required");
+                formState.setError("Not all fields have been set");
+            } else if (field.getSpecification().containsFacet(ParseableFacet.class)) {
+                try {
+                    final ParseableFacet facet = field.getSpecification().getFacet(ParseableFacet.class);
+                    final ObjectAdapter originalValue = field.get(object);
+                    Localization localization = IsisContext.getLocalization(); 
+                    final ObjectAdapter newValue = facet.parseTextEntry(originalValue, newEntry, localization); 
+                    consent = ((OneToOneAssociation) field).isAssociationValid(object, newValue);
+                    fieldState.setValue(newValue);
+                } catch (final TextEntryParseException e) {
+                    consent = new Veto(e.getMessage());
+                    // formState.setError("Not all fields have been entered correctly");
+                }
+
+            } else {
+                final ObjectAdapter associate = newEntry.equals("null") ? null : context.getMappedObject(newEntry);
+                if (associate != null) {
+                    IsisContext.getPersistenceSession().resolveImmediately(associate);
+                }
+                consent = ((OneToOneAssociation) field).isAssociationValid(object, associate);
+                fieldState.setValue(associate);
+
+            }
+            if (consent.isVetoed()) {
+                fieldState.setError(consent.getReason());
+                formState.setError("Not all fields have been entered correctly");
+            }
+        }
+
+        // TODO check the state of the complete object.
+        return formState;
+    }
+
+    private void changeObject(final RequestContext context, final ObjectAdapter object, final FormState editState, final List<ObjectAssociation> fields) {
+        for (int i = 0; i < fields.size(); i++) {
+            final FieldEditState field = editState.getField(fields.get(i).getId());
+            if (field == null) {
+                continue;
+            }
+            final String newEntry = field.getEntry();
+            final ObjectAdapter originalValue = fields.get(i).get(object);
+            final boolean isVisible = fields.get(i).isVisible(IsisContext.getAuthenticationSession(), object, where).isAllowed();
+            final boolean isUsable = fields.get(i).isUsable(IsisContext.getAuthenticationSession(), object, where).isAllowed();
+            final boolean bothEmpty = originalValue == null && newEntry.equals("");
+            final boolean bothSame = newEntry.equals(originalValue == null ? "" : originalValue.titleString());
+            if ((!isVisible || !isUsable) || bothEmpty || bothSame) {
+                if (fields.get(i).getSpecification().getFacet(ParseableFacet.class) == null) {
+                    // REVIEW restores object to loader
+                    context.getMappedObject(newEntry);
+                }
+                continue;
+            }
+
+            if (fields.get(i).getSpecification().containsFacet(ParseableFacet.class)) {
+                final ParseableFacet facet = fields.get(i).getSpecification().getFacet(ParseableFacet.class);
+                Localization localization = IsisContext.getLocalization(); 
+                final ObjectAdapter newValue = facet.parseTextEntry(originalValue, newEntry, localization);
+                ((OneToOneAssociation) fields.get(i)).set(object, newValue);
+            } else {
+                ((OneToOneAssociation) fields.get(i)).set(object, field.getValue());
+            }
+        }
+    }
+
+    @Override
+    public void init() {
+    }
+
+    @Override
+    public void debug(final DebugBuilder debug) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FieldEditState.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FieldEditState.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FieldEditState.java
new file mode 100644
index 0000000..70e6789
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FieldEditState.java
@@ -0,0 +1,57 @@
+/*
+ *  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.scimpi.dispatcher.edit;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+
+public class FieldEditState {
+    private final String entry;
+    private String reason;
+    private ObjectAdapter value;
+
+    public FieldEditState(final String entry) {
+        this.entry = entry;
+    }
+
+    public void setError(final String reason) {
+        this.reason = reason;
+    }
+
+    public boolean isEntryValid() {
+        return reason == null;
+    }
+
+    public String getEntry() {
+        return entry;
+    }
+
+    public String getError() {
+        return reason;
+    }
+
+    public ObjectAdapter getValue() {
+        return value;
+    }
+
+    public void setValue(final ObjectAdapter value) {
+        this.value = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FormState.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FormState.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FormState.java
new file mode 100644
index 0000000..7349837
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/FormState.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.scimpi.dispatcher.edit;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class FormState {
+    private final Map<String, FieldEditState> fields = new HashMap<String, FieldEditState>();
+    private String error;
+    private String formId;
+
+    public FieldEditState createField(final String name, final String entry) {
+        final FieldEditState fieldEditState = new FieldEditState(entry);
+        fields.put(name, fieldEditState);
+        return fieldEditState;
+    }
+
+    public boolean isValid() {
+        final Iterator<FieldEditState> iterator = fields.values().iterator();
+        while (iterator.hasNext()) {
+            if (!iterator.next().isEntryValid()) {
+                return false;
+            }
+        }
+        return error == null;
+    }
+
+    public FieldEditState getField(final String name) {
+        return fields.get(name);
+    }
+
+    public void setError(final String error) {
+        this.error = error;
+    }
+
+    public String getError() {
+        return error;
+    }
+
+    public void setForm(final String formId) {
+        this.formId = formId;
+    }
+
+    public boolean isForForm(final String formId) {
+        return this.formId == null || this.formId.equals(formId);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/RemoveAction.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/RemoveAction.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/RemoveAction.java
new file mode 100644
index 0000000..919ccc2
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/edit/RemoveAction.java
@@ -0,0 +1,114 @@
+/*
+ *  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.scimpi.dispatcher.edit;
+
+import java.io.IOException;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.authentication.AnonymousSession;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.scimpi.dispatcher.Action;
+import org.apache.isis.viewer.scimpi.dispatcher.ForbiddenException;
+import org.apache.isis.viewer.scimpi.dispatcher.ScimpiException;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext.Scope;
+
+/**
+ * Remove an element from a collection.
+ */
+public class RemoveAction implements Action {
+    public static final String ACTION = "remove";
+
+    // REVIEW: confirm this rendering context
+    private final Where where = Where.OBJECT_FORMS;
+
+    @Override
+    public String getName() {
+        return ACTION;
+    }
+
+    @Override
+    public void process(final RequestContext context) throws IOException {
+        AuthenticationSession session = context.getSession();
+        if (session == null) {
+            session = new AnonymousSession();
+        }
+
+        final String parentId = context.getParameter(OBJECT);
+        final String rowId = context.getParameter(ELEMENT);
+
+        try {
+            final ObjectAdapter parent = context.getMappedObject(parentId);
+            final ObjectAdapter row = context.getMappedObject(rowId);
+
+            final String fieldName = context.getParameter(FIELD);
+            final ObjectAssociation field = parent.getSpecification().getAssociation(fieldName);
+            if (field == null) {
+                throw new ScimpiException("No field " + fieldName + " in " + parent.getSpecification().getFullIdentifier());
+            }
+            if (field.isVisible(IsisContext.getAuthenticationSession(), parent, where).isVetoed()) {
+                throw new ForbiddenException(field, ForbiddenException.VISIBLE);
+            }
+
+            ((OneToManyAssociation) field).removeElement(parent, row);
+
+            // TODO duplicated in EditAction
+            String view = context.getParameter(VIEW);
+            final String override = context.getParameter(RESULT_OVERRIDE);
+
+            String resultName = context.getParameter(RESULT_NAME);
+            resultName = resultName == null ? RequestContext.RESULT : resultName;
+
+            final String id = context.mapObject(parent, Scope.REQUEST);
+            context.addVariable(resultName, id, Scope.REQUEST);
+            if (override != null) {
+                context.addVariable(resultName, override, Scope.REQUEST);
+            }
+
+            final int questionMark = view == null ? -1 : view.indexOf("?");
+            if (questionMark > -1) {
+                final String params = view.substring(questionMark + 1);
+                final int equals = params.indexOf("=");
+                context.addVariable(params.substring(0, equals), params.substring(equals + 1), Scope.REQUEST);
+                view = view.substring(0, questionMark);
+            }
+            context.setRequestPath(view);
+            // TODO end of duplication
+
+        } catch (final RuntimeException e) {
+            IsisContext.getMessageBroker().getMessages();
+            IsisContext.getMessageBroker().getWarnings();
+            throw e;
+        }
+    }
+
+    @Override
+    public void init() {
+    }
+
+    @Override
+    public void debug(final DebugBuilder debug) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/DomainSession.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/DomainSession.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/DomainSession.java
new file mode 100644
index 0000000..55809e0
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/DomainSession.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.scimpi.dispatcher.logon;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.isis.core.commons.authentication.AuthenticationSessionAbstract;
+import org.apache.isis.core.commons.encoding.DataInputExtended;
+
+public class DomainSession extends AuthenticationSessionAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String CODE = "";
+
+    public DomainSession(final String username, final List<String> roles) {
+        super(username, roles, CODE);
+    }
+    
+    public DomainSession(final DataInputExtended input) throws IOException {
+        super(input);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogonAction.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogonAction.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogonAction.java
new file mode 100644
index 0000000..e90740a
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogonAction.java
@@ -0,0 +1,175 @@
+/*
+ *  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.scimpi.dispatcher.logon;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.scimpi.dispatcher.Action;
+import org.apache.isis.viewer.scimpi.dispatcher.Dispatcher;
+import org.apache.isis.viewer.scimpi.dispatcher.ScimpiException;
+import org.apache.isis.viewer.scimpi.dispatcher.UserManager;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext.Scope;
+import org.apache.isis.viewer.scimpi.dispatcher.edit.FieldEditState;
+import org.apache.isis.viewer.scimpi.dispatcher.edit.FormState;
+import org.apache.isis.viewer.scimpi.dispatcher.util.MethodsUtils;
+
+
+public class LogonAction implements Action {
+
+    @Override
+    public void process(final RequestContext context) throws IOException {
+        String username = context.getParameter("username");
+        String password = context.getParameter("password");
+        final String actualFormId = context.getParameter("_" + FORM_ID);
+        final String expectedFormId = context.getParameter(LOGON_FORM_ID);
+        boolean isDomainLogon = expectedFormId != null && expectedFormId.equals(actualFormId);
+        boolean isValid;
+
+        if (username == null || password == null) {
+            context.redirectTo("/");
+            return;
+        }
+        AuthenticationSession session = null;
+        if (username.length() == 0 || password.length() == 0) {
+            isValid = false;
+        } else {
+            if (isDomainLogon) {
+                final String objectId = context.getParameter(LOGON_OBJECT);
+                final String scope = context.getParameter(LOGON_SCOPE);
+                final String loginMethodName = context.getParameter(LOGON_METHOD);
+                final String roleFieldName = context.getParameter(PREFIX + "roles-field");
+                String resultName = context.getParameter(LOGON_RESULT_NAME);
+                resultName = resultName == null ? "_" + USER : resultName;
+
+                final ObjectAdapter object = MethodsUtils.findObject(context, objectId);
+                final ObjectAction loginAction = MethodsUtils.findAction(object, loginMethodName);
+                final int parameterCount = loginAction.getParameterCount();
+                final ObjectAdapter[] parameters = new ObjectAdapter[parameterCount];
+                List<ObjectActionParameter> parameters2 = loginAction.getParameters();
+                if (parameters.length != 2) {
+                    throw new ScimpiException("Expected two parameters for the log-on method: " + loginMethodName);
+                }
+
+                Localization localization = IsisContext.getLocalization(); 
+                ParseableFacet facet = parameters2.get(0).getSpecification().getFacet(ParseableFacet.class);
+                parameters[0] = facet.parseTextEntry(null, username, localization);
+                facet = parameters2.get(1).getSpecification().getFacet(ParseableFacet.class);
+                parameters[1] = facet.parseTextEntry(null, password, localization);
+                final ObjectAdapter result = loginAction.execute(object, parameters);
+                isValid = result != null;
+                if (isValid) {
+                    ObjectSpecification specification = result.getSpecification();
+                    ObjectAssociation association = specification.getAssociation(roleFieldName);
+                    if (association == null) {
+                        throw new ScimpiException("Expected a role name field called: " + roleFieldName);
+                    }
+                    ObjectAdapter role = association.get(result);
+                    List<String> roles = new ArrayList<String>();
+                    if (role != null) {
+                        String[] split = role.titleString().split("\\|");
+                        for (String r : split) {
+                            roles.add(r);
+                        }
+                    }
+                    //String domainRoleName = role == null ? "" : role.titleString(); 
+                    
+                    
+                    Scope scope2 = scope == null ? Scope.SESSION : RequestContext.scope(scope);
+                    final String resultId = context.mapObject(result, scope2);
+                    context.addVariable(resultName, resultId, scope);
+                    context.addVariable("_username", username, Scope.SESSION);
+                    
+                    context.clearVariable(LOGON_OBJECT, Scope.SESSION);
+                    context.clearVariable(LOGON_METHOD, Scope.SESSION);
+                    context.clearVariable(LOGON_RESULT_NAME, Scope.SESSION);
+                    context.clearVariable(LOGON_SCOPE, Scope.SESSION);
+                    context.clearVariable(PREFIX + "roles-field", Scope.SESSION);
+ //                   context.clearVariable(PREFIX + "isis-user", Scope.SESSION);
+                    context.clearVariable(LOGON_FORM_ID, Scope.SESSION);
+
+                    session = new DomainSession(result.titleString(), roles);
+                } else {
+                    session = context.getSession();
+                }
+                
+            } else {
+                session = UserManager.authenticate(new AuthenticationRequestPassword(username, password));
+                isValid = session != null;
+            }
+        }
+
+        String view;
+        if (!isValid) {
+            final FormState formState = new FormState();
+            formState.setForm(actualFormId);
+            formState.setError("Failed to login. Check the username and ensure that your password was entered correctly");
+            FieldEditState fieldState = formState.createField("username", username);
+            if (username.length() == 0) {
+                fieldState.setError("User Name required");
+            }
+            fieldState = formState.createField("password", password);
+            if (password.length() == 0) {
+                fieldState.setError("Password required");
+            }
+            if (username.length() == 0 || password.length() == 0) {
+                formState.setError("Both the user name and password must be entered");
+            }
+            context.addVariable(ENTRY_FIELDS, formState, Scope.REQUEST);
+
+            view = context.getParameter(ERROR);
+            context.setRequestPath("/" + view, Dispatcher.ACTION);
+        } else {
+            context.setSession(session);
+            context.startHttpSession();
+            context.setUserAuthenticated(true);
+            view = context.getParameter(VIEW);
+            if (view == null) {
+                // REVIEW this is duplicated in Logon.java
+                view = "start." + Dispatcher.EXTENSION;
+            }
+            context.redirectTo(view);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return "logon";
+    }
+
+    @Override
+    public void init() {}
+
+    @Override
+    public void debug(final DebugBuilder debug) {}
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogoutAction.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogoutAction.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogoutAction.java
new file mode 100644
index 0000000..a6f4730
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/logon/LogoutAction.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.scimpi.dispatcher.logon;
+
+import java.io.IOException;
+
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.scimpi.dispatcher.Action;
+import org.apache.isis.viewer.scimpi.dispatcher.UserManager;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext.Scope;
+
+public class LogoutAction implements Action {
+
+    public static void logoutUser(final RequestContext context) {
+        if (context.isUserAuthenticated()) {
+            final AuthenticationSession session = context.getSession();
+            if (session != null) {
+                UserManager.logoffUser(session);
+            }
+            context.endHttpSession();
+            context.setUserAuthenticated(false);
+        }
+        context.clearVariables(Scope.SESSION);
+    }
+
+    @Override
+    public String getName() {
+        return "logout";
+    }
+
+    @Override
+    public void init() {
+    }
+
+    @Override
+    public void process(final RequestContext context) throws IOException {
+        logoutUser(context);
+        
+        String view = context.getParameter("view");
+        if (view == null) {
+            view = context.getContextPath();
+        }
+        context.redirectTo(view);
+    }
+
+    @Override
+    public void debug(final DebugBuilder debug) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/Encoder.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/Encoder.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/Encoder.java
new file mode 100644
index 0000000..1efe91e
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/Encoder.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.scimpi.dispatcher.processor;
+
+public interface Encoder {
+
+    String encoder(String text);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/HtmlFileParser.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/HtmlFileParser.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/HtmlFileParser.java
new file mode 100644
index 0000000..6730510
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/HtmlFileParser.java
@@ -0,0 +1,205 @@
+/*
+ *  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.scimpi.dispatcher.processor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Stack;
+
+import org.htmlparser.Node;
+import org.htmlparser.Remark;
+import org.htmlparser.lexer.Lexer;
+import org.htmlparser.lexer.Page;
+import org.htmlparser.nodes.TagNode;
+import org.htmlparser.util.ParserException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.viewer.scimpi.dispatcher.ElementProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.ScimpiException;
+import org.apache.isis.viewer.scimpi.dispatcher.action.Attributes;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestContext;
+import org.apache.isis.viewer.scimpi.dispatcher.view.HtmlSnippet;
+import org.apache.isis.viewer.scimpi.dispatcher.view.Snippet;
+import org.apache.isis.viewer.scimpi.dispatcher.view.SwfTag;
+
+public class HtmlFileParser {
+    private static final Logger LOG = LoggerFactory.getLogger(HtmlFileParser.class);
+    private final ProcessorLookup processors;
+
+    public HtmlFileParser(final ProcessorLookup processors) {
+        this.processors = processors;
+    }
+
+    public Stack<Snippet> parseHtmlFile(final String filePath, final RequestContext context) {
+        final Stack<Snippet> tagsBeforeContent = new Stack<Snippet>();
+        final Stack<Snippet> tagsAfterContent = new Stack<Snippet>();
+        parseHtmlFile("/", filePath, context, tagsBeforeContent, tagsAfterContent);
+        return tagsBeforeContent;
+    }
+
+    public void parseHtmlFile(final String parentPath, final String filePath, final RequestContext context, final Stack<Snippet> allTags, final Stack<Snippet> tagsForPreviousTemplate) {
+        LOG.debug("parent/file: " + parentPath + " & " + filePath);
+        final File directory = filePath.startsWith("/") ? new File(".") : new File(parentPath);
+        final File loadFile = new File(directory.getParentFile(), filePath);
+        final String loadPath = loadFile.getPath().replace('\\', '/');
+        LOG.debug("loading template '" + loadPath + "'");
+        final InputStream in = context.openStream(loadPath);
+
+        Page page;
+        try {
+            page = new Page(in, null);
+        } catch (final UnsupportedEncodingException e) {
+            throw new ScimpiException(e);
+        }
+        final Lexer lexer = new Lexer(page);
+
+        Node node = null;
+        try {
+            Stack<Snippet> tags = allTags;
+            String lineNumbers = "1";
+            String template = null;
+            tags.push(new HtmlSnippet(lineNumbers, filePath));
+
+            // NOTE done like this the tags can be cached for faster processing
+            while ((node = lexer.nextNode()) != null) {
+                if (node instanceof Remark) {
+                    // TODO need to pick up on comments within tags; at the
+                    // moment this splits a tag into two causing a
+                    // failure later
+                    continue;
+
+                } else if (node instanceof TagNode && ((TagNode) node).getTagName().startsWith("SWF:")) {
+                    final TagNode tagNode = (TagNode) node;
+                    final String tagName = tagNode.getTagName().toUpperCase();
+                    LOG.debug(tagName);
+
+                    // TODO remove context & request from Attributes -- the tags
+                    // will be re-used across
+                    // requests
+                    final Attributes attributes = new Attributes(tagNode, context);
+                    int type = 0;
+                    if (tagNode.isEndTag()) {
+                        type = SwfTag.END;
+                    } else {
+                        type = tagNode.isEmptyXmlTag() ? SwfTag.EMPTY : SwfTag.START;
+                    }
+                    testForProcessorForTag(lexer, tagName);
+                    lineNumbers = lineNumbering(node);
+                    final SwfTag tag = new SwfTag(tagName, attributes, type, lineNumbers, loadFile.getCanonicalPath());
+                    tags.push(tag);
+
+                    if (tagName.equals("SWF:IMPORT")) {
+                        if (!tagNode.isEmptyXmlTag()) {
+                            throw new ScimpiException("Import tag must be empty");
+                        }
+                        String importFile = tagNode.getAttribute("file");
+                        if (context.isDebug()) {
+                            context.getWriter().println("<!-- " + "import file " + importFile + " -->");
+                        }
+                        importFile = context.replaceVariables(importFile);
+                        parseHtmlFile(loadPath, importFile, context, tags, tagsForPreviousTemplate);
+                    }
+
+                    if (tagName.equals("SWF:TEMPLATE")) {
+                        if (!tagNode.isEmptyXmlTag()) {
+                            throw new ScimpiException("Template tag must be empty");
+                        }
+                        if (template != null) {
+                            throw new ScimpiException("Template tag can only be used once within a file");
+                        }
+                        template = tagNode.getAttribute("file");
+                        template = context.replaceVariables(template);
+                        if (context.isDebug()) {
+                            context.getWriter().println("<!-- " + "apply template " + template + " -->");
+                        }
+                        tags = new Stack<Snippet>();
+                    }
+
+                    if (tagName.equals("SWF:CONTENT")) {
+                        if (!tagNode.isEmptyXmlTag()) {
+                            throw new ScimpiException("Content tag must be empty");
+                        }
+                        if (context.isDebug()) {
+                            context.getWriter().println("<!-- " + "insert content into template -->");
+                        }
+                        tags.addAll(tagsForPreviousTemplate);
+                    }
+                } else {
+                    final Snippet snippet = tags.size() == 0 ? null : tags.peek();
+                    if (snippet instanceof HtmlSnippet) {
+                        ((HtmlSnippet) snippet).append(node.toHtml());
+                    } else {
+                        final HtmlSnippet htmlSnippet = new HtmlSnippet(lineNumbers, filePath);
+                        htmlSnippet.append(node.toHtml());
+                        tags.push(htmlSnippet);
+                    }
+                }
+
+            }
+            in.close();
+
+            if (template != null) {
+                final String filePathRoot = loadPath.startsWith("/") ? "" : "/";
+                parseHtmlFile(filePathRoot + loadPath, template, context, allTags, tags);
+            }
+
+        } catch (final ParserException e) {
+            exception(loadPath, node, e);
+            // throw new ScimpiException(e);
+        } catch (final RuntimeException e) {
+            // TODO: extend to deal with other exceptions
+            exception(loadPath, node, e);
+        } catch (final IOException e) {
+            throw new ScimpiException(e);
+        }
+    }
+
+    private void exception(final String filePath, final Node node, final Exception e) {
+        String lineNumbers = "";
+        String element = ("" + node).toLowerCase();
+        if (node instanceof TagNode) {
+            lineNumbers = ":" + lineNumbering(node);
+            element = "tag &lt;" + node.getText() + "&gt;";
+        }
+        throw new ScimpiException("Error processing " + element + " in " + filePath + lineNumbers, e);
+    }
+
+    private String lineNumbering(final Node node) {
+        String lineNumbers;
+        final int startingLine = ((TagNode) node).getStartingLineNumber() + 1;
+        final int endingLine = ((TagNode) node).getStartingLineNumber() + 1;
+        if (startingLine == endingLine) {
+            lineNumbers = "" + startingLine;
+        } else {
+            lineNumbers = startingLine + "-" + endingLine;
+        }
+        return lineNumbers;
+    }
+
+    private void testForProcessorForTag(final Lexer lexer, final String tagName) {
+        final ElementProcessor elementProcessor = processors.getFor(tagName);
+        if (elementProcessor == null) {
+            throw new ScimpiException("No processor for tag " + tagName.toLowerCase());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2c7cfbfe/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/PageWriter.java
----------------------------------------------------------------------
diff --git a/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/PageWriter.java b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/PageWriter.java
new file mode 100644
index 0000000..4e11481
--- /dev/null
+++ b/mothballed/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/processor/PageWriter.java
@@ -0,0 +1,28 @@
+/*
+ *  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.scimpi.dispatcher.processor;
+
+public interface PageWriter {
+
+    void appendAsHtmlEncoded(String string);
+
+    void appendHtml(String string);
+
+}