1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.nuiton.validator.xwork2;
23
24 import com.google.common.collect.Maps;
25 import com.opensymphony.xwork2.ActionContext;
26 import com.opensymphony.xwork2.ActionProxy;
27 import com.opensymphony.xwork2.ActionProxyFactory;
28 import com.opensymphony.xwork2.DefaultActionInvocation;
29 import com.opensymphony.xwork2.ObjectFactory;
30 import com.opensymphony.xwork2.Result;
31 import com.opensymphony.xwork2.UnknownHandler;
32 import com.opensymphony.xwork2.config.Configuration;
33 import com.opensymphony.xwork2.config.ConfigurationManager;
34 import com.opensymphony.xwork2.config.entities.ActionConfig;
35 import com.opensymphony.xwork2.inject.Container;
36 import com.opensymphony.xwork2.inject.Inject;
37 import com.opensymphony.xwork2.util.ValueStack;
38 import com.opensymphony.xwork2.util.ValueStackFactory;
39 import com.opensymphony.xwork2.validator.ActionValidatorManager;
40 import com.opensymphony.xwork2.validator.FieldValidator;
41 import com.opensymphony.xwork2.validator.Validator;
42 import org.apache.commons.logging.Log;
43 import org.apache.commons.logging.LogFactory;
44 import org.nuiton.util.beans.BeanUtil;
45 import org.nuiton.validator.NuitonValidatorScope;
46
47 import java.util.HashSet;
48 import java.util.Map;
49 import java.util.Set;
50 import java.util.TreeMap;
51
52
53
54
55
56
57
58 public class XWork2ValidatorUtil {
59
60
61 private static final Log log = LogFactory.getLog(XWork2ValidatorUtil.class);
62
63
64
65
66
67 static private ValueStack sharedValueStack;
68
69 public static ValueStack getSharedValueStack() {
70 if (sharedValueStack == null) {
71
72
73 sharedValueStack = createValuestack();
74 if (log.isDebugEnabled()) {
75 log.debug("init shared value stack " + sharedValueStack);
76 }
77 }
78 return sharedValueStack;
79 }
80
81
82
83
84
85
86
87 public static void setSharedValueStack(ValueStack sharedValueStack) {
88 if (log.isDebugEnabled()) {
89 log.debug("set shared value stack " + sharedValueStack);
90 }
91 XWork2ValidatorUtil.sharedValueStack = sharedValueStack;
92 }
93
94 public static ValueStack createValuestack() {
95
96 ValueStack result;
97
98 ActionContext context = ActionContext.getContext();
99 if (context == null) {
100
101
102 ConfigurationManager confManager = new ConfigurationManager("xwork");
103 Configuration conf = confManager.getConfiguration();
104 Container container = conf.getContainer();
105 ValueStackFactory stackFactory = container.getInstance(ValueStackFactory.class);
106 result = stackFactory.createValueStack();
107 } else {
108
109
110 result = context.getValueStack();
111
112 if (result == null) {
113
114
115 ValueStackFactory stackFactory = context.getInstance(ValueStackFactory.class);
116 result = stackFactory.createValueStack();
117 }
118 }
119 return result;
120 }
121
122 public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, String contextName,
123 Set<String> fields) {
124 return newXWorkScopeValidator(beanClass, contextName, fields, getSharedValueStack());
125 }
126
127 public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, String contextName,
128 Set<String> fields, ValueStack vs) {
129
130 return new XWork2ScopeValidator<O>(beanClass, contextName, fields, vs);
131 }
132
133
134 public static String getContextForScope(String context, NuitonValidatorScope scope) {
135 return (context == null ? "" : context + "-") + scope.name().toLowerCase();
136 }
137
138 protected static ActionValidatorManager newValidationManager(ValueStack vs) {
139
140 if (vs == null) {
141 vs = createValuestack();
142
143 if (log.isDebugEnabled()) {
144 log.debug("create a standalone value stack " + vs);
145 }
146 } else {
147 if (log.isDebugEnabled()) {
148 log.debug("use given value stack " + vs);
149 }
150 }
151
152 ActionContext context = ActionContext.getContext();
153
154 if (context == null) {
155 context = new ActionContext(vs.getContext());
156
157
158
159
160
161 ActionContext.setContext(context);
162
163 }
164 Container container = context.getContainer();
165
166 if (context.getActionInvocation() == null) {
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 Map<String, Object> extraContext = Maps.newHashMap();
187 extraContext.put(ActionContext.VALUE_STACK, vs);
188 DefaultActionInvocation invocation = new DefaultActionInvocation(extraContext, false);
189 invocation.setObjectFactory(container.getInstance(ObjectFactory.class));
190 invocation.setContainer(container);
191
192 ActionProxyFactory actionProxyFactory = context.getInstance(ActionProxyFactory.class);
193 ActionProxy actionProxy = actionProxyFactory.createActionProxy(invocation, "java.lang", "java.lang.Object", null, false, false);
194 invocation.init(actionProxy);
195 context.setActionInvocation(invocation);
196
197 }
198
199
200 ActionValidatorManager validatorManager =
201 container.getInstance(ActionValidatorManager.class, "no-annotations");
202
203
204
205
206
207
208
209
210
211
212 return validatorManager;
213 }
214
215 public static <O> Map<NuitonValidatorScope, String[]> detectFields(Class<O> type, String context,
216 NuitonValidatorScope[] scopeUniverse) {
217
218 Set<String> availableFields = BeanUtil.getReadableProperties(type);
219
220 ActionValidatorManager validatorManager = newValidationManager(getSharedValueStack());
221
222 Map<NuitonValidatorScope, String[]> fields = new TreeMap<NuitonValidatorScope, String[]>();
223
224 for (NuitonValidatorScope scope : scopeUniverse) {
225
226 Set<String> fieldNames =
227 detectFieldsForScope(validatorManager, type, scope, context, availableFields, false);
228
229 if (log.isDebugEnabled()) {
230 log.debug("detected validator fields for scope " + scope +
231 ":" + context + " : " + fieldNames);
232 }
233
234 if (!fieldNames.isEmpty()) {
235
236
237
238 fields.put(scope, fieldNames.toArray(new String[fieldNames.size()]));
239 }
240 }
241
242 return fields;
243
244 }
245
246 protected static Set<String> detectFieldsForScope(ActionValidatorManager validator,
247 Class<?> type,
248 NuitonValidatorScope scope,
249 String context,
250 Set<String> availableFields,
251 boolean includeDefaultContext) {
252
253 String scopeContext = getContextForScope(context, scope);
254
255 Set<String> fields = new HashSet<String>();
256
257 int skip = 0;
258 if (scopeContext != null && !includeDefaultContext) {
259
260 for (Validator<?> v : validator.getValidators(type, null)) {
261
262 if (v instanceof FieldValidator) {
263 skip++;
264 }
265 }
266 }
267
268 for (Validator<?> v : validator.getValidators(type, scopeContext)) {
269
270
271 if (v instanceof FieldValidator) {
272 if (skip > 0) {
273 skip--;
274 continue;
275 }
276 FieldValidator fieldValidator = (FieldValidator) v;
277 if (log.isDebugEnabled()) {
278 log.debug("context " + context + " - field " +
279 fieldValidator.getFieldName());
280 }
281 String fName = fieldValidator.getFieldName();
282 if (availableFields.contains(fName)) {
283
284
285 fields.add(fName);
286 } else {
287
288 if (BeanUtil.isNestedReadableProperty(type, fName)) {
289
290 fields.add(fName);
291
292 } else {
293
294 String message =
295 "Field " + fName + " in scope [" + scopeContext + "] is not a readable property of " +
296 type.getName();
297 if (log.isErrorEnabled()) {
298 log.error(message);
299 }
300 throw new IllegalStateException(message);
301 }
302 }
303 }
304 }
305
306 return fields;
307 }
308
309
310
311
312
313
314
315
316
317
318 public static class NuitonDefaultUnknownHandler implements UnknownHandler {
319
320 protected Configuration configuration;
321
322 protected ObjectFactory objectFactory;
323
324 @Inject
325 public void setConfiguration(Configuration configuration) {
326 this.configuration = configuration;
327 }
328
329 @Inject
330 public void setObjectFactory(ObjectFactory objectFactory) {
331 this.objectFactory = objectFactory;
332 }
333
334 @Override
335 public ActionConfig handleUnknownAction(String namespace, String actionName) {
336 return new ActionConfig.Builder(namespace, actionName, Object.class.getName()).build();
337 }
338
339 @Override
340 public Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig, String resultCode) {
341 return null;
342 }
343
344 @Override
345 public Object handleUnknownActionMethod(Object action, String methodName) {
346 return null;
347 }
348 }
349 }