1 /*
2 * Copyright (c) 2002-2006 by OpenSymphony
3 * All rights reserved.
4 */
5 package com.opensymphony.xwork2.interceptor;
6
7 import com.opensymphony.xwork2.ActionInvocation;
8 import com.opensymphony.xwork2.ModelDriven;
9 import com.opensymphony.xwork2.util.CompoundRoot;
10 import com.opensymphony.xwork2.util.ValueStack;
11
12
13 /**
14 * <!-- START SNIPPET: description -->
15 *
16 * Watches for {@link ModelDriven} actions and adds the action's model on to the value stack.
17 *
18 * <p/> <b>Note:</b> The ModelDrivenInterceptor must come before the both {@link StaticParametersInterceptor} and
19 * {@link ParametersInterceptor} if you want the parameters to be applied to the model.
20 *
21 * <p/> <b>Note:</b> The ModelDrivenInterceptor will only push the model into the stack when the
22 * model is not null, else it will be ignored.
23 *
24 * <!-- END SNIPPET: description -->
25 *
26 * <p/> <u>Interceptor parameters:</u>
27 *
28 * <!-- START SNIPPET: parameters -->
29 *
30 * <ul>
31 *
32 * <li>refreshModelBeforeResult - set to true if you want the model to be refreshed on the value stack after action
33 * execution and before result execution. The setting is useful if you want to change the model instance during the
34 * action execution phase, like when loading it from the data layer. This will result in getModel() being called at
35 * least twice.</li>
36 *
37 * </ul>
38 *
39 * <!-- END SNIPPET: parameters -->
40 *
41 * <p/> <u>Extending the interceptor:</u>
42 *
43 * <p/>
44 *
45 * <!-- START SNIPPET: extending -->
46 *
47 * There are no known extension points to this interceptor.
48 *
49 * <!-- END SNIPPET: extending -->
50 *
51 * <p/> <u>Example code:</u>
52 *
53 * <pre>
54 * <!-- START SNIPPET: example -->
55 * <action name="someAction" class="com.examples.SomeAction">
56 * <interceptor-ref name="modelDriven"/>
57 * <interceptor-ref name="basicStack"/>
58 * <result name="success">good_result.ftl</result>
59 * </action>
60 * <!-- END SNIPPET: example -->
61 * </pre>
62 *
63 * @author tm_jee
64 * @version $Date: 2009-07-28 02:25:13 +0200 (Di, 28 Jul 2009) $ $Id: ModelDrivenInterceptor.java 2027 2009-07-28 00:25:13Z musachy $
65 */
66 public class ModelDrivenInterceptor extends AbstractInterceptor {
67
68 protected boolean refreshModelBeforeResult = false;
69
70 public void setRefreshModelBeforeResult(boolean val) {
71 this.refreshModelBeforeResult = val;
72 }
73
74 @Override
75 public String intercept(ActionInvocation invocation) throws Exception {
76 Object action = invocation.getAction();
77
78 if (action instanceof ModelDriven) {
79 ModelDriven modelDriven = (ModelDriven) action;
80 ValueStack stack = invocation.getStack();
81 Object model = modelDriven.getModel();
82 if (model != null) {
83 stack.push(model);
84 }
85 if (refreshModelBeforeResult) {
86 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
87 }
88 }
89 return invocation.invoke();
90 }
91
92 /**
93 * Refreshes the model instance on the value stack, if it has changed
94 */
95 protected static class RefreshModelBeforeResult implements PreResultListener {
96 private Object originalModel = null;
97 protected ModelDriven action;
98
99
100 public RefreshModelBeforeResult(ModelDriven action, Object model) {
101 this.originalModel = model;
102 this.action = action;
103 }
104
105 public void beforeResult(ActionInvocation invocation, String resultCode) {
106 ValueStack stack = invocation.getStack();
107 CompoundRoot root = stack.getRoot();
108
109 boolean needsRefresh = true;
110 Object newModel = action.getModel();
111
112 // Check to see if the new model instance is already on the stack
113 for (Object item : root) {
114 if (item.equals(newModel)) {
115 needsRefresh = false;
116 }
117 }
118
119 // Add the new model on the stack
120 if (needsRefresh) {
121
122 // Clear off the old model instance
123 if (originalModel != null) {
124 root.remove(originalModel);
125 }
126 if (newModel != null) {
127 stack.push(newModel);
128 }
129 }
130 }
131 }
132 }