1. opensymphony
  2. xwork

Commits

mrdon  committed 519cfb6

Adding the ability to refresh the model instance on the value stack after action execution
XW-584

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk@1665e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits 536a864
  • Branches master

Comments (0)

Files changed (2)

File src/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java

View file
  • Ignore whitespace
 import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.ModelDriven;
 import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.CompoundRoot;
 
 
 /**
  *
  * <ul>
  *
- * <li>None</li>
+ * <li>refreshModelBeforeResult - set to true if you want the model to be refreshed on the value stack after action
+ * execution and before result execution.  The setting is useful if you want to change the model instance during the
+ * action execution phase, like when loading it from the data layer.  This will result in getModel() being called at
+ * least twice.</li>
  *
  * </ul>
  *
  */
 public class ModelDrivenInterceptor extends AbstractInterceptor {
 
+    protected boolean refreshModelBeforeResult = false;
+
+    public void setRefreshModelBeforeResult(boolean val) {
+        this.refreshModelBeforeResult = val;
+    }
+
     public String intercept(ActionInvocation invocation) throws Exception {
         Object action = invocation.getAction();
 
             if (model !=  null) {
             	stack.push(model);
             }
+            if (refreshModelBeforeResult) {
+                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
+            }
         }
         return invocation.invoke();
     }
+
+    /**
+     * Refreshes the model instance on the value stack, if it has changed
+     */
+    protected static class RefreshModelBeforeResult implements PreResultListener {
+        private Object originalModel = null;
+        protected ModelDriven action;
+
+
+        public RefreshModelBeforeResult(ModelDriven action, Object model) {
+            this.originalModel = model;
+            this.action = action;
+        }
+
+        public void beforeResult(ActionInvocation invocation, String resultCode) {
+            ValueStack stack = invocation.getStack();
+            CompoundRoot root = stack.getRoot();
+
+            boolean needsRefresh = true;
+            Object newModel = action.getModel();
+
+            // Check to see if the new model instance is already on the stack
+            for (Object item : root) {
+                if (item == newModel) {
+                    needsRefresh = false;
+                }
+            }
+
+            // Add the new model on the stack
+            if (needsRefresh) {
+
+                // Clear off the old model instance
+                if (originalModel != null) {
+                    root.remove(originalModel);
+                }
+                if (newModel != null) {
+                    stack.push(newModel);
+                }
+            }
+        }
+    }
 }

File src/test/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptorTest.java

View file
  • Ignore whitespace
 package com.opensymphony.xwork2.interceptor;
 
 import com.mockobjects.dynamic.Mock;
+import com.mockobjects.dynamic.ConstraintMatcher;
 import com.opensymphony.xwork2.Action;
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ActionInvocation;
     Mock mockActionInvocation;
     ModelDrivenInterceptor modelDrivenInterceptor;
     Object model;
+    PreResultListener preResultListener;
 
 
     public void testModelDrivenGetsPushedOntoStack() throws Exception {
         assertEquals("our model should be on the top of the stack", model, topOfStack);
     }
 
+    public void testModelDrivenUpdatedAndGetsPushedOntoStack() throws Exception {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        action = new ModelDrivenAction();
+        mockActionInvocation.expectAndReturn("getAction", action);
+        mockActionInvocation.matchAndReturn("getStack", stack);
+        mockActionInvocation.expectAndReturn("invoke", "foo");
+        mockActionInvocation.expect("addPreResultListener", new ConstraintMatcher() {
+
+            public boolean matches(Object[] objects) {
+                preResultListener = (PreResultListener) objects[0];
+                return true;
+            }
+
+            public Object[] getConstraints() {
+                return new Object[0];  //To change body of implemented methods use File | Settings | File Templates.
+            }
+        });
+        modelDrivenInterceptor.setRefreshModelBeforeResult(true);
+
+        modelDrivenInterceptor.intercept((ActionInvocation) mockActionInvocation.proxy());
+        assertNotNull(preResultListener);
+        model = "this is my model";
+        preResultListener.beforeResult((ActionInvocation) mockActionInvocation.proxy(), "success");
+
+        Object topOfStack = stack.pop();
+        assertEquals("our model should be on the top of the stack", model, topOfStack);
+        assertEquals(1, stack.getRoot().size());
+    }
+
     public void testStackNotModifedForNormalAction() throws Exception {
         action = new ActionSupport();
         mockActionInvocation.expectAndReturn("getAction", action);
 
 
     public class ModelDrivenAction extends ActionSupport implements ModelDriven {
+
         public Object getModel() {
             return model;
         }
+
     }
 }