View Javadoc

1   /*
2    * Copyright 2010 Capgemini
3    * Licensed under the Apache License, Version 2.0 (the "License"); 
4    * you may not use this file except in compliance with the License. 
5    * You may obtain a copy of the License at 
6    * 
7    * http://www.apache.org/licenses/LICENSE-2.0 
8    * 
9    * Unless required by applicable law or agreed to in writing, software 
10   * distributed under the License is distributed on an "AS IS" BASIS, 
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
12   * See the License for the specific language governing permissions and 
13   * limitations under the License. 
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   * XPath Validation Utils tool.
41   * 
42   * @author David Andrianavalontsalama
43   * @author Guillaume Mary <guillaume.mary@capgemini.com>
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 }