View Javadoc

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 }