1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.xmlfield.validation;
17
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static com.google.common.collect.Iterables.toArray;
20 import static org.apache.commons.lang.StringUtils.isBlank;
21 import static org.xmlfield.core.internal.XmlFieldUtils.getXmlFieldNode;
22
23 import java.lang.reflect.AccessibleObject;
24 import java.lang.reflect.Field;
25 import java.lang.reflect.InvocationHandler;
26 import java.lang.reflect.Method;
27 import java.lang.reflect.Proxy;
28 import java.util.ArrayList;
29 import java.util.List;
30
31 import org.xmlfield.core.api.XmlFieldNode;
32 import org.xmlfield.core.api.XmlFieldNodeList;
33 import org.xmlfield.core.api.XmlFieldSelector;
34 import org.xmlfield.core.api.XmlFieldSelectorFactory;
35 import org.xmlfield.core.exception.XmlFieldXPathException;
36 import org.xmlfield.core.internal.NamespaceMap;
37 import org.xmlfield.validation.annotations.XPathEquals;
38
39
40
41
42
43
44
45 @Deprecated
46 public class XPathValidation {
47
48 private static class ExplosiveValidatorInvocationHandler implements InvocationHandler {
49
50 private final XmlFieldNode node;
51
52 public ExplosiveValidatorInvocationHandler(final XmlFieldNode node) {
53
54 this.node = checkNotNull(node, "node");
55 }
56
57 @Override
58 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
59
60 handleXPathEquals(EXPLOSIVE_CALLBACK, method, method.getName(), null, node);
61
62 return null;
63 }
64 }
65
66 private static interface HandleXPathCallback {
67
68 void handleXPathEquals(String message);
69 }
70
71 private static class ValidatorWithErrorsInvocationHandler implements InvocationHandler {
72
73 private final XmlFieldNode node;
74
75 public ValidatorWithErrorsInvocationHandler(final XmlFieldNode node) {
76
77 this.node = checkNotNull(node, "node");
78 }
79
80 @Override
81 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
82
83 final String[] error = new String[1];
84
85 handleXPathEquals(new HandleXPathCallback() {
86
87 @Override
88 public void handleXPathEquals(final String message) {
89
90 error[0] = message;
91 }
92
93 }, method, method.getName(), null, node);
94
95 return error[0];
96 }
97 }
98
99 private static final HandleXPathCallback EXPLOSIVE_CALLBACK = new HandleXPathCallback() {
100
101 @Override
102 public void handleXPathEquals(final String message) {
103
104 throw new AssertionError(message);
105 }
106 };
107
108 public static <T> T getExplosiveValidator(final Object object, final Class<T> validatorClass) {
109
110 return getExplosiveValidator(getXmlFieldNode(object), validatorClass);
111 }
112
113 public static <T> T getExplosiveValidator(final XmlFieldNode node, final Class<T> validatorClass) {
114
115 final Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class<?>[] { validatorClass },
116 new ExplosiveValidatorInvocationHandler(node));
117
118 return validatorClass.cast(proxy);
119
120 }
121
122 public static String[] getValidationErrors(final Object object, final Class<?>... validationClasses)
123 throws XmlFieldXPathException {
124
125 return getValidationErrors(getXmlFieldNode(object), validationClasses);
126 }
127
128 public static String[] getValidationErrors(final XmlFieldNode node, final Class<?>... validationClasses)
129 throws XmlFieldXPathException {
130
131 final List<String> errors = new ArrayList<String>();
132
133 validate(new HandleXPathCallback() {
134
135 @Override
136 public void handleXPathEquals(final String message) {
137
138 errors.add(message);
139 }
140
141 }, node, validationClasses);
142
143 return toArray(errors, String.class);
144 }
145
146 public static <T> T getValidatorWithErrors(final Object object, final Class<T> validatorClass) {
147 return getValidatorWithErrors(getXmlFieldNode(object), validatorClass);
148 }
149
150 public static <T> T getValidatorWithErrors(final XmlFieldNode node, final Class<T> validatorClass) {
151
152 final Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class<?>[] { validatorClass },
153 new ValidatorWithErrorsInvocationHandler(node));
154
155 return validatorClass.cast(proxy);
156 }
157
158 public static void validateExplosively(final Object object, final Class<?>... validationClasses)
159 throws XmlFieldXPathException {
160
161 validateExplosively(getXmlFieldNode(object), validationClasses);
162 }
163
164 public static void validateExplosively(final XmlFieldNode node, final Class<?>... validationClasses)
165 throws XmlFieldXPathException {
166
167 validate(EXPLOSIVE_CALLBACK, node, validationClasses);
168 }
169
170 private static void assertXPath(final NamespaceMap namespaces, final XmlFieldSelector xpath,
171 final HandleXPathCallback handleXPathCallback, final String methodName, final String message,
172 final String refValueParam, final boolean isXPathRefValue, final String xpathExpression,
173 final XmlFieldNode node) throws XmlFieldXPathException {
174
175 final String result = xpath.selectXPathToString(namespaces, xpathExpression, node);
176
177 if (result == null && refValueParam == null) {
178 return;
179 }
180
181 final String refValue;
182
183 if (isXPathRefValue) {
184
185 refValue = xpath.selectXPathToString(namespaces, refValueParam, node);
186
187 } else {
188
189 refValue = refValueParam;
190 }
191
192 if (result == null || refValue == null || !refValue.equals(result)) {
193
194 final String error = isBlank(message) ? "" : xpath.selectXPathToString(namespaces, message, node);
195
196 String m = "Error in the following assertion: " + methodName + "/" + error + ": XPath=" + xpathExpression
197 + ", expected: ";
198
199 if (isXPathRefValue) {
200
201 m += "XPath=" + refValueParam + ": ";
202 }
203
204 m += refValue + ", but was: " + result;
205
206 handleXPathCallback.handleXPathEquals(m);
207 }
208 }
209
210 private static ClassLoader getClassLoader() {
211
212 return XPathValidation.class.getClassLoader();
213 }
214
215 private static XmlFieldSelector getSelector() {
216 return XmlFieldSelectorFactory.newInstance().newSelector();
217 }
218
219 private static void handleXPathEquals(final HandleXPathCallback handleXPathCallback, final AccessibleObject object,
220 final String name, final Object objectValue, final XmlFieldNode node) throws XmlFieldXPathException {
221
222 final XPathEquals xpathEquals = object.getAnnotation(XPathEquals.class);
223
224 if (xpathEquals == null) {
225 return;
226 }
227
228 final int[] intValues = xpathEquals.intValue();
229
230 final boolean[] booleanValues = xpathEquals.booleanValue();
231
232 final String[] namespaces = xpathEquals.namespaces();
233
234 final String[] stringValues = xpathEquals.stringValue();
235
236 final String[] xpathRefValues = xpathEquals.xpathRefValue();
237
238 final String selector = xpathEquals.selector();
239
240 final String message = xpathEquals.message();
241
242 final String xpathExpression = xpathEquals.xpath();
243
244 final String declValue;
245
246 final boolean isXPathRefValue;
247
248 if (objectValue != null) {
249
250 declValue = objectValue.toString();
251
252 isXPathRefValue = false;
253
254 } else if (xpathRefValues != null && xpathRefValues.length == 1) {
255
256 declValue = xpathRefValues[0];
257
258 isXPathRefValue = true;
259
260 } else if (intValues != null && intValues.length == 1) {
261
262 declValue = Integer.toString(intValues[0]);
263
264 isXPathRefValue = false;
265
266 } else if (booleanValues != null && booleanValues.length == 1) {
267
268 declValue = Boolean.toString(booleanValues[0]);
269
270 isXPathRefValue = false;
271
272 } else if (stringValues != null && stringValues.length == 1) {
273
274 declValue = stringValues[0];
275
276 isXPathRefValue = false;
277
278 } else {
279
280 declValue = null;
281
282 isXPathRefValue = false;
283 }
284
285 final XmlFieldSelector xpathSelector = getSelector();
286
287 final NamespaceMap namespaceMap = new NamespaceMap(namespaces);
288
289 if (isBlank(selector)) {
290
291 assertXPath(namespaceMap, xpathSelector, handleXPathCallback, name, message, declValue, isXPathRefValue,
292 xpathExpression, node);
293
294 } else {
295
296 final XmlFieldNodeList nodeList = xpathSelector.selectXPathToNodeList(namespaceMap, selector, node);
297
298 final int count = nodeList.getLength();
299
300 for (int i = 0; i < count; ++i) {
301
302 final XmlFieldNode n = nodeList.item(i);
303
304 assertXPath(namespaceMap, xpathSelector, handleXPathCallback, name, message, declValue,
305 isXPathRefValue, xpathExpression, n);
306 }
307 }
308 }
309
310 private static void validate(final HandleXPathCallback handleXPathCallback, final XmlFieldNode node,
311 final Class<?>[] validationClasses) throws XmlFieldXPathException {
312
313 for (final Class<?> validationClass : validationClasses) {
314
315 for (final Method method : validationClass.getMethods()) {
316
317 handleXPathEquals(handleXPathCallback, method, method.getName(), null, node);
318 }
319
320 for (final Field field : validationClass.getFields()) {
321
322 Object objectValue;
323
324 try {
325
326 objectValue = field.get(null);
327
328 } catch (final IllegalAccessException e) {
329
330 objectValue = null;
331 }
332
333 handleXPathEquals(handleXPathCallback, field, field.getName(), objectValue, node);
334 }
335 }
336 }
337 }