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.decorator;
23
24 import org.apache.commons.beanutils.MethodUtils;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.nuiton.decorator.JXPathDecorator.Context;
28 import org.nuiton.decorator.JXPathDecorator.JXPathComparator;
29
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.Comparator;
33 import java.util.Date;
34 import java.util.List;
35 import java.util.StringTokenizer;
36 import java.util.regex.Matcher;
37 import java.util.regex.Pattern;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class DecoratorUtil {
58
59
60 private static final Log log = LogFactory.getLog(DecoratorUtil.class);
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public static <O> PropertyDecorator<O> newPropertyDecorator(
81 Class<O> type,
82 String property)
83 throws IllegalArgumentException, NullPointerException {
84 return new PropertyDecorator<O>(type, property);
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public static <O> JXPathDecorator<O> newJXPathDecorator(
105 Class<O> type,
106 String expression)
107 throws IllegalArgumentException, NullPointerException {
108
109 Context<O> context = createJXPathContext(expression);
110 return new JXPathDecorator<O>(type, expression, context);
111 }
112
113 public static <O> MultiJXPathDecorator<O> newMultiJXPathDecorator(
114 Class<O> type,
115 String expression,
116 String separator)
117 throws IllegalArgumentException, NullPointerException {
118
119 MultiJXPathDecorator<O> decorator = newMultiJXPathDecorator(
120 type,
121 expression,
122 separator,
123 separator);
124 return decorator;
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 public static <O> MultiJXPathDecorator<O> newMultiJXPathDecorator(
147 Class<O> type,
148 String expression,
149 String separator,
150 String separatorReplacement)
151 throws IllegalArgumentException, NullPointerException {
152
153 Context<O>[] contexts = createMultiJXPathContext(
154 expression,
155 separator,
156 separatorReplacement);
157
158 return new MultiJXPathDecorator<O>(
159 type,
160 expression,
161 separator,
162 separatorReplacement,
163 contexts);
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 public static <O> MultiJXPathDecorator<O> newMultiJXPathDecoratorKeepingOrder(
186 Class<O> type,
187 String expression,
188 String separator,
189 String separatorReplacement)
190 throws IllegalArgumentException, NullPointerException {
191
192 Context<O>[] contexts = createMultiJXPathContextKeepingOrder(
193 expression,
194 separator,
195 separatorReplacement);
196
197 return new MultiJXPathDecorator<O>(
198 type,
199 expression,
200 separator,
201 separatorReplacement,
202 contexts);
203 }
204
205 private static final Object[] EMPTY_CLASS_ARRAY = new Object[0];
206
207
208
209
210
211
212
213
214
215
216
217 public static <O> MultiJXPathDecorator<O> cloneDecorator(JXPathDecorator<O> decorator) {
218 if (decorator == null) {
219 throw new NullPointerException(
220 "can not have a null decorator as parameter");
221 }
222 String separator;
223 String separatorReplacement;
224
225 if (decorator instanceof Cloneable) {
226 Cloneable cloneable = (Cloneable) decorator;
227
228 try {
229 Object clone = MethodUtils.invokeExactMethod(cloneable,
230 "clone",
231 EMPTY_CLASS_ARRAY);
232 return (MultiJXPathDecorator<O>) clone;
233 } catch (Exception e) {
234 throw new IllegalStateException("Could not clone decorator " + decorator, e);
235 }
236
237 }
238 if (decorator instanceof MultiJXPathDecorator<?>) {
239
240 separator = ((MultiJXPathDecorator<?>) decorator).getSeparator();
241 separatorReplacement = ((MultiJXPathDecorator<?>) decorator).getSeparatorReplacement();
242
243 } else {
244
245 separator = "??" + new Date().getTime();
246 separatorReplacement = " - ";
247 }
248
249 return newMultiJXPathDecorator(decorator.getType(),
250 decorator.getInitialExpression(),
251 separator,
252 separatorReplacement);
253
254 }
255
256
257
258
259
260
261
262
263
264
265
266 public static <O> void sort(JXPathDecorator<O> decorator,
267 List<O> datas,
268 int pos) {
269 sort(decorator, datas, pos, false);
270 }
271
272
273
274
275
276
277
278
279
280
281
282
283
284 public static <O> void sort(JXPathDecorator<O> decorator,
285 List<O> datas,
286 int pos,
287 boolean reverse) {
288 Comparator<O> c = null;
289 boolean cachedComparator = false;
290 try {
291 c = decorator.getComparator(pos);
292 cachedComparator = c instanceof JXPathComparator<?>;
293
294 if (cachedComparator) {
295 ((JXPathComparator<O>) c).init(decorator, datas);
296 }
297 Collections.sort(datas, c);
298 if (reverse) {
299
300
301 Collections.reverse(datas);
302 }
303 } finally {
304 if (cachedComparator) {
305 ((JXPathComparator<?>) c).clear();
306 }
307 }
308 }
309
310 public static <O> Context<O> createJXPathContext(String expression) {
311 List<String> lTokens = new ArrayList<String>();
312 StringBuilder buffer = new StringBuilder();
313 int size = expression.length();
314 int end = -1;
315 int start;
316 while ((start = expression.indexOf("${", end + 1)) > -1) {
317 if (start > end + 1) {
318
319
320 buffer.append(expression.substring(end + 1, start));
321 }
322
323
324 end = expression.indexOf("}", start + 1);
325 if (end == -1) {
326 throw new IllegalArgumentException(
327 "could not find the rigth brace starting at car " +
328 start + " : " + expression.substring(start + 2));
329 }
330 String jxpath = expression.substring(start + 2, end);
331
332
333 if (jxpath.contains("${")) {
334 throw new IllegalArgumentException(
335 "could not find a ${ inside a jxpath expression at " +
336 "car " + (start + 2) + " : " + jxpath);
337 }
338
339
340 lTokens.add(jxpath);
341
342
343 buffer.append('%').append(lTokens.size());
344 }
345 if (size > end + 1) {
346
347
348 buffer.append(expression.substring(end + 1));
349 }
350 String[] tokens = lTokens.toArray(new String[lTokens.size()]);
351 return new Context<O>(buffer.toString(), tokens);
352 }
353
354 public static <O> Context<O>[] createMultiJXPathContext(
355 String expression,
356 String separator,
357 String separatorReplacement) {
358 int sep = expression.indexOf(separator);
359 if (sep == -1) {
360 Context<O>[] result = newInstance(1);
361 result[0] = createJXPathContext(expression);
362 return result;
363 }
364
365 List<String> tokens = new ArrayList<String>();
366 StringTokenizer stk = new StringTokenizer(expression, separator);
367 while (stk.hasMoreTokens()) {
368 tokens.add(stk.nextToken());
369 }
370
371 int nbTokens = tokens.size();
372 Context<O>[] contexts = newInstance(nbTokens);
373 if (log.isDebugEnabled()) {
374 log.debug("Will prepare " + nbTokens + " contexts from [" + expression + "]");
375 }
376 for (int i = 0; i < nbTokens; i++) {
377 StringBuilder buffer = new StringBuilder(expression.length());
378 for (int j = 0; j < nbTokens; j++) {
379 int index = (i + j) % nbTokens;
380 String str = tokens.get(index);
381
382
383 Pattern p = Pattern.compile("\\%(" + (index + 1) + ")\\$");
384 Matcher matcher = p.matcher(str);
385 String safeStr = matcher.replaceAll("\\%" + (j + 1) + "\\$");
386
387 if (log.isDebugEnabled()) {
388 log.debug("[" + (index + 1) + "-->" + (j + 1) + "] " + str +
389 " transformed to " + safeStr);
390 }
391 buffer.append(separatorReplacement).append(safeStr);
392 }
393 String expr = buffer.substring(separatorReplacement.length());
394 if (log.isDebugEnabled()) {
395 log.debug("context [" + i + "] : " + expr);
396 }
397 contexts[i] = createJXPathContext(
398 expr);
399 }
400 return contexts;
401 }
402
403 public static <O> Context<O>[] createMultiJXPathContextKeepingOrder(
404 String expression,
405 String separator,
406 String separatorReplacement) {
407 int sep = expression.indexOf(separator);
408 if (sep == -1) {
409 Context<O>[] result = newInstance(1);
410 result[0] = createJXPathContext(expression);
411 return result;
412 }
413
414 List<String> tokens = new ArrayList<String>();
415 StringTokenizer stk = new StringTokenizer(expression, separator);
416 while (stk.hasMoreTokens()) {
417 tokens.add(stk.nextToken());
418 }
419
420 int nbTokens = tokens.size();
421 Context<O>[] contexts = newInstance(nbTokens);
422 if (log.isDebugEnabled()) {
423 log.debug("Will prepare " + nbTokens + " contexts from [" + expression + "]");
424 }
425 for (int i = 0; i < nbTokens; i++) {
426 StringBuilder buffer = new StringBuilder(expression.length());
427
428 {
429
430 int index = i;
431 String str = tokens.get(index);
432
433
434 Pattern p = Pattern.compile("\\%(" + (index + 1) + ")\\$");
435 Matcher matcher = p.matcher(str);
436 String safeStr = matcher.replaceAll("\\%" + (1) + "\\$");
437
438 if (log.isDebugEnabled()) {
439 log.debug("[" + (index + 1) + "-->" + (1) + "] " + str +
440 " transformed to " + safeStr);
441 }
442 buffer.append(separatorReplacement).append(safeStr);
443 }
444 for (int j = 0; j < nbTokens; j++) {
445 if (j == i) {
446
447
448 continue;
449 }
450
451 int index = j;
452
453 String str = tokens.get(index);
454
455 int againstIndex = j < i ? j + 1 : j;
456
457
458 Pattern p = Pattern.compile("\\%(" + (index + 1) + ")\\$");
459 Matcher matcher = p.matcher(str);
460 String safeStr = matcher.replaceAll("\\%" + (againstIndex + 1) + "\\$");
461
462 if (log.isDebugEnabled()) {
463 log.debug("[" + (index + 1) + "-->" + (againstIndex + 1) + "] " + str +
464 " transformed to " + safeStr);
465 }
466 buffer.append(separatorReplacement).append(safeStr);
467 }
468 String expr = buffer.substring(separatorReplacement.length());
469 if (log.isDebugEnabled()) {
470 log.debug("context [" + i + "] : " + expr);
471 }
472 contexts[i] = createJXPathContext(
473 expr);
474 }
475 return contexts;
476 }
477
478 @SuppressWarnings("unchecked")
479 protected static <O> Context<O>[] newInstance(int size) {
480
481 return new Context[size];
482 }
483 }