This project has retired. For details please refer to its
Attic page.
InMemoryQueryProcessor xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.apache.chemistry.opencmis.inmemory.query;
24
25 import java.math.BigDecimal;
26 import java.math.BigInteger;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.GregorianCalendar;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.regex.Pattern;
34
35 import org.antlr.runtime.tree.Tree;
36 import org.apache.chemistry.opencmis.commons.data.ObjectData;
37 import org.apache.chemistry.opencmis.commons.data.ObjectList;
38 import org.apache.chemistry.opencmis.commons.data.PropertyData;
39 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
40 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
41 import org.apache.chemistry.opencmis.commons.enums.Cardinality;
42 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
43 import org.apache.chemistry.opencmis.commons.enums.PropertyType;
44 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
45 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Content;
46 import org.apache.chemistry.opencmis.inmemory.storedobj.api.DocumentVersion;
47 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Filing;
48 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Folder;
49 import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
50 import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
51 import org.apache.chemistry.opencmis.inmemory.storedobj.api.VersionedDocument;
52 import org.apache.chemistry.opencmis.inmemory.storedobj.impl.ContentStreamDataImpl;
53 import org.apache.chemistry.opencmis.inmemory.storedobj.impl.ObjectStoreImpl;
54 import org.apache.chemistry.opencmis.inmemory.types.PropertyCreationHelper;
55 import org.apache.chemistry.opencmis.inmemory.types.PropertyUtil;
56 import org.apache.chemistry.opencmis.server.support.TypeManager;
57 import org.apache.chemistry.opencmis.server.support.query.AbstractPredicateWalker;
58 import org.apache.chemistry.opencmis.server.support.query.CmisQueryWalker;
59 import org.apache.chemistry.opencmis.server.support.query.CmisSelector;
60 import org.apache.chemistry.opencmis.server.support.query.ColumnReference;
61 import org.apache.chemistry.opencmis.server.support.query.QueryObject;
62 import org.apache.chemistry.opencmis.server.support.query.QueryObject.SortSpec;
63 import org.apache.chemistry.opencmis.server.support.query.QueryUtil;
64 import org.apache.chemistry.opencmis.server.support.query.StringUtil;
65 import org.apache.commons.logging.Log;
66 import org.apache.commons.logging.LogFactory;
67
68
69
70
71
72
73
74
75 public class InMemoryQueryProcessor {
76
77 private static final Log LOG = LogFactory.getLog(InMemoryQueryProcessor.class);
78
79 private List<StoredObject> matches = new ArrayList<StoredObject>();
80 private QueryObject queryObj;
81 private Tree whereTree;
82 private ObjectStoreImpl objStore;
83
84 public InMemoryQueryProcessor(ObjectStoreImpl objStore) {
85 this.objStore = objStore;
86 }
87
88
89
90
91 public ObjectList query(TypeManager tm, ObjectStore objectStore, String user, String repositoryId,
92 String statement, Boolean searchAllVersions, Boolean includeAllowableActions,
93 IncludeRelationships includeRelationships, String renditionFilter, BigInteger maxItems, BigInteger skipCount) {
94
95 queryObj = new QueryObject(tm);
96 processQueryAndCatchExc(statement);
97
98
99 for (String objectId : ((ObjectStoreImpl) objectStore).getIds()) {
100 StoredObject so = objectStore.getObjectById(objectId);
101 match(so, user, searchAllVersions == null ? true : searchAllVersions.booleanValue());
102 }
103
104 ObjectList objList = buildResultList(tm, user, includeAllowableActions, includeRelationships, renditionFilter,
105 maxItems, skipCount);
106 LOG.debug("Query result, number of matching objects: " + objList.getNumItems());
107 return objList;
108 }
109
110 public void processQueryAndCatchExc(String statement) {
111 QueryUtil queryUtil = new QueryUtil();
112 CmisQueryWalker walker = queryUtil.traverseStatementAndCatchExc(statement, queryObj, null);
113 whereTree = walker.getWherePredicateTree();
114 }
115
116 public ObjectList buildResultList(TypeManager tm, String user, Boolean includeAllowableActions,
117 IncludeRelationships includeRelationships, String renditionFilter, BigInteger maxItems, BigInteger skipCount) {
118
119 sortMatches();
120
121 ObjectListImpl res = new ObjectListImpl();
122 res.setNumItems(BigInteger.valueOf(matches.size()));
123 int start = 0;
124 if (skipCount != null) {
125 start = (int) skipCount.longValue();
126 }
127 if (start < 0) {
128 start = 0;
129 }
130 if (start > matches.size()) {
131 start = matches.size();
132 }
133 int stop = 0;
134 if (maxItems != null) {
135 stop = start + (int) maxItems.longValue();
136 }
137 if (stop <= 0 || stop > matches.size()) {
138 stop = matches.size();
139 }
140 res.setHasMoreItems(stop < matches.size());
141 if (start > 0 || stop > 0) {
142 matches = matches.subList(start, stop);
143 }
144 List<ObjectData> objDataList = new ArrayList<ObjectData>();
145 Map<String, String> props = queryObj.getRequestedPropertiesByAlias();
146 Map<String, String> funcs = queryObj.getRequestedFuncsByAlias();
147 for (StoredObject so : matches) {
148 TypeDefinition td = tm.getTypeById(so.getTypeId()).getTypeDefinition();
149 ObjectData od = PropertyCreationHelper.getObjectDataQueryResult(td, so, user, props, funcs,
150 includeAllowableActions, includeRelationships, renditionFilter);
151
152 objDataList.add(od);
153 }
154 res.setObjects(objDataList);
155 return res;
156 }
157
158 private boolean typeMatches(TypeDefinition td, StoredObject so) {
159 String typeId = so.getTypeId();
160 while (typeId != null) {
161 if (typeId.equals(td.getId())) {
162 return true;
163 }
164
165 TypeDefinition parentTD = queryObj.getParentType(typeId);
166 typeId = parentTD == null ? null : parentTD.getId();
167 }
168 return false;
169 }
170
171 private void sortMatches() {
172 final List<SortSpec> orderBy = queryObj.getOrderBys();
173 if (orderBy.size() > 1) {
174 LOG.warn("ORDER BY has more than one sort criterium, all but the first are ignored.");
175 }
176 class ResultComparator implements Comparator<StoredObject> {
177
178 @SuppressWarnings("unchecked")
179 public int compare(StoredObject so1, StoredObject so2) {
180 SortSpec s = orderBy.get(0);
181 CmisSelector sel = s.getSelector();
182 int result;
183
184 if (sel instanceof ColumnReference) {
185 String propId = ((ColumnReference) sel).getPropertyId();
186 PropertyDefinition<?> pd = ((ColumnReference) sel).getPropertyDefinition();
187
188 Object propVal1 = PropertyUtil.getProperty(so1, propId, pd);
189 Object propVal2 = PropertyUtil.getProperty(so2, propId, pd);
190
191 if (propVal1 == null && propVal2 == null) {
192 result = 0;
193 } else if (propVal1 == null) {
194 result = -1;
195 } else if (propVal2 == null) {
196 result = 1;
197 } else {
198 result = ((Comparable<Object>) propVal1).compareTo(propVal2);
199 }
200 } else {
201
202
203 result = 0;
204 }
205 if (!s.isAscending()) {
206 result = -result;
207 }
208 return result;
209 }
210 }
211
212 if (orderBy.size() > 0) {
213 Collections.sort(matches, new ResultComparator());
214 }
215
216 }
217
218
219
220
221
222
223
224
225
226 private void match(StoredObject so, String user, boolean searchAllVersions) {
227
228
229 String queryName = queryObj.getTypes().values().iterator().next();
230
231
232
233
234
235
236
237 TypeDefinition td = queryObj.getTypeDefinitionFromQueryName(queryName);
238 boolean skip = so instanceof VersionedDocument;
239
240
241
242 boolean typeMatches = typeMatches(td, so);
243 if (!searchAllVersions && so instanceof DocumentVersion
244 && ((DocumentVersion) so).getParentDocument().getLatestVersion(false) != so) {
245 skip = true;
246 }
247
248 if (typeMatches && !skip) {
249 evalWhereTree(whereTree, user, so);
250 }
251 }
252
253 private void evalWhereTree(Tree node, String user, StoredObject so) {
254 boolean match = true;
255 if (null != node) {
256 match = evalWhereNode(so, user, node);
257 }
258 if (match && objStore.hasReadAccess(user, so))
259 {
260 matches.add(so);
261 }
262 }
263
264
265
266
267
268
269
270
271
272
273 boolean evalWhereNode(StoredObject so, String user, Tree node) {
274 return new InMemoryWhereClauseWalker(so, user).walkPredicate(node);
275 }
276
277 public class InMemoryWhereClauseWalker extends AbstractPredicateWalker {
278
279 protected final StoredObject so;
280 protected final String user;
281
282 public InMemoryWhereClauseWalker(StoredObject so, String user) {
283 this.so = so;
284 this.user = user;
285 }
286
287 @Override
288 public Boolean walkNot(Tree opNode, Tree node) {
289 boolean matches = walkPredicate(node);
290 return !matches;
291 }
292
293 @Override
294 public Boolean walkAnd(Tree opNode, Tree leftNode, Tree rightNode) {
295 boolean matches1 = walkPredicate(leftNode);
296 boolean matches2 = walkPredicate(rightNode);
297 return matches1 && matches2;
298 }
299
300 @Override
301 public Boolean walkOr(Tree opNode, Tree leftNode, Tree rightNode) {
302 boolean matches1 = walkPredicate(leftNode);
303 boolean matches2 = walkPredicate(rightNode);
304 return matches1 || matches2;
305 }
306
307 @Override
308 public Boolean walkEquals(Tree opNode, Tree leftNode, Tree rightNode) {
309 Integer cmp = compareTo(leftNode, rightNode);
310 return cmp == null ? false : cmp == 0;
311 }
312
313 @Override
314 public Boolean walkNotEquals(Tree opNode, Tree leftNode, Tree rightNode) {
315 Integer cmp = compareTo(leftNode, rightNode);
316 return cmp == null ? false : cmp != 0;
317 }
318
319 @Override
320 public Boolean walkGreaterThan(Tree opNode, Tree leftNode, Tree rightNode) {
321 Integer cmp = compareTo(leftNode, rightNode);
322 return cmp == null ? false : cmp > 0;
323 }
324
325 @Override
326 public Boolean walkGreaterOrEquals(Tree opNode, Tree leftNode, Tree rightNode) {
327 Integer cmp = compareTo(leftNode, rightNode);
328 return cmp == null ? false : cmp >= 0;
329 }
330
331 @Override
332 public Boolean walkLessThan(Tree opNode, Tree leftNode, Tree rightNode) {
333 Integer cmp = compareTo(leftNode, rightNode);
334 return cmp == null ? false : cmp < 0;
335 }
336
337 @Override
338 public Boolean walkLessOrEquals(Tree opNode, Tree leftNode, Tree rightNode) {
339 Integer cmp = compareTo(leftNode, rightNode);
340 return cmp == null ? false : cmp <= 0;
341 }
342
343 @Override
344 public Boolean walkIn(Tree opNode, Tree colNode, Tree listNode) {
345 ColumnReference colRef = getColumnReference(colNode);
346 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
347 List<Object> literals = onLiteralList(listNode);
348 Object prop = PropertyUtil.getProperty(so, colRef.getPropertyId(), pd);
349
350 if (pd.getCardinality() != Cardinality.SINGLE) {
351 throw new IllegalStateException("Operator IN only is allowed on single-value properties ");
352 } else if (prop == null) {
353 return false;
354 } else {
355 return literals.contains(prop);
356 }
357 }
358
359 @Override
360 public Boolean walkNotIn(Tree opNode, Tree colNode, Tree listNode) {
361
362
363
364 ColumnReference colRef = getColumnReference(colNode);
365 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
366 Object prop = PropertyUtil.getProperty(so, colRef.getPropertyId(), pd);
367 List<Object> literals = onLiteralList(listNode);
368 if (pd.getCardinality() != Cardinality.SINGLE) {
369 throw new IllegalStateException("Operator IN only is allowed on single-value properties ");
370 } else if (prop == null) {
371 return false;
372 } else {
373 return !literals.contains(prop);
374 }
375 }
376
377 @Override
378 public Boolean walkInAny(Tree opNode, Tree colNode, Tree listNode) {
379 ColumnReference colRef = getColumnReference(colNode);
380 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
381 PropertyData<?> lVal = so.getProperties().get(colRef.getPropertyId());
382 List<Object> literals = onLiteralList(listNode);
383 if (pd.getCardinality() != Cardinality.MULTI) {
384 throw new IllegalStateException("Operator ANY...IN only is allowed on multi-value properties ");
385 } else if (lVal == null) {
386 return false;
387 } else {
388 List<?> props = lVal.getValues();
389 for (Object prop : props) {
390 LOG.debug("comparing with: " + prop);
391 if (literals.contains(prop)) {
392 return true;
393 }
394 }
395 return false;
396 }
397 }
398
399 @Override
400 public Boolean walkNotInAny(Tree opNode, Tree colNode, Tree listNode) {
401
402
403
404 ColumnReference colRef = getColumnReference(colNode);
405 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
406 PropertyData<?> lVal = so.getProperties().get(colRef.getPropertyId());
407 List<Object> literals = onLiteralList(listNode);
408 if (pd.getCardinality() != Cardinality.MULTI) {
409 throw new IllegalStateException("Operator ANY...IN only is allowed on multi-value properties ");
410 } else if (lVal == null) {
411 return false;
412 } else {
413 List<?> props = lVal.getValues();
414 for (Object prop : props) {
415 LOG.debug("comparing with: " + prop);
416 if (literals.contains(prop)) {
417 return false;
418 }
419 }
420 return true;
421 }
422 }
423
424 @Override
425 public Boolean walkEqAny(Tree opNode, Tree literalNode, Tree colNode) {
426 ColumnReference colRef = getColumnReference(colNode);
427 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
428 PropertyData<?> lVal = so.getProperties().get(colRef.getPropertyId());
429 Object literal = walkExpr(literalNode);
430 if (pd.getCardinality() != Cardinality.MULTI) {
431 throw new IllegalStateException("Operator = ANY only is allowed on multi-value properties ");
432 } else if (lVal == null) {
433 return false;
434 } else {
435 List<?> props = lVal.getValues();
436 return props.contains(literal);
437 }
438 }
439
440 @Override
441 public Boolean walkIsNull(Tree opNode, Tree colNode) {
442 ColumnReference colRef = getColumnReference(colNode);
443 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
444 Object propVal = PropertyUtil.getProperty(so, colRef.getPropertyId(), pd);
445 return propVal == null;
446 }
447
448 @Override
449 public Boolean walkIsNotNull(Tree opNode, Tree colNode) {
450 ColumnReference colRef = getColumnReference(colNode);
451 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
452 Object propVal = PropertyUtil.getProperty(so, colRef.getPropertyId(), pd);
453 return propVal != null;
454 }
455
456 @Override
457 public Boolean walkLike(Tree opNode, Tree colNode, Tree stringNode) {
458 Object rVal = walkExpr(stringNode);
459 if (!(rVal instanceof String)) {
460 throw new IllegalStateException("LIKE operator requires String literal on right hand side.");
461 }
462
463 ColumnReference colRef = getColumnReference(colNode);
464 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
465 PropertyType propType = pd.getPropertyType();
466 if (propType != PropertyType.STRING && propType != PropertyType.HTML && propType != PropertyType.ID
467 && propType != PropertyType.URI) {
468 throw new IllegalStateException("Property type " + propType.value() + " is not allowed FOR LIKE");
469 }
470 if (pd.getCardinality() != Cardinality.SINGLE) {
471 throw new IllegalStateException("LIKE is not allowed for multi-value properties ");
472 }
473
474 String propVal = (String) PropertyUtil.getProperty(so, colRef.getPropertyId(), pd);
475
476 String pattern = translatePattern((String) rVal);
477
478
479 Pattern p = Pattern.compile(pattern);
480 return p.matcher(propVal).matches();
481 }
482
483 @Override
484 public Boolean walkNotLike(Tree opNode, Tree colNode, Tree stringNode) {
485 return !walkLike(opNode, colNode, stringNode);
486 }
487
488 @Override
489 public Boolean walkInFolder(Tree opNode, Tree qualNode, Tree paramNode) {
490 if (null != qualNode) {
491 getTableReference(qualNode);
492
493
494 }
495 Object lit = walkExpr(paramNode);
496 if (!(lit instanceof String)) {
497 throw new IllegalStateException("Folder id in IN_FOLDER must be of type String");
498 }
499 String folderId = (String) lit;
500
501
502 if (so instanceof Filing) {
503 return hasParent((Filing) so, folderId, user);
504 } else {
505 return false;
506 }
507 }
508
509 @Override
510 public Boolean walkInTree(Tree opNode, Tree qualNode, Tree paramNode) {
511 if (null != qualNode) {
512 getTableReference(qualNode);
513
514
515 }
516 Object lit = walkExpr(paramNode);
517 if (!(lit instanceof String)) {
518 throw new IllegalStateException("Folder id in IN_FOLDER must be of type String");
519 }
520 String folderId = (String) lit;
521
522
523 if (so instanceof Filing) {
524 return hasAncestor((Filing) so, folderId, user);
525 } else {
526 return false;
527 }
528 }
529
530 protected Integer compareTo(Tree leftChild, Tree rightChild) {
531 Object rVal = walkExpr(rightChild);
532
533
534
535 ColumnReference colRef = getColumnReference(leftChild);
536 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
537 Object val = PropertyUtil.getProperty(so, colRef.getPropertyId(), pd);
538 if (val==null) {
539 return null;
540 } else if (val instanceof List<?>) {
541 throw new IllegalStateException("You can't query operators <, <=, ==, !=, >=, > on multi-value properties ");
542 } else {
543 return InMemoryQueryProcessor.this.compareTo(pd, val, rVal);
544 }
545 }
546
547 @SuppressWarnings("unchecked")
548 public List<Object> onLiteralList(Tree node) {
549 return (List<Object>) walkExpr(node);
550 }
551
552 @Override
553 protected Boolean walkTextAnd(Tree node) {
554 List<Tree> terms = getChildrenAsList(node);
555 for (Tree term: terms) {
556 Boolean foundOnce = walkSearchExpr(term);
557 if (foundOnce== null || !foundOnce)
558 return false;
559 }
560 return true;
561 }
562
563 @Override
564 protected Boolean walkTextOr(Tree node) {
565 List<Tree> terms = getChildrenAsList(node);
566 for (Tree term: terms) {
567 Boolean foundOnce = walkSearchExpr(term);
568 if (foundOnce!= null && foundOnce)
569 return true;
570 }
571 return false;
572 }
573
574 @Override
575 protected Boolean walkTextMinus(Tree node) {
576 return !findText(node.getChild(0).getText());
577 }
578
579 @Override
580 protected Boolean walkTextWord(Tree node) {
581 return findText(node.getText());
582 }
583
584 @Override
585 protected Boolean walkTextPhrase(Tree node) {
586 String phrase = node.getText();
587 return findText(phrase.substring(1, phrase.length()-1));
588 }
589
590 private List<Tree> getChildrenAsList(Tree node) {
591 List<Tree> res = new ArrayList<Tree>(node.getChildCount());
592 for (int i=0; i<node.getChildCount(); i++) {
593 Tree childNnode = node.getChild(i);
594 res.add(childNnode);
595 }
596 return res;
597 }
598
599 private boolean findText(String nodeText) {
600 Content cont;
601 String pattern = StringUtil.unescape(nodeText, null);
602 if (so instanceof Content && (cont=(Content)so).hasContent()) {
603 ContentStreamDataImpl cdi = (ContentStreamDataImpl) cont.getContent(0, -1);
604 byte[] ba = cdi.getBytes();
605 String text = new String(ba);
606 int match = text.indexOf(pattern);
607 return match >= 0;
608 }
609 return false;
610 }
611
612 }
613
614 private static boolean hasParent(Filing objInFolder, String folderId, String user) {
615 List<Folder> parents = objInFolder.getParents(user);
616
617 for (Folder folder : parents) {
618 if (folderId.equals(folder.getId())) {
619 return true;
620 }
621 }
622 return false;
623 }
624
625 private boolean hasAncestor(Filing objInFolder, String folderId, String user) {
626 List<Folder> parents = objInFolder.getParents(user);
627
628 for (Folder folder : parents) {
629 if (folderId.equals(folder.getId())) {
630 return true;
631 }
632 }
633 for (Folder folder : parents) {
634 if (hasAncestor(folder, folderId, user)) {
635 return true;
636 }
637 }
638 return false;
639 }
640
641 protected int compareTo(PropertyDefinition<?> td, Object lValue, Object rVal) {
642 switch (td.getPropertyType()) {
643 case BOOLEAN:
644 if (rVal instanceof Boolean) {
645 return ((Boolean) lValue).compareTo((Boolean) rVal);
646 } else {
647 throwIncompatibleTypesException(lValue, rVal);
648 }
649 break;
650 case INTEGER: {
651 Long lLongValue = ((BigInteger) lValue).longValue();
652 if (rVal instanceof Long) {
653 return (lLongValue).compareTo((Long) rVal);
654 } else if (rVal instanceof Double) {
655 return Double.valueOf(((Integer) lValue).doubleValue()).compareTo((Double) rVal);
656 } else {
657 throwIncompatibleTypesException(lValue, rVal);
658 }
659 break;
660 }
661 case DATETIME:
662 if (rVal instanceof GregorianCalendar) {
663
664
665
666
667 return ((GregorianCalendar) lValue).compareTo((GregorianCalendar) rVal);
668 } else {
669 throwIncompatibleTypesException(lValue, rVal);
670 }
671 break;
672 case DECIMAL: {
673 Double lDoubleValue = ((BigDecimal) lValue).doubleValue();
674 if (rVal instanceof Double) {
675 return lDoubleValue.compareTo((Double) rVal);
676 } else if (rVal instanceof Long) {
677 return Double.valueOf(((Integer) lValue).doubleValue()).compareTo(((Long)rVal).doubleValue());
678 } else {
679 throwIncompatibleTypesException(lValue, rVal);
680 }
681 break;
682 }
683 case HTML:
684 case STRING:
685 case URI:
686 case ID:
687 if (rVal instanceof String) {
688 LOG.debug("compare strings: " + lValue + " with " + rVal);
689 return ((String) lValue).compareTo((String) rVal);
690 } else {
691 throwIncompatibleTypesException(lValue, rVal);
692 }
693 break;
694 }
695 return 0;
696 }
697
698 private ColumnReference getColumnReference(Tree columnNode) {
699 CmisSelector sel = queryObj.getColumnReference(columnNode.getTokenStartIndex());
700 if (null == sel) {
701 throw new IllegalStateException("Unknown property query name " + columnNode.getChild(0));
702 } else if (sel instanceof ColumnReference) {
703 return (ColumnReference) sel;
704 } else {
705 throw new IllegalStateException("Unexpected numerical value function in where clause");
706 }
707 }
708
709 private String getTableReference(Tree tableNode) {
710 String typeQueryName = queryObj.getTypeQueryName(tableNode.getText());
711 if (null == typeQueryName) {
712 throw new IllegalStateException("Inavlid type in IN_FOLDER() or IN_TREE(), must be in FROM list: "
713 + tableNode.getText());
714 }
715 return typeQueryName;
716 }
717
718 private Object xgetPropertyValue(Tree columnNode, StoredObject so) {
719 ColumnReference colRef = getColumnReference(columnNode);
720 PropertyDefinition<?> pd = colRef.getPropertyDefinition();
721 return PropertyUtil.getProperty(so, colRef.getPropertyId(), pd);
722 }
723
724
725 public static String translatePattern(String wildcardString) {
726 int index = 0;
727 int start = 0;
728 StringBuffer res = new StringBuffer();
729
730 while (index >= 0) {
731 index = wildcardString.indexOf('%', start);
732 if (index < 0) {
733 res.append(wildcardString.substring(start));
734 } else if (index == 0 || index > 0 && wildcardString.charAt(index - 1) != '\\') {
735 res.append(wildcardString.substring(start, index));
736 res.append(".*");
737 } else {
738 res.append(wildcardString.substring(start, index + 1));
739 }
740 start = index + 1;
741 }
742 wildcardString = res.toString();
743
744 index = 0;
745 start = 0;
746 res = new StringBuffer();
747
748 while (index >= 0) {
749 index = wildcardString.indexOf('_', start);
750 if (index < 0) {
751 res.append(wildcardString.substring(start));
752 } else if (index == 0 || index > 0 && wildcardString.charAt(index - 1) != '\\') {
753 res.append(wildcardString.substring(start, index));
754 res.append(".");
755 } else {
756 res.append(wildcardString.substring(start, index + 1));
757 }
758 start = index + 1;
759 }
760 return res.toString();
761 }
762
763 private static void throwIncompatibleTypesException(Object o1, Object o2) {
764 throw new IllegalArgumentException("Incompatible Types to compare: " + o1 + " and " + o2);
765 }
766
767 }