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 2013/02/26 00:28:30 UTC

[7/24] git commit: ISIS-351: now rendering recognized exceptions on action panel

ISIS-351: now rendering recognized exceptions on action panel

* if the runtime exception is recognized, then will be rendered on the action panel's feedback
  rather than the fallback ErrorPage
* also ensured call abortTransaction if an application exception is thrown.
* moved the threadlocal logic for notifications from ActionModel and into ActionPanel.


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

Branch: refs/heads/dan/ISIS-233-ro
Commit: eef7356aa18208c1c3d1fb4b63c7c72e05158ef2
Parents: b2b72fe
Author: Dan Haywood <da...@apache.org>
Authored: Fri Feb 22 13:11:28 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Feb 22 13:11:28 2013 +0000

----------------------------------------------------------------------
 .../ComponentFactoryRegistrarDefault.java          |    2 +-
 .../viewer/wicket/model/models/ActionExecutor.java |    4 +-
 .../viewer/wicket/model/models/ActionModel.java    |   22 +--
 .../actions/params/ActionParametersFormPanel.css   |   19 --
 .../actions/params/ActionParametersFormPanel.html  |   39 ----
 .../actions/params/ActionParametersFormPanel.java  |  134 -----------
 .../params/ActionParametersFormPanelFactory.java   |   52 -----
 .../wicket/ui/components/actions/ActionPanel.java  |  173 ++++++++++++--
 .../actions/ActionParametersFormPanel.css          |   19 ++
 .../actions/ActionParametersFormPanel.html         |   39 ++++
 .../actions/ActionParametersFormPanel.java         |  136 +++++++++++
 .../actions/ActionParametersFormPanelFactory.java  |   52 +++++
 .../isis/viewer/wicket/ui/pages/PageAbstract.java  |    5 +-
 13 files changed, 405 insertions(+), 291 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
index 8f55d0b..1de840b 100644
--- a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
+++ b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
@@ -24,12 +24,12 @@ import java.util.ServiceLoader;
 import com.google.inject.Singleton;
 
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
-import org.apache.isis.viewer.wicket.ui.actions.params.ActionParametersFormPanelFactory;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistrar;
 import org.apache.isis.viewer.wicket.ui.components.about.AboutPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actionlink.ActionLinkPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionInfoPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.actions.ActionParametersFormPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.appactions.cssmenu.AppActionsCssMenuFactory;
 import org.apache.isis.viewer.wicket.ui.components.bookmarkedpages.BookmarkedPagesPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanelFactory;

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionExecutor.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionExecutor.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionExecutor.java
index 7869182..ec73fcd 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionExecutor.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionExecutor.java
@@ -21,12 +21,14 @@ package org.apache.isis.viewer.wicket.model.models;
 
 import java.io.Serializable;
 
+import org.apache.wicket.MarkupContainer;
+
 /**
  * Decouples the {@link ActionModel}, which needs to delegate the actual
  * execution of an action, from its implementor.
  */
 public interface ActionExecutor extends Serializable {
 
-    void executeActionAndProcessResults();
+    void executeActionAndProcessResults(MarkupContainer paramForm);
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
index aed3834..1df27ab 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
@@ -440,30 +440,16 @@ public class ActionModel extends BookmarkableModel<ObjectAdapter> {
     }
 
     
-    // TODO: hacky!!
-    public static ThreadLocal<String> applicationError = new ThreadLocal<String>();
     
     private ObjectAdapter executeAction() {
         final ObjectAdapter targetAdapter = getTargetAdapter();
         final ObjectAdapter[] arguments = getArgumentsAsArray();
         final ObjectAction action = getActionMemento().getAction();
-        try {
-            final ObjectAdapter results = action.execute(targetAdapter, arguments);
-            return results;
-        } catch(RuntimeException ex) {
-            final ApplicationException appEx = getApplicationExceptionIfAny(ex);
-            if(appEx != null) {
-                applicationError.set(appEx.getMessage());
-                return null;
-            }
-            throw ex;
-        }
-    }
 
-    private ApplicationException getApplicationExceptionIfAny(Exception ex) {
-        Iterable<ApplicationException> appEx = Iterables.filter(Throwables.getCausalChain(ex), ApplicationException.class);
-        Iterator<ApplicationException> iterator = appEx.iterator();
-        return iterator.hasNext() ? iterator.next() : null;
+        // let any exceptions propogate, will be caught by UI layer 
+        // (ActionPanel at time of writing)
+        final ObjectAdapter results = action.execute(targetAdapter, arguments);
+        return results;
     }
 
     public String getReasonInvalidIfAny() {

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.css
deleted file mode 100644
index 9f1612a..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.css
+++ /dev/null
@@ -1,19 +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.
- */
-

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.html
deleted file mode 100644
index 87c6033..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-  
-         http://www.apache.org/licenses/LICENSE-2.0
-         
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<html>
-	<body>
-		<wicket:panel>
-			<div class="actionParametersForm inputForm">
-			    <form wicket:id="inputForm" 
-			    	method="post"> 
-			    	<fieldset class="inputFormTable parameters">
-				    	<div wicket:id="parameters" class="parameter">
-			              <div wicket:id="scalarNameAndValue">[scalar]</div>
-				    	</div>
-	   	      			<span wicket:id="feedback"></span>
-				    	<div class="buttons">
-				    		<input type="submit" wicket:id="okButton" value="OK" class="okButton"/> 
-				    	</div>
-			    	</fieldset>
-				</form>
-			</div>
-		</wicket:panel>
-	</body>
-</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.java
deleted file mode 100644
index b875f5a..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanel.java
+++ /dev/null
@@ -1,134 +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.wicket.ui.actions.params;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.nullValue;
-
-import java.util.List;
-
-import com.google.common.collect.Lists;
-
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.form.Button;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.markup.repeater.RepeatingView;
-
-import org.apache.isis.core.commons.ensure.Ensure;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
-import org.apache.isis.viewer.wicket.model.mementos.ActionParameterMemento;
-import org.apache.isis.viewer.wicket.model.models.ActionExecutor;
-import org.apache.isis.viewer.wicket.model.models.ActionModel;
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
-import org.apache.isis.viewer.wicket.model.util.Mementos;
-import org.apache.isis.viewer.wicket.ui.ComponentType;
-import org.apache.isis.viewer.wicket.ui.components.widgets.formcomponent.FormFeedbackPanel;
-import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
-
-/**
- * {@link PanelAbstract Panel} to capture the arguments for an action
- * invocation.
- */
-public class ActionParametersFormPanel extends PanelAbstract<ActionModel> {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final String ID_OK_BUTTON = "okButton";
-    private static final String ID_ACTION_PARAMETERS = "parameters";
-
-    private final ActionExecutor actionExecutor;
-
-    public ActionParametersFormPanel(final String id, final ActionModel model) {
-        super(id, model);
-
-        Ensure.ensureThatArg(model.getExecutor(), is(not(nullValue())));
-
-        this.actionExecutor = model.getExecutor();
-        buildGui();
-    }
-
-    private void buildGui() {
-        add(new ActionParameterForm("inputForm", getModel()));
-    }
-
-    class ActionParameterForm extends Form<ObjectAdapter> {
-
-        private static final long serialVersionUID = 1L;
-
-        private static final String ID_FEEDBACK = "feedback";
-
-        public ActionParameterForm(final String id, final ActionModel actionModel) {
-            super(id, actionModel);
-
-            addParameters();
-
-            addOrReplace(new FormFeedbackPanel(ID_FEEDBACK));
-            addOkButton();
-        }
-
-        private ActionModel getActionModel() {
-            return (ActionModel) super.getModel();
-        }
-
-        private void addParameters() {
-            final ActionModel actionModel = getActionModel();
-            final ObjectAction objectAction = actionModel.getActionMemento().getAction();
-            
-            final List<ObjectActionParameter> parameters = objectAction.getParameters();
-            
-            final List<ActionParameterMemento> mementos = buildParameterMementos(parameters);
-            for (final ActionParameterMemento apm1 : mementos) {
-                actionModel.getArgumentModel(apm1);
-            }
-            
-            final RepeatingView rv = new RepeatingView(ID_ACTION_PARAMETERS);
-            add(rv);
-            for (final ActionParameterMemento apm : mementos) {
-                final WebMarkupContainer container = new WebMarkupContainer(rv.newChildId());
-                rv.add(container);
-
-                final ScalarModel argumentModel = actionModel.getArgumentModel(apm);
-                getComponentFactoryRegistry().addOrReplaceComponent(container, ComponentType.SCALAR_NAME_AND_VALUE, argumentModel);
-            }
-        }
-
-        private void addOkButton() {
-            add(new Button(ID_OK_BUTTON) {
-                private static final long serialVersionUID = 1L;
-
-                @Override
-                public void onSubmit() {
-                    actionExecutor.executeActionAndProcessResults();
-                };
-            });
-        }
-
-        private List<ActionParameterMemento> buildParameterMementos(final List<ObjectActionParameter> parameters) {
-            final List<ActionParameterMemento> parameterMementoList = Lists.transform(parameters, Mementos.fromActionParameter());
-            // we copy into a new array list otherwise we get lazy evaluation =
-            // reference to a non-serializable object
-            return Lists.newArrayList(parameterMementoList);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanelFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanelFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanelFactory.java
deleted file mode 100644
index 0d67112..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actions/params/ActionParametersFormPanelFactory.java
+++ /dev/null
@@ -1,52 +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.wicket.ui.actions.params;
-
-import org.apache.wicket.Component;
-import org.apache.wicket.model.IModel;
-
-import org.apache.isis.viewer.wicket.model.models.ActionModel;
-import org.apache.isis.viewer.wicket.ui.ComponentFactory;
-import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
-import org.apache.isis.viewer.wicket.ui.ComponentType;
-
-/**
- * {@link ComponentFactory} for {@link ActionParametersFormPanel}.
- */
-public class ActionParametersFormPanelFactory extends ComponentFactoryAbstract {
-
-    private static final long serialVersionUID = 1L;
-
-    public ActionParametersFormPanelFactory() {
-        super(ComponentType.PARAMETERS);
-    }
-
-    @Override
-    public ApplicationAdvice appliesTo(final IModel<?> model) {
-        return appliesIf(model instanceof ActionModel);
-    }
-
-    @Override
-    public Component createComponent(final String id, final IModel<?> model) {
-        final ActionModel actionModel = (ActionModel) model;
-        return new ActionParametersFormPanel(id, actionModel);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
index fd9cacb..367a469 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
@@ -20,18 +20,26 @@
 package org.apache.isis.viewer.wicket.ui.components.actions;
 
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 
+import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.model.Model;
 
+import org.apache.isis.applib.ApplicationException;
 import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
+import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
 import org.apache.isis.viewer.wicket.model.common.SelectionHandler;
 import org.apache.isis.viewer.wicket.model.isis.PersistenceSessionProvider;
 import org.apache.isis.viewer.wicket.model.models.ActionExecutor;
@@ -44,9 +52,13 @@ import org.apache.isis.viewer.wicket.model.models.ValueModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
 import org.apache.isis.viewer.wicket.ui.pages.BookmarkedPagesModelProvider;
+import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
 /**
  * {@link PanelAbstract Panel} representing an action invocation, backed by an
  * {@link ActionModel}.
@@ -82,7 +94,7 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
         if (actionModel.getActionMode() == ActionModel.Mode.PARAMETERS) {
             buildGuiForParameters(actionModel);
         } else {
-            executeActionAndProcessResults();
+            executeActionAndProcessResults(null);
         }
     }
 
@@ -108,38 +120,29 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
         return application.getBookmarkedPagesModel();
     }
 
+    
+    /**
+     * @param feedbackForm - for feedback messages.
+     */
     @Override
-    public void executeActionAndProcessResults() {
+    public void executeActionAndProcessResults(MarkupContainer feedbackForm) {
 
         permanentlyHide(ComponentType.ENTITY_ICON_AND_TITLE);
-        
 
         ObjectAdapter targetAdapter = null;
+        boolean clearArgs = true;
         try {
+
             targetAdapter = getModel().getTargetAdapter();
 
-            // validate the action parameters (if any)
-            final ActionModel actionModel = getActionModel();
-            final String invalidReasonIfAny = actionModel.getReasonInvalidIfAny();
-            if (invalidReasonIfAny != null) {
-                error(invalidReasonIfAny);
-                return;
-            }
+            // no concurrency exception, so continue...
+            clearArgs = executeActionOnTargetAndProcessResults(targetAdapter, feedbackForm);
 
-            // executes the action
-            ObjectAdapter resultAdapter = actionModel.getObject();
-            
-            final ResultType resultType = ResultType.determineFor(resultAdapter);
-            resultType.addResults(this, resultAdapter);
-            
-            if(actionModel.hasSafeActionSemantics()) {
-                bookmarkPage(actionModel);
-            }
+        } catch (ConcurrencyException ex) {
 
-        } catch(ConcurrencyException ex) {
-            
-            // second attempt should succeed, because the Oid would have been updated in the attempt
-            if(targetAdapter == null) {
+            // second attempt should succeed, because the Oid would have
+            // been updated in the attempt
+            if (targetAdapter == null) {
                 targetAdapter = getModel().getTargetAdapter();
             }
 
@@ -148,12 +151,116 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
             resultType.addResults(this, targetAdapter, ex);
 
             return;
+            
         } finally {
-            final ActionModel actionModel = getActionModel();
-            actionModel.clearArguments();
+            if(clearArgs) {
+                getActionModel().clearArguments();
+            }
         }
     }
 
+    /**
+     * @return - whether action arguments should be cleared or not.
+     */
+    private boolean executeActionOnTargetAndProcessResults(ObjectAdapter targetAdapter, MarkupContainer feedbackOwner) {
+
+        // validate the action parameters (if any)
+        final ActionModel actionModel = getActionModel();
+        final String invalidReasonIfAny = actionModel.getReasonInvalidIfAny();
+        if (invalidReasonIfAny != null) {
+            feedbackOwner.error(invalidReasonIfAny);
+            return false;
+        }
+
+        // the object store could raise an exception (eg uniqueness constraint)
+        // so we handle it here.
+        try {
+            // could be programmatic flushing, so must include in the try... finally
+            final ObjectAdapter resultAdapter = executeActionHandlingApplicationExceptions(feedbackOwner);
+    
+            final ResultType resultType = ResultType.determineFor(resultAdapter);
+            
+            // this will flush any queued changes, so exception (if any)
+            // will be thrown here
+            resultType.addResults(this, resultAdapter);
+
+        } catch (RuntimeException ex) {
+
+            // see if the exception is recognized as being a non-serious error
+            // (nb: similar code in WebRequestCycleForIsis, as a fallback)
+            List<ExceptionRecognizer> exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
+            String message = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
+            if(message != null) {
+                // recognized
+                feedbackOwner.error(message);
+                getTransactionManager().abortTransaction();
+                return false;
+            }
+
+            // not handled, so propagate
+            throw ex;
+        }
+
+        if (actionModel.hasSafeActionSemantics()) {
+            bookmarkPage(actionModel);
+        }
+
+        return true;
+    }
+
+    /**
+     * The executeAction method will set a value on the thread if an
+     * {@link ApplicationException} is thrown.  This will allow the exception
+     * to be rendered in the usual way (using jGrowl).  Once rendered,
+     * this {@link ThreadLocal} will be cleared (see {@link PageAbstract}).
+     * 
+     * <p>
+     * Using a {@link ThreadLocal} is always a  bit hacky, but will do, I think.
+     */
+    public static ThreadLocal<String> applicationError = new ThreadLocal<String>();
+
+
+    /**
+     * Executes the action, handling any {@link ApplicationException}s that
+     * might be encountered.
+     * 
+     * <p>
+     * If an {@link ApplicationException} is encountered, then the {@link #applicationError} thread-local
+     * will be set so that a suitable message can be rendered, and the current {@link IsisTransaction transaction}
+     * will also be aborted.
+     * 
+     * <p>
+     * Any other types of exception will be ignored (to be picked up higher up in the callstack).
+     * @param feedbackOwner 
+     */
+    private ObjectAdapter executeActionHandlingApplicationExceptions(MarkupContainer feedbackOwner) {
+        final ActionModel actionModel = getActionModel();
+        try {
+            ObjectAdapter resultAdapter = actionModel.getObject();
+            return resultAdapter;
+
+        } catch (RuntimeException ex) {
+
+            // see if is an application-defined exception
+            final ApplicationException appEx = getApplicationExceptionIfAny(ex);
+            if (appEx != null) {
+                applicationError.set(appEx.getMessage());
+                getTransactionManager().abortTransaction();
+                return null;
+            } 
+
+            // not handled, so propagate
+            throw ex;
+        }
+    }
+
+    private ApplicationException getApplicationExceptionIfAny(Exception ex) {
+        Iterable<ApplicationException> appEx = Iterables.filter(Throwables.getCausalChain(ex), ApplicationException.class);
+        Iterator<ApplicationException> iterator = appEx.iterator();
+        return iterator.hasNext() ? iterator.next() : null;
+    }
+
+
     enum ResultType {
         OBJECT {
             @Override
@@ -317,4 +424,20 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
         hideAllBut();
     }
 
+
+    ///////////////////////////////////////////////////////
+    // Dependencies (from context)
+    ///////////////////////////////////////////////////////
+    
+    protected IsisTransactionManager getTransactionManager() {
+        return IsisContext.getTransactionManager();
+    }
+
+    /**
+     * Factored out so can be overridden in testing.
+     */
+    protected ServicesInjector getServicesInjector() {
+        return IsisContext.getPersistenceSession().getServicesInjector();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.css
new file mode 100644
index 0000000..9f1612a
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.css
@@ -0,0 +1,19 @@
+/*
+ *  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.
+ */
+

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.html
new file mode 100644
index 0000000..87c6033
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.html
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+         http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html>
+	<body>
+		<wicket:panel>
+			<div class="actionParametersForm inputForm">
+			    <form wicket:id="inputForm" 
+			    	method="post"> 
+			    	<fieldset class="inputFormTable parameters">
+				    	<div wicket:id="parameters" class="parameter">
+			              <div wicket:id="scalarNameAndValue">[scalar]</div>
+				    	</div>
+	   	      			<span wicket:id="feedback"></span>
+				    	<div class="buttons">
+				    		<input type="submit" wicket:id="okButton" value="OK" class="okButton"/> 
+				    	</div>
+			    	</fieldset>
+				</form>
+			</div>
+		</wicket:panel>
+	</body>
+</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
new file mode 100644
index 0000000..90651ea
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.actions;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.repeater.RepeatingView;
+
+import org.apache.isis.core.commons.ensure.Ensure;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.viewer.wicket.model.mementos.ActionParameterMemento;
+import org.apache.isis.viewer.wicket.model.models.ActionExecutor;
+import org.apache.isis.viewer.wicket.model.models.ActionModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.util.Mementos;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.widgets.formcomponent.FormFeedbackPanel;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+/**
+ * {@link PanelAbstract Panel} to capture the arguments for an action
+ * invocation.
+ */
+public class ActionParametersFormPanel extends PanelAbstract<ActionModel> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ID_OK_BUTTON = "okButton";
+    private static final String ID_ACTION_PARAMETERS = "parameters";
+
+    private final ActionExecutor actionExecutor;
+
+    public ActionParametersFormPanel(final String id, final ActionModel model) {
+        super(id, model);
+
+        Ensure.ensureThatArg(model.getExecutor(), is(not(nullValue())));
+
+        this.actionExecutor = model.getExecutor();
+        buildGui();
+    }
+
+    private void buildGui() {
+        add(new ActionParameterForm("inputForm", getModel()));
+    }
+
+    class ActionParameterForm extends Form<ObjectAdapter> {
+
+        private static final long serialVersionUID = 1L;
+
+        private static final String ID_FEEDBACK = "feedback";
+
+        public ActionParameterForm(final String id, final ActionModel actionModel) {
+            super(id, actionModel);
+
+            addParameters();
+
+            FormFeedbackPanel formFeedback = new FormFeedbackPanel(ID_FEEDBACK);
+            formFeedback.setEscapeModelStrings(false);
+            addOrReplace(formFeedback);
+            addOkButton();
+        }
+
+        private ActionModel getActionModel() {
+            return (ActionModel) super.getModel();
+        }
+
+        private void addParameters() {
+            final ActionModel actionModel = getActionModel();
+            final ObjectAction objectAction = actionModel.getActionMemento().getAction();
+            
+            final List<ObjectActionParameter> parameters = objectAction.getParameters();
+            
+            final List<ActionParameterMemento> mementos = buildParameterMementos(parameters);
+            for (final ActionParameterMemento apm1 : mementos) {
+                actionModel.getArgumentModel(apm1);
+            }
+            
+            final RepeatingView rv = new RepeatingView(ID_ACTION_PARAMETERS);
+            add(rv);
+            for (final ActionParameterMemento apm : mementos) {
+                final WebMarkupContainer container = new WebMarkupContainer(rv.newChildId());
+                rv.add(container);
+
+                final ScalarModel argumentModel = actionModel.getArgumentModel(apm);
+                getComponentFactoryRegistry().addOrReplaceComponent(container, ComponentType.SCALAR_NAME_AND_VALUE, argumentModel);
+            }
+        }
+
+        private void addOkButton() {
+            add(new Button(ID_OK_BUTTON) {
+                private static final long serialVersionUID = 1L;
+
+                @Override
+                public void onSubmit() {
+                    actionExecutor.executeActionAndProcessResults(ActionParameterForm.this);
+                };
+            });
+        }
+
+        private List<ActionParameterMemento> buildParameterMementos(final List<ObjectActionParameter> parameters) {
+            final List<ActionParameterMemento> parameterMementoList = Lists.transform(parameters, Mementos.fromActionParameter());
+            // we copy into a new array list otherwise we get lazy evaluation =
+            // reference to a non-serializable object
+            return Lists.newArrayList(parameterMementoList);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanelFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanelFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanelFactory.java
new file mode 100644
index 0000000..95229f0
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanelFactory.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.actions;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+
+import org.apache.isis.viewer.wicket.model.models.ActionModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+
+/**
+ * {@link ComponentFactory} for {@link ActionParametersFormPanel}.
+ */
+public class ActionParametersFormPanelFactory extends ComponentFactoryAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    public ActionParametersFormPanelFactory() {
+        super(ComponentType.PARAMETERS);
+    }
+
+    @Override
+    public ApplicationAdvice appliesTo(final IModel<?> model) {
+        return appliesIf(model instanceof ActionModel);
+    }
+
+    @Override
+    public Component createComponent(final String id, final IModel<?> model) {
+        final ActionModel actionModel = (ActionModel) model;
+        return new ActionParametersFormPanel(id, actionModel);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eef7356a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
index 66e10b6..7b36cff 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
@@ -38,6 +38,7 @@ import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistryAccessor;
+import org.apache.isis.viewer.wicket.ui.components.actions.ActionPanel;
 import org.apache.isis.viewer.wicket.ui.pages.about.AboutPage;
 import org.apache.isis.viewer.wicket.ui.pages.login.WicketSignInPage;
 import org.apache.log4j.Logger;
@@ -158,12 +159,12 @@ public abstract class PageAbstract extends WebPage {
         }
         
         try {
-            final String error = ActionModel.applicationError.get();
+            final String error = ActionPanel.applicationError.get();
             if(error!=null) {
                 addJGrowlCall(error, "ERROR", true, buf);
             }
         } finally {
-            ActionModel.applicationError.remove();
+            ActionPanel.applicationError.remove();
         }
         return buf.toString();
     }