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.ValueStack;
10 import com.opensymphony.xwork2.util.CompoundRoot;
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: 2007-11-07 08:21:46 +0100 (Wed, 07 Nov 2007) $ $Id: ModelDrivenInterceptor.java 1665 2007-11-07 07:21:46Z mrdon $
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 public String intercept(ActionInvocation invocation) throws Exception {
75 Object action = invocation.getAction();
76
77 if (action instanceof ModelDriven) {
78 ModelDriven modelDriven = (ModelDriven) action;
79 ValueStack stack = invocation.getStack();
80 Object model = modelDriven.getModel();
81 if (model != null) {
82 stack.push(model);
83 }
84 if (refreshModelBeforeResult) {
85 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
86 }
87 }
88 return invocation.invoke();
89 }
90
91 /**
92 * Refreshes the model instance on the value stack, if it has changed
93 */
94 protected static class RefreshModelBeforeResult implements PreResultListener {
95 private Object originalModel = null;
96 protected ModelDriven action;
97
98
99 public RefreshModelBeforeResult(ModelDriven action, Object model) {
100 this.originalModel = model;
101 this.action = action;
102 }
103
104 public void beforeResult(ActionInvocation invocation, String resultCode) {
105 ValueStack stack = invocation.getStack();
106 CompoundRoot root = stack.getRoot();
107
108 boolean needsRefresh = true;
109 Object newModel = action.getModel();
110
111 // Check to see if the new model instance is already on the stack
112 for (Object item : root) {
113 if (item == newModel) {
114 needsRefresh = false;
115 }
116 }
117
118 // Add the new model on the stack
119 if (needsRefresh) {
120
121 // Clear off the old model instance
122 if (originalModel != null) {
123 root.remove(originalModel);
124 }
125 if (newModel != null) {
126 stack.push(newModel);
127 }
128 }
129 }
130 }
131 }