1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.search.expression;
18
19 import java.io.Serializable;
20 import java.util.Comparator;
21 import java.util.Map;
22
23 import net.sf.ehcache.Element;
24 import net.sf.ehcache.search.SearchException;
25 import net.sf.ehcache.search.attribute.AttributeExtractor;
26 import net.sf.ehcache.search.attribute.AttributeType;
27
28 /***
29 * Abstract base class for criteria involving {@link java.lang.Comparable} values
30 *
31 * @author teck
32 */
33 public abstract class ComparableValue extends BaseCriteria {
34
35 private static final Comparator<String> LUCENE_STRING_COMPARATOR = new LuceneCaseAgnosticStringComparator();
36
37 private final String attributeName;
38 private final AttributeType type;
39
40 /***
41 * Constructor
42 *
43 * @param attributeName attribute name
44 * @param value comparable value (used to infer type)
45 */
46 public ComparableValue(String attributeName, Object value) {
47 this(attributeName, AttributeType.typeFor(attributeName, value));
48 }
49
50 /***
51 * Constructor
52 *
53 * @param attributeName attribute name
54 * @param type the expeceted type for values evaluated by this criteria
55 */
56 public ComparableValue(String attributeName, AttributeType type) {
57 this.attributeName = attributeName;
58 this.type = type;
59
60 if (!this.type.isComparable()) {
61 throw new SearchException("Illegal (non-comparable) type for comparsion (" + type + ")");
62 }
63 }
64
65 /***
66 * Attribute name.
67 *
68 * @return name
69 */
70 public String getAttributeName() {
71 return attributeName;
72 }
73
74 /***
75 * Attribute type.
76 *
77 * @return type
78 */
79 public AttributeType getType() {
80 return type;
81 }
82
83 /***
84 * {@inheritDoc}
85 */
86 public boolean execute(Element e, Map<String, AttributeExtractor> attributeExtractors) {
87 Object attrValue = attributeExtractors.get(getAttributeName()).attributeFor(e, getAttributeName());
88 if (attrValue == null) {
89 return false;
90 } else {
91 AttributeType attrType = AttributeType.typeFor(getAttributeName(), attrValue);
92 if (!getType().equals(attrType)) {
93 throw new SearchException("Expecting attribute of type " + getType().name() + " but was " + attrType.name());
94 }
95
96 if (getType().equals(AttributeType.STRING)) {
97 return executeComparableString((Comparable) attrValue);
98 } else {
99 return executeComparable((Comparable) attrValue);
100 }
101 }
102 }
103
104 /***
105 * Execute this criteria for the given {@link Comparable} attribute value
106 *
107 * @param attributeValue Comparable attribute value
108 * @return true if criteria is met
109 */
110 protected abstract boolean executeComparable(Comparable attributeValue);
111
112 /***
113 * Execute this criteria for the given {@link Comparable} strin type attribute value
114 *
115 * @param attributeValue Comparable attribute value
116 * @return true if criteria is met
117 */
118 protected abstract boolean executeComparableString(Comparable attributeValue);
119
120 /***
121 * Perform a Lucene compatible case insensitive string comparison.
122 *
123 * @param s1 first string
124 * @param s2 second string
125 * @return the comparison result
126 */
127 protected static int luceneStringCompare(String s1, String s2) {
128 return LUCENE_STRING_COMPARATOR.compare(s1, s2);
129 }
130
131 /***
132 * A Lucene compatible case insensitive string comparator.
133 */
134 private static class LuceneCaseAgnosticStringComparator implements Comparator<String>, Serializable {
135
136 public int compare(String s1, String s2) {
137 int n1 = s1.length();
138 int n2 = s2.length();
139 for (int i = 0; i < n1 && i < n2; i++) {
140 char c1 = s1.charAt(i);
141 char c2 = s2.charAt(i);
142
143 if (c1 != c2) {
144 c1 = Character.toLowerCase(c1);
145 c2 = Character.toLowerCase(c2);
146 if (c1 != c2) { return c1 - c2; }
147 }
148 }
149 return n1 - n2;
150 }
151 }
152 }