You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by rm...@apache.org on 2013/03/24 18:45:14 UTC

[17/24] Restructuring Scimpi to remove dependencies and enable easier testing.

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedFieldsBlock.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedFieldsBlock.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedFieldsBlock.java
deleted file mode 100644
index 5049a3d..0000000
--- a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedFieldsBlock.java
+++ /dev/null
@@ -1,47 +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.viewer.scimpi.dispatcher.view.field;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
-
-public class LinkedFieldsBlock extends InclusionList {
-    private final Map<String, LinkedObject> linkedFields = new HashMap<String, LinkedObject>();
-
-    public void link(final String field, final String variable, final String scope, final String forwardView) {
-        include(field);
-        linkedFields.put(field, new LinkedObject(variable, scope, forwardView));
-    }
-
-    public LinkedObject[] linkedFields(final List<ObjectAssociation> fields) {
-        final LinkedObject[] includedFields = new LinkedObject[fields.size()];
-        for (int i = 0; i < fields.size(); i++) {
-            final String id2 = fields.get(i).getId();
-            if (fields.get(i).isOneToOneAssociation() && linkedFields.containsKey(id2)) {
-                includedFields[i] = linkedFields.get(id2);
-            }
-        }
-        return includedFields;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedObject.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedObject.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedObject.java
deleted file mode 100644
index 934e1c1..0000000
--- a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/field/LinkedObject.java
+++ /dev/null
@@ -1,58 +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.viewer.scimpi.dispatcher.view.field;
-
-import org.apache.isis.viewer.scimpi.Names;
-import org.apache.isis.viewer.scimpi.dispatcher.context.Request.Scope;
-
-public class LinkedObject {
-    private final String variable;
-    private final String scope;
-    private String forwardView;
-
-    public LinkedObject(final String variable, final String scope, final String forwardView) {
-        this.variable = variable;
-        this.scope = scope;
-        this.forwardView = forwardView;
-    }
-
-    public LinkedObject(final String forwardView) {
-        this.forwardView = forwardView;
-        scope = Scope.INTERACTION.toString();
-        variable = Names.RESULT;
-    }
-
-    public String getVariable() {
-        return variable;
-    }
-
-    public String getScope() {
-        return scope;
-    }
-
-    public String getForwardView() {
-        return forwardView;
-    }
-
-    public void setForwardView(final String path) {
-        forwardView = path;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/ActionFormAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/ActionFormAbstract.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/ActionFormAbstract.java
new file mode 100644
index 0000000..f3fa4dd
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/ActionFormAbstract.java
@@ -0,0 +1,223 @@
+package org.apache.isis.viewer.scimpi.dispatcher.view.form;
+
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+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.viewer.scimpi.Names;
+import org.apache.isis.viewer.scimpi.ScimpiException;
+import org.apache.isis.viewer.scimpi.dispatcher.action.ActionAction;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request.Scope;
+import org.apache.isis.viewer.scimpi.dispatcher.form.FieldEditState;
+import org.apache.isis.viewer.scimpi.dispatcher.form.FormState;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.util.MethodsUtils;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+// TODO combine the common stuff that is found here and in EditFormAbstract and LoginFormAbstract
+public abstract class ActionFormAbstract extends AbstractElementProcessor {
+
+    private static final Where where = Where.OBJECT_FORMS;
+
+    public static void createForm(final TemplateProcessor templateProcessor, final CreateFormParameter parameterObject) {
+        createForm(templateProcessor, parameterObject, false);
+    }
+
+    public static void createForm(final TemplateProcessor templateProcessor, final CreateFormParameter parameterObject, final boolean withoutProcessing) {
+        final Request context = templateProcessor.getContext();
+        final ObjectAdapter object = MethodsUtils.findObject(context, parameterObject.objectId);
+        final String version = templateProcessor.getContext().mapVersion(object);
+        final ObjectAction action = MethodsUtils.findAction(object, parameterObject.methodName);
+        // TODO how do we distinguish between overloaded methods?
+    
+        // REVIEW Is this useful?
+        if (action.getParameterCount() == 0) {
+            throw new ScimpiException("Action form can only be used for actions with parameters");
+        }
+        if (parameterObject.showMessage && MethodsUtils.isVisible(object, action, where)) {
+            final String notUsable = MethodsUtils.isUsable(object, action, where);
+            if (notUsable != null) {
+                if (!withoutProcessing) {
+                    templateProcessor.skipUntilClose();
+                }
+                templateProcessor.appendHtml("<div class=\"" + parameterObject.className + "-message\" >");
+                templateProcessor.appendAsHtmlEncoded(notUsable);
+                templateProcessor.appendHtml("</div>");
+                return;
+            }
+        }
+        if (!MethodsUtils.isVisibleAndUsable(object, action, where)) {
+            if (!withoutProcessing) {
+                templateProcessor.skipUntilClose();
+            }
+            return;
+        }
+        final String objectId = context.mapObject(object, Scope.INTERACTION);
+        final String errorView = context.fullFilePath(parameterObject.forwardErrorTo == null ? context.getResourceFile() : parameterObject.forwardErrorTo);
+        final String voidView = context.fullFilePath(parameterObject.forwardVoidTo == null ? context.getResourceFile() : parameterObject.forwardVoidTo);
+        if (action.isContributed() && !action.hasReturn() && parameterObject.resultOverride == null) {
+            parameterObject.resultOverride = objectId;
+        }
+        final HiddenInputField[] hiddenFields = new HiddenInputField[] { new HiddenInputField("_" + OBJECT, objectId), new HiddenInputField("_" + VERSION, version), new HiddenInputField("_" + FORM_ID, parameterObject.formId), new HiddenInputField("_" + METHOD, parameterObject.methodName),
+                parameterObject.forwardResultTo == null ? null : new HiddenInputField("_" + VIEW, context.fullFilePath(parameterObject.forwardResultTo)), new HiddenInputField("_" + VOID, voidView), new HiddenInputField("_" + ERROR, errorView),
+                parameterObject.completionMessage == null ? null : new HiddenInputField("_" + MESSAGE, parameterObject.completionMessage), parameterObject.scope == null ? null : new HiddenInputField("_" + SCOPE, parameterObject.scope),
+                parameterObject.resultOverride == null ? null : new HiddenInputField("_" + RESULT_OVERRIDE, parameterObject.resultOverride), parameterObject.resultName == null ? null : new HiddenInputField("_" + RESULT_NAME, parameterObject.resultName),
+                parameterObject.resultName == null ? null : new HiddenInputField(Names.RESULT, (String) templateProcessor.getContext().getVariable(Names.RESULT)) };
+    
+        // TODO when the block contains a selector tag it doesn't disable it if
+        // the field cannot be edited!!!
+        final FormFieldBlock containedBlock = new FormFieldBlock() {
+            @Override
+            public boolean isNullable(final String name) {
+                final int index = Integer.parseInt(name.substring(5)) - 1;
+                final ObjectActionParameter param = action.getParameters().get(index);
+                return param.isOptional();
+            }
+        };
+        templateProcessor.pushBlock(containedBlock);
+        if (!withoutProcessing) {
+            templateProcessor.processUtilCloseTag();
+        }
+    
+        final FormState entryState = (FormState) context.getVariable(ENTRY_FIELDS);
+    
+        // TODO the list of included fields should be considered in the next
+        // method (see EditObject)
+        final InputField[] formFields = createFields(action, object);
+        hideExcludedParameters(containedBlock, formFields);
+        containedBlock.setUpValues(formFields);
+        initializeFields(context, object, action, formFields);
+        setDefaults(context, object, action, formFields, entryState, parameterObject.showIcon);
+        String errors = null;
+        if (entryState != null && entryState.isForForm(parameterObject.formId)) {
+            copyEntryState(context, object, action, formFields, entryState);
+            errors = entryState.getError();
+        }
+        overrideWithHtml(context, containedBlock, formFields);
+    
+        String formTitle;
+        if (parameterObject.formTitle == null) {
+            formTitle = action.getName();
+        } else {
+            formTitle = parameterObject.formTitle;
+        }
+    
+        String buttonTitle = parameterObject.buttonTitle;
+        if (buttonTitle == null) {
+            buttonTitle = action.getName();
+        } else if (buttonTitle.equals("")) {
+            buttonTitle = "Ok";
+        }
+    
+        HtmlFormBuilder.createForm(templateProcessor, ActionAction.ACTION + ".app", hiddenFields, formFields, parameterObject.className,
+                parameterObject.id, formTitle, parameterObject.labelDelimiter, action.getDescription(), action.getHelp(), buttonTitle, errors, parameterObject.cancelTo);
+    
+        templateProcessor.popBlock();
+    }
+
+    private static void hideExcludedParameters(final FormFieldBlock containedBlock, final InputField[] formFields) {
+        for (final InputField inputField : formFields) {
+            final String id2 = inputField.getName();
+            if (!containedBlock.includes(id2)) {
+                inputField.setHidden(true);
+            }
+        }
+    }
+
+    private static InputField[] createFields(final ObjectAction action, final ObjectAdapter object) {
+        final int parameterCount = action.getParameterCount();
+        final InputField[] fields = new InputField[parameterCount];
+        for (int i = 0; i < fields.length; i++) {
+            fields[i] = new InputField(ActionAction.parameterName(i));
+        }
+        return fields;
+    }
+
+    private static void initializeFields(final Request context, final ObjectAdapter object, final ObjectAction action, final InputField[] fields) {
+        final List<ObjectActionParameter> parameters = action.getParameters();
+        for (int i = 0; i < fields.length; i++) {
+            final InputField field = fields[i];
+            final ObjectActionParameter param = parameters.get(i);
+            if (action.isContributed() && i == 0) {
+                // fields[i].setValue(context.mapObject(object,
+                // Scope.INTERACTION));
+                fields[i].setType(InputField.REFERENCE);
+                fields[i].setHidden(true);
+            } else {
+    
+                fields[i].setHelpReference("xxxhelp");
+                final ObjectAdapter[] optionsForParameter = action.getChoices(object)[i];
+                FieldFactory.initializeField(context, object, param, optionsForParameter, !param.isOptional(), field);
+            }
+        }
+    }
+
+    /**
+     * Sets up the fields with their initial values
+     * 
+     * @param showIcon
+     */
+    private static void setDefaults(final Request context, final ObjectAdapter object, final ObjectAction action, final InputField[] fields, final FormState entryState, final boolean showIcon) {
+        final ObjectAdapter[] defaultValues = action.getDefaults(object);
+        if (defaultValues == null) {
+            return;
+        }
+    
+        for (int i = 0; i < fields.length; i++) {
+            final InputField field = fields[i];
+            final ObjectAdapter defaultValue = defaultValues[i];
+    
+            final String title = defaultValue == null ? "" : defaultValue.titleString();
+            if (field.getType() == InputField.REFERENCE) {
+                final ObjectSpecification objectSpecification = action.getParameters().get(i).getSpecification();
+                if (defaultValue != null) {
+                    final String imageSegment = showIcon ? "<img class=\"small-icon\" src=\"" + context.imagePath(objectSpecification) + "\" alt=\"" + objectSpecification.getShortIdentifier() + "\"/>" : "";
+                    final String html = imageSegment + title;
+                    final String value = context.mapObject(defaultValue, Scope.INTERACTION);
+                    field.setValue(value);
+                    field.setHtml(html);
+                }
+            } else {
+                field.setValue(title);
+            }
+        }
+    }
+
+    private static void copyEntryState(final Request context, final ObjectAdapter object, final ObjectAction action, final InputField[] fields, final FormState entryState) {
+    
+        for (final InputField field : fields) {
+            final FieldEditState fieldState = entryState.getField(field.getName());
+            if (fieldState != null) {
+                if (field.isEditable()) {
+                    String entry;
+                    entry = fieldState.getEntry();
+                    field.setValue(entry);
+                }
+    
+                field.setErrorText(fieldState.getError());
+            }
+        }
+    }
+
+    private static void overrideWithHtml(final Request context, final FormFieldBlock containedBlock, final InputField[] formFields) {
+        for (int i = 0; i < formFields.length; i++) {
+            final String id = ActionAction.parameterName(i);
+            if (containedBlock.hasContent(id)) {
+                final String content = containedBlock.getContent(id);
+                if (content != null) {
+                    formFields[i].setHtml(content);
+                    formFields[i].setType(InputField.HTML);
+                }
+            }
+        }
+    }
+
+    public ActionFormAbstract() {
+        super();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/CreateFormParameter.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/CreateFormParameter.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/CreateFormParameter.java
new file mode 100644
index 0000000..d4d02f0
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/CreateFormParameter.java
@@ -0,0 +1,43 @@
+/*
+ *  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.view.form;
+
+public class CreateFormParameter {
+    public String methodName;
+    public String forwardResultTo;
+    public String forwardVoidTo;
+    public String forwardErrorTo;
+    public String buttonTitle;
+    public String formTitle;
+    public String formId;
+    public String resultName;
+    public String scope;
+    public String objectId;
+    public String description;
+    public String helpReference;
+    public String className;
+    public String id;
+    public String resultOverride;
+    public boolean showMessage;
+    public boolean showIcon;
+    public String completionMessage;
+    public String cancelTo;
+    public String labelDelimiter;
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/EditFormAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/EditFormAbstract.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/EditFormAbstract.java
new file mode 100644
index 0000000..096b8f9
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/EditFormAbstract.java
@@ -0,0 +1,171 @@
+package org.apache.isis.viewer.scimpi.dispatcher.view.form;
+
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+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.ObjectAssociation;
+import org.apache.isis.core.progmodel.facets.object.choices.enums.EnumFacet;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request.Scope;
+import org.apache.isis.viewer.scimpi.dispatcher.form.FieldEditState;
+import org.apache.isis.viewer.scimpi.dispatcher.form.FormState;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+
+//TODO combine the common stuff that is found here and in ActionFormAbstract and LoginFormAbstract
+public abstract class EditFormAbstract extends AbstractElementProcessor {
+
+    protected final Where where = Where.OBJECT_FORMS;
+
+    public EditFormAbstract() {
+        super();
+    }
+
+    protected InputField[] createFields(final List<ObjectAssociation> fields) {
+        final InputField[] formFields = new InputField[fields.size()];
+        int length = 0;
+        for (int i = 0; i < fields.size(); i++) {
+            if (!fields.get(i).isOneToManyAssociation()) {
+                formFields[i] = new InputField(fields.get(i).getId());
+                length++;
+            }
+        }
+        final InputField[] array = new InputField[length];
+        for (int i = 0, j = 0; i < formFields.length; i++) {
+            if (formFields[i] != null) {
+                array[j++] = formFields[i];
+            }
+        }
+        return array;
+    }
+
+    protected void initializeFields(final Request context, final ObjectAdapter object, final InputField[] formFields, final FormState entryState, final boolean includeUnusableFields) {
+        for (final InputField formField : formFields) {
+            final String fieldId = formField.getName();
+            final ObjectAssociation field = object.getSpecification().getAssociation(fieldId);
+            final AuthenticationSession session = IsisContext.getAuthenticationSession();
+            final Consent usable = field.isUsable(session, object, where);
+            final ObjectAdapter[] options = field.getChoices(object);
+            FieldFactory.initializeField(context, object, field, options, field.isMandatory(), formField);
+    
+            final boolean isEditable = usable.isAllowed();
+            if (!isEditable) {
+                formField.setDescription(usable.getReason());
+            }
+            formField.setEditable(isEditable);
+            final boolean hiddenField = field.isVisible(session, object, where).isVetoed();
+            final boolean unusable = usable.isVetoed();
+            final boolean hideAsUnusable = unusable && !includeUnusableFields;
+            if (hiddenField || hideAsUnusable) {
+                formField.setHidden(true);
+            }
+        }
+    }
+
+    protected void copyFieldContent(final Request context, final ObjectAdapter object, final InputField[] formFields, final boolean showIcon) {
+        for (final InputField inputField : formFields) {
+            final String fieldName = inputField.getName();
+            final ObjectAssociation field = object.getSpecification().getAssociation(fieldName);
+            if (field.isVisible(IsisContext.getAuthenticationSession(), object, where).isAllowed()) {
+                IsisContext.getPersistenceSession().resolveField(object, field);
+                final ObjectAdapter fieldValue = field.get(object);
+                if (inputField.isEditable()) {
+                    final String value = getValue(context, fieldValue);
+                    if (!value.equals("") || inputField.getValue() == null) {
+                        inputField.setValue(value);
+                    }
+                } else {
+                    final String entry = getValue(context, fieldValue);
+                    inputField.setHtml(entry);
+                    inputField.setType(InputField.HTML);
+    
+                }
+    
+                if (field.getSpecification().getFacet(ParseableFacet.class) == null) {
+                    if (fieldValue != null) {
+                        final String iconSegment = showIcon ? "<img class=\"small-icon\" src=\"" + context.imagePath(field.getSpecification()) + "\" alt=\"" + field.getSpecification().getShortIdentifier() + "\"/>" : "";
+                        final String entry = iconSegment + fieldValue.titleString();
+                        inputField.setHtml(entry);
+                    } else {
+                        final String entry = "<em>none specified</em>";
+                        inputField.setHtml(entry);
+                    }
+                }
+            }
+        }
+    }
+
+    protected void setDefaults(final Request context, final ObjectAdapter object, final InputField[] formFields, final FormState entryState, final boolean showIcon) {
+        for (final InputField formField : formFields) {
+            final String fieldId = formField.getName();
+            final ObjectAssociation field = object.getSpecification().getAssociation(fieldId);
+            final ObjectAdapter defaultValue = field.getDefault(object);
+            if (defaultValue == null) {
+                continue;
+            }
+    
+            final String title = defaultValue.titleString();
+            if (field.getSpecification().containsFacet(ParseableFacet.class)) {
+                formField.setValue(title);
+            } else if (field.isOneToOneAssociation()) {
+                final ObjectSpecification objectSpecification = field.getSpecification();
+                if (defaultValue != null) {
+                    final String iconSegment = showIcon ? "<img class=\"small-icon\" src=\"" + context.imagePath(objectSpecification) + "\" alt=\"" + objectSpecification.getShortIdentifier() + "\"/>" : "";
+                    final String html = iconSegment + title;
+                    formField.setHtml(html);
+                    final String value = defaultValue == null ? null : context.mapObject(defaultValue, Scope.INTERACTION);
+                    formField.setValue(value);
+                }
+            }
+        }
+    }
+
+    protected void overrideWithHtml(final Request context, final FormFieldBlock containedBlock, final InputField[] formFields) {
+        for (final InputField formField : formFields) {
+            final String fieldId = formField.getName();
+            if (containedBlock.hasContent(fieldId)) {
+                final String content = containedBlock.getContent(fieldId);
+                if (content != null) {
+                    formField.setHtml(content);
+                    formField.setValue(null);
+                    formField.setType(InputField.HTML);
+                }
+            }
+        }
+    }
+
+    protected void copyEntryState(final Request context, final ObjectAdapter object, final InputField[] formFields, final FormState entryState) {
+        for (final InputField formField : formFields) {
+            final String fieldId = formField.getName();
+            final ObjectAssociation field = object.getSpecification().getAssociation(fieldId);
+            if (field.isVisible(IsisContext.getAuthenticationSession(), object, where).isAllowed() && formField.isEditable()) {
+                final FieldEditState fieldState = entryState.getField(field.getId());
+                final String entry = fieldState == null ? "" : fieldState.getEntry();
+                formField.setValue(entry);
+                final String error = fieldState == null ? "" : fieldState.getError();
+                formField.setErrorText(error);
+            }
+        }
+    }
+
+    protected String getValue(final Request context, final ObjectAdapter field) {
+        if (field == null || field.isTransient()) {
+            return "";
+        }
+        final ObjectSpecification specification = field.getSpecification();
+        if (specification.containsFacet(EnumFacet.class)) {
+            return String.valueOf(field.getObject());
+        } else if (specification.getFacet(ParseableFacet.class) == null) {
+            return context.mapObject(field, Scope.INTERACTION);
+        } else {
+            return field.titleString();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FieldFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FieldFactory.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FieldFactory.java
new file mode 100644
index 0000000..d6470fc
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FieldFactory.java
@@ -0,0 +1,104 @@
+/*
+ *  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.view.form;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.help.HelpFacet;
+import org.apache.isis.core.metamodel.facets.maxlen.MaxLengthFacet;
+import org.apache.isis.core.metamodel.facets.multiline.MultiLineFacet;
+import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
+import org.apache.isis.core.metamodel.facets.typicallen.TypicalLengthFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.progmodel.facets.value.booleans.BooleanValueFacet;
+import org.apache.isis.core.progmodel.facets.value.password.PasswordValueFacet;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request.Scope;
+
+public class FieldFactory {
+
+    public static void initializeField(final Request context, final ObjectAdapter object, final ObjectFeature param, final ObjectAdapter[] optionsForParameter, final boolean isRequired, final InputField field) {
+
+        field.setLabel(param.getName());
+        field.setDescription(param.getDescription());
+        field.setDataType(param.getSpecification().getShortIdentifier());
+        if (param instanceof ObjectMember) {
+            field.setHelpReference(((ObjectMember) param).getHelp());
+        } else {
+            final HelpFacet helpFacet = param.getFacet(HelpFacet.class);
+            final String value = helpFacet.value();
+            field.setHelpReference(value);
+        }
+        field.setRequired(isRequired);
+        field.setHidden(false);
+
+        if (param.getSpecification().getFacet(ParseableFacet.class) != null) {
+            final int maxLength = param.getFacet(MaxLengthFacet.class).value();
+            field.setMaxLength(maxLength);
+
+            final TypicalLengthFacet typicalLengthFacet = param.getFacet(TypicalLengthFacet.class);
+            if (typicalLengthFacet.isDerived() && maxLength > 0) {
+                field.setWidth(maxLength);
+            } else {
+                field.setWidth(typicalLengthFacet.value());
+            }
+
+            final MultiLineFacet multiLineFacet = param.getFacet(MultiLineFacet.class);
+            field.setHeight(multiLineFacet.numberOfLines());
+            field.setWrapped(!multiLineFacet.preventWrapping());
+
+            final ObjectSpecification spec = param.getSpecification();
+            if (spec.containsFacet(BooleanValueFacet.class)) {
+                field.setType(InputField.CHECKBOX);
+            } else if (spec.containsFacet(PasswordValueFacet.class)) {
+                field.setType(InputField.PASSWORD);
+            } else {
+                field.setType(InputField.TEXT);
+            }
+
+        } else {
+            field.setType(InputField.REFERENCE);
+        }
+
+        if (optionsForParameter != null) {
+            final int noOptions = optionsForParameter.length;
+            final String[] optionValues = new String[noOptions];
+            final String[] optionTitles = new String[noOptions];
+            for (int j = 0; j < optionsForParameter.length; j++) {
+                final int i = j; // + (field.isRequired() ? 0 : 1);
+                optionValues[i] = getValue(context, optionsForParameter[j]);
+                optionTitles[i] = optionsForParameter[j].titleString();
+            }
+            field.setOptions(optionTitles, optionValues);
+        }
+    }
+
+    private static String getValue(final Request context, final ObjectAdapter field) {
+        if (field == null) {
+            return "";
+        }
+        if (field.getSpecification().getFacet(ParseableFacet.class) == null) {
+            return context.mapObject(field, Scope.INTERACTION);
+        } else {
+            return field.getObject().toString();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormEntry.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormEntry.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormEntry.java
new file mode 100644
index 0000000..f196f7d
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormEntry.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.view.form;
+
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestState;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+public class FormEntry extends AbstractElementProcessor {
+
+    @Override
+    public void process(final TemplateProcessor templateProcessor, RequestState state) {
+        final FormFieldBlock block = (FormFieldBlock) templateProcessor.peekBlock();
+        final String field = templateProcessor.getRequiredProperty(FIELD);
+        final String value = templateProcessor.getRequiredProperty(VALUE);
+        final boolean isHidden = templateProcessor.isRequested(HIDDEN, true);
+        block.exclude(field);
+        // TODO this is replaced because the field is marked as hidden!
+        final String content = "reference <input type=\"" + (isHidden ? "hidden" : "text") + "\" disabled=\"disabled\" name=\"" + field + "\" value=\"" + value + "\" />";
+        block.replaceContent(field, content);
+    }
+
+    @Override
+    public String getName() {
+        return "form-entry";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormField.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormField.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormField.java
new file mode 100644
index 0000000..4409897
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormField.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.view.form;
+
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestState;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+public class FormField extends AbstractElementProcessor {
+
+    @Override
+    public void process(final TemplateProcessor templateProcessor, RequestState state) {
+        final FormFieldBlock block = (FormFieldBlock) templateProcessor.peekBlock();
+        final String field = templateProcessor.getRequiredProperty(FIELD);
+        if (block.isVisible(field)) {
+            templateProcessor.pushNewBuffer();
+            templateProcessor.processUtilCloseTag();
+            final String content = templateProcessor.popBuffer();
+            block.replaceContent(field, content);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return "form-field";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormFieldBlock.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormFieldBlock.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormFieldBlock.java
new file mode 100644
index 0000000..9247eb0
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/FormFieldBlock.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.view.form;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.scimpi.dispatcher.view.determine.InclusionList;
+
+public class FormFieldBlock extends InclusionList {
+    private final Map<String, String> content = new HashMap<String, String>();
+    private final Map<String, String> values = new HashMap<String, String>();
+
+    public void replaceContent(final String field, final String htmlString) {
+        content.put(field, htmlString);
+    }
+
+    public boolean hasContent(final String name) {
+        return content.containsKey(name);
+    }
+
+    public String getContent(final String name) {
+        return content.get(name);
+    }
+
+    public boolean isVisible(final String name) {
+        return true;
+    }
+
+    public boolean isNullable(final String name) {
+        return true;
+    }
+
+    public ObjectAdapter getCurrent(final String name) {
+        return null;
+    }
+
+    public void value(final String field, final String value) {
+        values.put(field, value);
+    }
+
+    public void setUpValues(final InputField[] inputFields) {
+        for (final InputField inputField : inputFields) {
+            final String name = inputField.getName();
+            inputField.setValue(values.get(name));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HiddenField.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HiddenField.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HiddenField.java
new file mode 100644
index 0000000..d03b4e3
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HiddenField.java
@@ -0,0 +1,49 @@
+/*
+ *  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.view.form;
+
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestState;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.BlockContent;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TagOrderException;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+public class HiddenField extends AbstractElementProcessor {
+
+    @Override
+    public void process(final TemplateProcessor templateProcessor, RequestState state) {
+        final BlockContent blockContent = templateProcessor.peekBlock();
+        if (!(blockContent instanceof FormFieldBlock)) {
+            throw new TagOrderException(templateProcessor);
+        }
+
+        final String field = templateProcessor.getOptionalProperty("name");
+        final String value = templateProcessor.getRequiredProperty("value");
+        final FormFieldBlock block = (FormFieldBlock) blockContent;
+        block.value(field, value);
+        block.exclude(field);
+    }
+
+    @Override
+    public String getName() {
+        return "hidden-field";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HtmlFormBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HtmlFormBuilder.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HtmlFormBuilder.java
index 6d362a6..3272a3e 100644
--- a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HtmlFormBuilder.java
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/HtmlFormBuilder.java
@@ -20,13 +20,14 @@
 package org.apache.isis.viewer.scimpi.dispatcher.view.form;
 
 import org.apache.isis.core.commons.exceptions.UnknownTypeException;
-import org.apache.isis.viewer.scimpi.dispatcher.processor.TagProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.HtmlEncoder;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
 import org.apache.isis.viewer.scimpi.dispatcher.view.other.HelpLink;
 
 public class HtmlFormBuilder {
 
     public static void createForm(
-            final TagProcessor tagProcessor,
+            final TemplateProcessor templateProcessor,
             final String action,
             final HiddenInputField[] hiddenFields,
             final InputField[] fields,
@@ -41,12 +42,12 @@ public class HtmlFormBuilder {
             final String cancelTo) {
 
         String classSegment = " class=\"" + className + (id == null ? "\"" : "\" id=\"" + id + "\"");
-        tagProcessor.appendHtml("<form " + classSegment + " action=\"" + action + "\" method=\"post\" accept-charset=\"UTF-8\">\n");
+        templateProcessor.appendHtml("<form " + classSegment + " action=\"" + action + "\" method=\"post\" accept-charset=\"UTF-8\">\n");
         if (formTitle != null && formTitle.trim().length() > 0) {
             classSegment = " class=\"title\"";
-            tagProcessor.appendHtml("<div" + classSegment + ">");
-            tagProcessor.appendAsHtmlEncoded(formTitle);
-            tagProcessor.appendHtml("</div>\n");
+            templateProcessor.appendHtml("<div" + classSegment + ">");
+            templateProcessor.appendAsHtmlEncoded(formTitle);
+            templateProcessor.appendHtml("</div>\n");
         }
 
         // TODO reinstate fieldsets when we can specify them
@@ -54,54 +55,54 @@ public class HtmlFormBuilder {
 
         final String cls = "errors";
         if (errors != null) {
-            tagProcessor.appendHtml("<div class=\"" + cls + "\">");
-            tagProcessor.appendAsHtmlEncoded(errors);
-            tagProcessor.appendHtml("</div>");
+            templateProcessor.appendHtml("<div class=\"" + cls + "\">");
+            templateProcessor.appendAsHtmlEncoded(errors);
+            templateProcessor.appendHtml("</div>");
         }
         for (final HiddenInputField hiddenField : hiddenFields) {
             if (hiddenField == null) {
                 continue;
             }
-            tagProcessor.appendHtml("  <input type=\"hidden\" name=\"" + hiddenField.getName() + "\" value=\"");
-            tagProcessor.appendAsHtmlEncoded(hiddenField.getValue());
-            tagProcessor.appendHtml("\" />\n");
+            templateProcessor.appendHtml("  <input type=\"hidden\" name=\"" + hiddenField.getName() + "\" value=\"");
+            templateProcessor.appendAsHtmlEncoded(hiddenField.getValue());
+            templateProcessor.appendHtml("\" />\n");
         }
-        tagProcessor.appendHtml(tagProcessor.getContext().interactionFields());
+        templateProcessor.appendHtml(templateProcessor.getContext().interactionFields());
         for (final InputField fld : fields) {
             if (fld.isHidden()) {
-                tagProcessor.appendHtml("  <input type=\"hidden\" name=\"" + fld.getName() + "\" value=\"");
-                tagProcessor.appendAsHtmlEncoded(fld.getValue());
-                tagProcessor.appendHtml("\" />\n");
+                templateProcessor.appendHtml("  <input type=\"hidden\" name=\"" + fld.getName() + "\" value=\"");
+                templateProcessor.appendAsHtmlEncoded(fld.getValue());
+                templateProcessor.appendHtml("\" />\n");
             } else {
                 final String errorSegment = fld.getErrorText() == null ? "" : "<span class=\"error\">" + fld.getErrorText() + "</span>";
-                final String fieldSegment = createField(fld);
+                final String fieldSegment = createField(fld, templateProcessor);
                 final String helpSegment = HelpLink.createHelpSegment(fld.getDescription(), fld.getHelpReference());
                 final String title = fld.getDescription().equals("") ? "" : " title=\"" + fld.getDescription() + "\"";
-                tagProcessor.appendHtml("  <div class=\"field " + fld.getName() + "\"><label class=\"label\" " + title + ">");
-                tagProcessor.appendAsHtmlEncoded(fld.getLabel());
-                tagProcessor.appendHtml(labelDelimiter + "</label>" + fieldSegment + errorSegment + helpSegment + "</div>\n");
+                templateProcessor.appendHtml("  <div class=\"field " + fld.getName() + "\"><label class=\"label\" " + title + ">");
+                templateProcessor.appendAsHtmlEncoded(fld.getLabel());
+                templateProcessor.appendHtml(labelDelimiter + "</label>" + fieldSegment + errorSegment + helpSegment + "</div>\n");
             }
         }
 
-        tagProcessor.appendHtml("  <input class=\"button\" type=\"submit\" value=\"");
-        tagProcessor.appendAsHtmlEncoded(buttonTitle);
-        tagProcessor.appendHtml("\" name=\"execute\" />\n");
-        HelpLink.append(tagProcessor, description, helpReference);
+        templateProcessor.appendHtml("  <input class=\"button\" type=\"submit\" value=\"");
+        templateProcessor.appendAsHtmlEncoded(buttonTitle);
+        templateProcessor.appendHtml("\" name=\"execute\" />\n");
+        HelpLink.append(templateProcessor, description, helpReference);
         // TODO alllow forms to be cancelled, returning to previous page.
         // request.appendHtml("  <div class=\"action\"><a class=\"button\" href=\"reset\">Cancel</a></div>");
 
         if (cancelTo != null) {
-            tagProcessor.appendHtml("  <input class=\"button\" type=\"button\" value=\"");
-            tagProcessor.appendAsHtmlEncoded("Cancel");
-            tagProcessor.appendHtml("\" onclick=\"window.location = '" + cancelTo + "'\" name=\"cancel\" />\n");
+            templateProcessor.appendHtml("  <input class=\"button\" type=\"button\" value=\"");
+            templateProcessor.appendAsHtmlEncoded("Cancel");
+            templateProcessor.appendHtml("\" onclick=\"window.location = '" + cancelTo + "'\" name=\"cancel\" />\n");
         }
 
         // TODO reinstate fieldsets when we can specify them
         // request.appendHtml("</fieldset>\n");
-        tagProcessor.appendHtml("</form>\n");
+        templateProcessor.appendHtml("</form>\n");
     }
 
-    private static String createField(final InputField field) {
+    private static String createField(final InputField field, final HtmlEncoder htmlEncoder) {
         if (field.isHidden()) {
             if (field.getType() == InputField.REFERENCE) {
                 return createObjectField(field, "hidden");
@@ -112,18 +113,18 @@ public class HtmlFormBuilder {
             if (field.getType() == InputField.HTML) {
                 return "<span class=\"value\">" + field.getHtml() + "</span>";
             } else if (field.getOptionsText() != null) {
-                return createOptions(field);
+                return createOptions(field, htmlEncoder);
             } else if (field.getType() == InputField.REFERENCE) {
                 return createObjectField(field, "text");
             } else if (field.getType() == InputField.CHECKBOX) {
-                return createCheckbox(field);
+                return createCheckbox(field, htmlEncoder);
             } else if (field.getType() == InputField.PASSWORD) {
-                return createPasswordField(field);
+                return createPasswordField(field, htmlEncoder);
             } else if (field.getType() == InputField.TEXT) {
                 if (field.getHeight() > 1) {
-                    return createTextArea(field);
+                    return createTextArea(field, htmlEncoder);
                 } else {
-                    return createTextField(field);
+                    return createTextField(field, htmlEncoder);
                 }
             } else {
                 throw new UnknownTypeException(field.toString());
@@ -135,7 +136,7 @@ public class HtmlFormBuilder {
         return field.getHtml();
     }
 
-    private static String createTextArea(final InputField field) {
+    private static String createTextArea(final InputField field, final HtmlEncoder htmlEncoder) {
         final String columnsSegment = field.getWidth() == 0 ? "" : " cols=\"" + field.getWidth() / field.getHeight() + "\"";
         final String rowsSegment = field.getHeight() == 0 ? "" : " rows=\"" + field.getHeight() + "\"";
         final String wrapSegment = !field.isWrapped() ? "" : " wrap=\"off\"";
@@ -143,21 +144,21 @@ public class HtmlFormBuilder {
         final String disabled = field.isEditable() ? "" : " disabled=\"disabled\"";
         final String maxLength = field.getMaxLength() == 0 ? "" : " maxlength=\"" + field.getMaxLength() + "\"";
         return "<textarea" + requiredSegment + " name=\"" + field.getName() + "\"" + columnsSegment + rowsSegment + wrapSegment
-                + maxLength + disabled + ">" + TagProcessor.getEncoder().encoder(field.getValue()) + "</textarea>";
+                + maxLength + disabled + ">" + htmlEncoder.encodeHtml(field.getValue()) + "</textarea>";
     }
 
-    private static String createPasswordField(final InputField field) {
+    private static String createPasswordField(final InputField field, final HtmlEncoder htmlEncoder) {
         final String extra = " autocomplete=\"off\"";
-        return createTextField(field, "password", extra);
+        return createTextField(field, "password", extra, htmlEncoder);
     }
 
-    private static String createTextField(final InputField field) {
-        return createTextField(field, "text", "");
+    private static String createTextField(final InputField field, final HtmlEncoder htmlEncoder) {
+        return createTextField(field, "text", "", htmlEncoder);
     }
 
-    private static String createTextField(final InputField field, final String type, final String additionalAttributes) {
+    private static String createTextField(final InputField field, final String type, final String additionalAttributes, final HtmlEncoder htmlEncoder) {
         final String value = field.getValue();
-        final String valueSegment = value == null ? "" : " value=\"" + TagProcessor.getEncoder().encoder(value) + "\"";
+        final String valueSegment = value == null ? "" : " value=\"" + htmlEncoder.encodeHtml(value) + "\"";
         final String lengthSegment = field.getWidth() == 0 ? "" : " size=\"" + field.getWidth() + "\"";
         final String maxLengthSegment = field.getMaxLength() == 0 ? "" : " maxlength=\"" + field.getMaxLength() + "\"";
         final String requiredSegment = !field.isRequired() ? "" : " required";
@@ -166,14 +167,14 @@ public class HtmlFormBuilder {
                 valueSegment + lengthSegment + maxLengthSegment + disabled + additionalAttributes + " />";
     }
 
-    private static String createCheckbox(final InputField field) {
+    private static String createCheckbox(final InputField field, final HtmlEncoder htmlEncoder) {
         final String entryText = field.getValue();
         final String valueSegment = entryText != null && entryText.toLowerCase().equals("true") ? " checked=\"checked\"" : "";
         final String disabled = field.isEditable() ? "" : " disabled=\"disabled\"";
         return "<input type=\"checkbox\" name=\"" + field.getName() + "\" value=\"true\" " + valueSegment + disabled + " />";
     }
 
-    private static String createOptions(final InputField field) {
+    private static String createOptions(final InputField field, final HtmlEncoder htmlEncoder) {
         final String[] options = field.getOptionsText();
         final String[] ids = field.getOptionValues();
         final int length = options.length;
@@ -187,7 +188,7 @@ public class HtmlFormBuilder {
             if (field.getType() == InputField.TEXT && options[i].equals("__other")) {
                 offerOther = true;
             } else {
-                str.append("    <option value=\"" + TagProcessor.getEncoder().encoder(ids[i]) + "\"" + selectedSegment + ">" + TagProcessor.getEncoder().encoder(options[i]) + "</option>\n");
+                str.append("    <option value=\"" + htmlEncoder.encodeHtml(ids[i]) + "\"" + selectedSegment + ">" + htmlEncoder.encodeHtml(options[i]) + "</option>\n");
             }
         }
         if (!field.isRequired() || length == 0) {

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/LogonFormAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/LogonFormAbstract.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/LogonFormAbstract.java
new file mode 100644
index 0000000..cdc7dcd
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/LogonFormAbstract.java
@@ -0,0 +1,86 @@
+package org.apache.isis.viewer.scimpi.dispatcher.view.form;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request.Scope;
+import org.apache.isis.viewer.scimpi.dispatcher.form.FieldEditState;
+import org.apache.isis.viewer.scimpi.dispatcher.form.FormState;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+//TODO combine the common stuff that is found here and in ActionFormAbstract and EditFormAbstract
+public abstract class LogonFormAbstract extends AbstractElementProcessor {
+
+    public static void loginForm(final TemplateProcessor templateProcessor, final String view) {
+        final String object = templateProcessor.getOptionalProperty(OBJECT);
+        final String method = templateProcessor.getOptionalProperty(METHOD, "logon");
+        final String result = templateProcessor.getOptionalProperty(RESULT_NAME, "_user");
+        final String resultScope = templateProcessor.getOptionalProperty(SCOPE, Scope.SESSION.name());
+        final String isisUser = templateProcessor.getOptionalProperty("isis-user", "_web_default");
+        final String formId = templateProcessor.getOptionalProperty(FORM_ID, templateProcessor.nextFormId());
+        final String labelDelimiter = templateProcessor.getOptionalProperty(LABEL_DELIMITER, ":");
+    
+        // TODO error if all values are not set (not if use type is not set and all others are still defaults);
+    
+        if (object != null) {
+            Request context = templateProcessor.getContext();
+            context.addVariable(LOGON_OBJECT, object, Scope.SESSION);
+            context.addVariable(LOGON_METHOD, method, Scope.SESSION);
+            context.addVariable(LOGON_RESULT_NAME, result, Scope.SESSION);
+            context.addVariable(LOGON_SCOPE, resultScope, Scope.SESSION);
+            context.addVariable(PREFIX + "isis-user", isisUser, Scope.SESSION);
+            context.addVariable(LOGON_FORM_ID, formId, Scope.SESSION);
+        }
+        
+        final String error = templateProcessor.getOptionalProperty(ERROR, templateProcessor.getContext().getRequestedFile());
+        final List<HiddenInputField> hiddenFields = new ArrayList<HiddenInputField>();
+        hiddenFields.add(new HiddenInputField(ERROR, error));
+        if (view != null) {
+            hiddenFields.add(new HiddenInputField(VIEW, view));
+        }
+        hiddenFields.add(new HiddenInputField("_" + FORM_ID, formId));
+    
+        final FormState entryState = (FormState) templateProcessor.getContext().getVariable(ENTRY_FIELDS);
+        boolean isforThisForm = entryState != null && entryState.isForForm(formId);
+        if (entryState != null && entryState.isForForm(formId)) {
+        }
+        final InputField nameField = createdField("username", "User Name", InputField.TEXT, isforThisForm ? entryState : null);
+        final String width = templateProcessor.getOptionalProperty("width");
+        if (width != null) {
+            final int w = Integer.valueOf(width).intValue();
+            nameField.setWidth(w);
+        }
+        final InputField passwordField = createdField("password", "Password", InputField.PASSWORD, isforThisForm ? entryState : null);
+        final InputField[] fields = new InputField[] { nameField, passwordField, };
+    
+        final String formTitle = templateProcessor.getOptionalProperty(FORM_TITLE);
+        final String loginButtonTitle = templateProcessor.getOptionalProperty(BUTTON_TITLE, "Log in");
+        final String className = templateProcessor.getOptionalProperty(CLASS, "login");
+        final String id = templateProcessor.getOptionalProperty(ID, "logon");
+    
+        HtmlFormBuilder.createForm(templateProcessor, "logon.app", hiddenFields.toArray(new HiddenInputField[hiddenFields.size()]), fields,
+                className, id, formTitle, labelDelimiter, null, null, loginButtonTitle,
+                isforThisForm && entryState != null ? entryState.getError() : null , null);        
+    }
+
+    protected static InputField createdField(final String fieldName, final String fieldLabel, final int type, final FormState entryState) {
+        final InputField nameField = new InputField(fieldName);
+        nameField.setType(type);
+        nameField.setLabel(fieldLabel);
+        if (entryState != null) {
+            final FieldEditState fieldState = entryState.getField(fieldName);
+            final String entry = fieldState == null ? "" : fieldState.getEntry();
+            nameField.setValue(entry);
+            final String error = fieldState == null ? "" : fieldState.getError();
+            nameField.setErrorText(error);
+        }
+        return nameField;
+    }
+
+    public LogonFormAbstract() {
+        super();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/RadioListField.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/RadioListField.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/RadioListField.java
new file mode 100644
index 0000000..9530834
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/RadioListField.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.view.form;
+
+import java.util.Iterator;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestState;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request.Scope;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+public class RadioListField extends AbstractElementProcessor {
+
+    @Override
+    public void process(final TemplateProcessor templateProcessor, RequestState state) {
+        final FormFieldBlock block = (FormFieldBlock) templateProcessor.peekBlock();
+        final String field = templateProcessor.getRequiredProperty(FIELD);
+        if (block.isVisible(field)) {
+            final String id = templateProcessor.getRequiredProperty(COLLECTION);
+            final String exclude = templateProcessor.getOptionalProperty("exclude");
+
+            final ObjectAdapter collection = templateProcessor.getContext().getMappedObjectOrResult(id);
+
+            final Request context = templateProcessor.getContext();
+            final CollectionFacet facet = collection.getSpecification().getFacet(CollectionFacet.class);
+            final Iterator<ObjectAdapter> iterator = facet.iterator(collection);
+
+            final StringBuffer buffer = new StringBuffer();
+
+            while (iterator.hasNext()) {
+                final ObjectAdapter element = iterator.next();
+                final Scope scope = Scope.INTERACTION;
+                final String elementId = context.mapObject(element, scope);
+                if (exclude != null && context.getMappedObject(exclude) == element) {
+                    continue;
+                }
+                final String title = element.titleString();
+                final String checked = "";
+                buffer.append("<input type=\"radio\" name=\"" + field + "\" value=\"" + elementId + "\"" + checked + " />" + title + "</input><br/>\n");
+            }
+
+            block.replaceContent(field, buffer.toString());
+        }
+    }
+
+    @Override
+    public String getName() {
+        return "radio-list";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/Selector.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/Selector.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/Selector.java
new file mode 100644
index 0000000..effe589
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/Selector.java
@@ -0,0 +1,157 @@
+/*
+ *  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.view.form;
+
+import java.util.Iterator;
+
+import org.apache.isis.core.commons.exceptions.UnknownTypeException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestState;
+import org.apache.isis.viewer.scimpi.dispatcher.context.Request.Scope;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.util.MethodsUtils;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+public class Selector extends AbstractElementProcessor {
+
+    @Override
+    public void process(final TemplateProcessor templateProcessor, RequestState state) {
+        final FormFieldBlock block = (FormFieldBlock) templateProcessor.peekBlock();
+        final String field = templateProcessor.getRequiredProperty(FIELD);
+        if (block.isVisible(field)) {
+            processElement(templateProcessor, block, field);
+        }
+        templateProcessor.skipUntilClose();
+    }
+
+    private void processElement(final TemplateProcessor templateProcessor, final FormFieldBlock block, final String field) {
+        final String type = templateProcessor.getOptionalProperty(TYPE, "dropdown");
+        if (!templateProcessor.isPropertySpecified(METHOD) && templateProcessor.isPropertySpecified(COLLECTION)) {
+            final String id = templateProcessor.getRequiredProperty(COLLECTION, TemplateProcessor.NO_VARIABLE_CHECKING);
+            final String selector = showSelectionList(templateProcessor, id, block.getCurrent(field), block.isNullable(field), type);
+            block.replaceContent(field, selector);
+        } else {
+            final String objectId = templateProcessor.getOptionalProperty(OBJECT);
+            final String methodName = templateProcessor.getRequiredProperty(METHOD);
+            final ObjectAdapter object = MethodsUtils.findObject(templateProcessor.getContext(), objectId);
+            final ObjectAction action = MethodsUtils.findAction(object, methodName);
+            if (action.getParameterCount() == 0) {
+                final ObjectAdapter collection = action.execute(object, new ObjectAdapter[0]);
+                final String selector = showSelectionList(templateProcessor, collection, block.getCurrent(field), block.isNullable(field), type);
+                block.replaceContent(field, selector);
+            } else {
+                final String id = "selector_options";
+                final String id2 = (String) templateProcessor.getContext().getVariable(id);
+                final String selector = showSelectionList(templateProcessor, id2, block.getCurrent(field), block.isNullable(field), type);
+
+                final CreateFormParameter parameters = new CreateFormParameter();
+                parameters.objectId = objectId;
+                parameters.methodName = methodName;
+                parameters.buttonTitle = templateProcessor.getOptionalProperty(BUTTON_TITLE, "Search");
+                parameters.formTitle = templateProcessor.getOptionalProperty(FORM_TITLE);
+                parameters.className = templateProcessor.getOptionalProperty(CLASS, "selector");
+                parameters.id = templateProcessor.getOptionalProperty(ID);
+
+                parameters.resultName = id;
+                parameters.forwardResultTo = templateProcessor.getContext().getResourceFile();
+                parameters.forwardVoidTo = "error";
+                parameters.forwardErrorTo = parameters.forwardResultTo;
+                parameters.scope = Scope.REQUEST.name();
+                templateProcessor.pushNewBuffer();
+                ActionFormAbstract.createForm(templateProcessor, parameters);
+                block.replaceContent(field, selector);
+
+                templateProcessor.appendHtml(templateProcessor.popBuffer());
+            }
+        }
+    }
+
+    private String showSelectionList(final TemplateProcessor templateProcessor, final String collectionId, final ObjectAdapter selectedItem, final boolean allowNotSet, final String type) {
+        if (collectionId != null && !collectionId.equals("")) {
+            final ObjectAdapter collection = templateProcessor.getContext().getMappedObjectOrResult(collectionId);
+            return showSelectionList(templateProcessor, collection, selectedItem, allowNotSet, type);
+        } else {
+            return null;
+        }
+    }
+
+    private String showSelectionList(final TemplateProcessor templateProcessor, final ObjectAdapter collection, final ObjectAdapter selectedItem, final boolean allowNotSet, final String type) {
+        final String field = templateProcessor.getRequiredProperty(FIELD);
+        final CollectionFacet facet = collection.getSpecification().getFacet(CollectionFacet.class);
+
+        if (type.equals("radio")) {
+            return radioButtonList(templateProcessor, field, allowNotSet, collection, selectedItem, facet);
+        } else if (type.equals("list")) {
+            final String size = templateProcessor.getOptionalProperty("size", "5");
+            return dropdownList(templateProcessor, field, allowNotSet, collection, selectedItem, size, facet);
+        } else if (type.equals("dropdown")) {
+            return dropdownList(templateProcessor, field, allowNotSet, collection, selectedItem, null, facet);
+        } else {
+            throw new UnknownTypeException(type);
+        }
+    }
+
+    private String radioButtonList(final TemplateProcessor templateProcessor, final String field, final boolean allowNotSet, final ObjectAdapter collection, final ObjectAdapter selectedItem, final CollectionFacet facet) {
+        final Request context = templateProcessor.getContext();
+        final Iterator<ObjectAdapter> iterator = facet.iterator(collection);
+        final StringBuffer buffer = new StringBuffer();
+        if (allowNotSet) {
+            buffer.append("<input type=\"radio\" name=\"" + field + "\" value=\"null\"></input><br/>\n");
+        }
+        while (iterator.hasNext()) {
+            final ObjectAdapter element = iterator.next();
+            final String elementId = context.mapObject(element, Scope.INTERACTION);
+            final String title = element.titleString();
+            final String checked = element == selectedItem ? "checked=\"checked\"" : "";
+            buffer.append("<input type=\"radio\" name=\"" + field + "\" value=\"" + elementId + "\"" + checked + ">" + title + "</input><br/>\n");
+        }
+
+        return buffer.toString();
+    }
+
+    private String dropdownList(final TemplateProcessor templateProcessor, final String field, final boolean allowNotSet, final ObjectAdapter collection, final ObjectAdapter selectedItem, String size, final CollectionFacet facet) {
+        final Request context = templateProcessor.getContext();
+        final Iterator<ObjectAdapter> iterator = facet.iterator(collection);
+        final StringBuffer buffer = new StringBuffer();
+        size = size == null ? "" : " size =\"" + size + "\"";
+        buffer.append("<select name=\"" + field + "\"" + size + " >\n");
+        if (allowNotSet) {
+            buffer.append("  <option value=\"null\"></option>\n");
+        }
+        while (iterator.hasNext()) {
+            final ObjectAdapter element = iterator.next();
+            final String elementId = context.mapObject(element, Scope.INTERACTION);
+            final String title = element.titleString();
+            final String checked = element == selectedItem ? "selected=\"selected\"" : "";
+            buffer.append("  <option value=\"" + elementId + "\"" + checked + ">" + title + "</option>\n");
+        }
+        buffer.append("</select>\n");
+        return buffer.toString();
+    }
+
+    @Override
+    public String getName() {
+        return "selector";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/SimpleButton.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/SimpleButton.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/SimpleButton.java
new file mode 100644
index 0000000..1a16dde
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/form/SimpleButton.java
@@ -0,0 +1,40 @@
+/*
+ *  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.view.form;
+
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestState;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+public class SimpleButton extends AbstractElementProcessor {
+    @Override
+    public void process(final TemplateProcessor templateProcessor, RequestState state) {
+        final String href = templateProcessor.getRequiredProperty("href");
+        templateProcessor.pushNewBuffer();
+        templateProcessor.processUtilCloseTag();
+        final String text = templateProcessor.popBuffer();
+        templateProcessor.appendHtml("<div class=\"action\"><a class=\"button\" href=\"" + href + "\">" + text + "</a></div>");
+    }
+
+    @Override
+    public String getName() {
+        return "button";
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/7700b437/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/global/Commit.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/global/Commit.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/global/Commit.java
new file mode 100644
index 0000000..f9375f5
--- /dev/null
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/view/global/Commit.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.viewer.scimpi.dispatcher.view.global;
+
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
+import org.apache.isis.viewer.scimpi.dispatcher.context.RequestState;
+import org.apache.isis.viewer.scimpi.dispatcher.processor.TemplateProcessor;
+import org.apache.isis.viewer.scimpi.dispatcher.view.AbstractElementProcessor;
+
+public class Commit extends AbstractElementProcessor {
+
+    @Override
+    public String getName() {
+        return "commit";
+    }
+
+    @Override
+    public void process(final TemplateProcessor templateProcessor, RequestState state) {
+        // Note - the session will have changed since the earlier call if a user
+        // has logged in or out in the action
+        // processing above.
+        final IsisTransactionManager transactionManager = IsisContext.getPersistenceSession().getTransactionManager();
+        if (transactionManager.getTransaction().getState().canCommit()) {
+            transactionManager.endTransaction();
+            transactionManager.startTransaction();
+        }
+    }
+
+}