View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.search.lucene.query;
25  
26  import java.io.IOException;
27  import org.apache.lucene.document.Document;
28  import org.apache.lucene.index.IndexReader;
29  import org.apache.lucene.search.Query;
30  import org.apache.lucene.search.Searcher;
31  import org.apache.lucene.search.Weight;
32  import org.modeshape.graph.property.Path;
33  import org.modeshape.graph.property.ValueComparators;
34  import org.modeshape.graph.property.ValueFactories;
35  import org.modeshape.graph.property.ValueFactory;
36  import org.modeshape.graph.query.model.Comparison;
37  
38  /**
39   * A Lucene {@link Query} implementation that is used to apply a {@link Comparison} constraint against the Path of nodes. This
40   * query implementation works by using the {@link Query#weight(Searcher) weight} and
41   * {@link Weight#scorer(IndexReader, boolean, boolean) scorer} of the wrapped query to score (and return) only those documents
42   * that correspond to nodes with Paths that satisfy the constraint.
43   */
44  public class ComparePathQuery extends CompareQuery<Path> {
45  
46      private static final long serialVersionUID = 1L;
47      protected static final Evaluator<Path> PATH_IS_LESS_THAN = new Evaluator<Path>() {
48          private static final long serialVersionUID = 1L;
49  
50          public boolean satisfiesConstraint( Path nodePath,
51                                              Path constraintPath ) {
52              return ValueComparators.PATH_COMPARATOR.compare(nodePath, constraintPath) < 0;
53          }
54  
55          @Override
56          public String toString() {
57              return " < ";
58          }
59      };
60      protected static final Evaluator<Path> PATH_IS_LESS_THAN_OR_EQUAL_TO = new Evaluator<Path>() {
61          private static final long serialVersionUID = 1L;
62  
63          public boolean satisfiesConstraint( Path nodePath,
64                                              Path constraintPath ) {
65              return ValueComparators.PATH_COMPARATOR.compare(nodePath, constraintPath) <= 0;
66          }
67  
68          @Override
69          public String toString() {
70              return " <= ";
71          }
72      };
73      protected static final Evaluator<Path> PATH_IS_GREATER_THAN = new Evaluator<Path>() {
74          private static final long serialVersionUID = 1L;
75  
76          public boolean satisfiesConstraint( Path nodePath,
77                                              Path constraintPath ) {
78              return ValueComparators.PATH_COMPARATOR.compare(nodePath, constraintPath) > 0;
79          }
80  
81          @Override
82          public String toString() {
83              return " > ";
84          }
85      };
86      protected static final Evaluator<Path> PATH_IS_GREATER_THAN_OR_EQUAL_TO = new Evaluator<Path>() {
87          private static final long serialVersionUID = 1L;
88  
89          public boolean satisfiesConstraint( Path nodePath,
90                                              Path constraintPath ) {
91              return ValueComparators.PATH_COMPARATOR.compare(nodePath, constraintPath) >= 0;
92          }
93  
94          @Override
95          public String toString() {
96              return " >= ";
97          }
98      };
99  
100     /**
101      * Construct a {@link Query} implementation that scores documents such that the node represented by the document has a path
102      * that is greater than the supplied constraint path.
103      * 
104      * @param constraintPath the constraint path; may not be null
105      * @param fieldName the name of the document field containing the path value; may not be null
106      * @param factories the value factories that can be used during the scoring; may not be null
107      * @param caseSensitive true if the comparison should be done in a case-sensitive manner, or false if it is to be
108      *        case-insensitive
109      * @return the path query; never null
110      */
111     public static ComparePathQuery createQueryForNodesWithPathGreaterThan( Path constraintPath,
112                                                                            String fieldName,
113                                                                            ValueFactories factories,
114                                                                            boolean caseSensitive ) {
115         return new ComparePathQuery(fieldName, constraintPath, factories.getPathFactory(), factories.getStringFactory(),
116                                     PATH_IS_GREATER_THAN, caseSensitive);
117     }
118 
119     /**
120      * Construct a {@link Query} implementation that scores documents such that the node represented by the document has a path
121      * that is greater than or equal to the supplied constraint path.
122      * 
123      * @param constraintPath the constraint path; may not be null
124      * @param fieldName the name of the document field containing the path value; may not be null
125      * @param factories the value factories that can be used during the scoring; may not be null
126      * @param caseSensitive true if the comparison should be done in a case-sensitive manner, or false if it is to be
127      *        case-insensitive
128      * @return the path query; never null
129      */
130     public static ComparePathQuery createQueryForNodesWithPathGreaterThanOrEqualTo( Path constraintPath,
131                                                                                     String fieldName,
132                                                                                     ValueFactories factories,
133                                                                                     boolean caseSensitive ) {
134         return new ComparePathQuery(fieldName, constraintPath, factories.getPathFactory(), factories.getStringFactory(),
135                                     PATH_IS_GREATER_THAN_OR_EQUAL_TO, caseSensitive);
136     }
137 
138     /**
139      * Construct a {@link Query} implementation that scores documents such that the node represented by the document has a path
140      * that is less than the supplied constraint path.
141      * 
142      * @param constraintPath the constraint path; may not be null
143      * @param fieldName the name of the document field containing the path value; may not be null
144      * @param factories the value factories that can be used during the scoring; may not be null
145      * @param caseSensitive true if the comparison should be done in a case-sensitive manner, or false if it is to be
146      *        case-insensitive
147      * @return the path query; never null
148      */
149     public static ComparePathQuery createQueryForNodesWithPathLessThan( Path constraintPath,
150                                                                         String fieldName,
151                                                                         ValueFactories factories,
152                                                                         boolean caseSensitive ) {
153         return new ComparePathQuery(fieldName, constraintPath, factories.getPathFactory(), factories.getStringFactory(),
154                                     PATH_IS_LESS_THAN, caseSensitive);
155     }
156 
157     /**
158      * Construct a {@link Query} implementation that scores documents such that the node represented by the document has a path
159      * that is less than or equal to the supplied constraint path.
160      * 
161      * @param constraintPath the constraint path; may not be null
162      * @param fieldName the name of the document field containing the path value; may not be null
163      * @param factories the value factories that can be used during the scoring; may not be null
164      * @param caseSensitive true if the comparison should be done in a case-sensitive manner, or false if it is to be
165      *        case-insensitive
166      * @return the path query; never null
167      */
168     public static ComparePathQuery createQueryForNodesWithPathLessThanOrEqualTo( Path constraintPath,
169                                                                                  String fieldName,
170                                                                                  ValueFactories factories,
171                                                                                  boolean caseSensitive ) {
172         return new ComparePathQuery(fieldName, constraintPath, factories.getPathFactory(), factories.getStringFactory(),
173                                     PATH_IS_LESS_THAN_OR_EQUAL_TO, caseSensitive);
174     }
175 
176     private final boolean caseSensitive;
177 
178     /**
179      * Construct a {@link Query} implementation that scores nodes according to the supplied comparator.
180      * 
181      * @param fieldName the name of the document field containing the path value; may not be null
182      * @param constraintPath the constraint path; may not be null
183      * @param pathFactory the value factory that can be used during the scoring; may not be null
184      * @param stringFactory the string factory that can be used during the scoring; may not be null
185      * @param evaluator the {@link CompareQuery.Evaluator} implementation that returns whether the node path satisfies the
186      *        constraint; may not be null
187      * @param caseSensitive true if the comparison should be done in a case-sensitive manner, or false if it is to be
188      *        case-insensitive
189      */
190     protected ComparePathQuery( String fieldName,
191                                 Path constraintPath,
192                                 ValueFactory<Path> pathFactory,
193                                 ValueFactory<String> stringFactory,
194                                 Evaluator<Path> evaluator,
195                                 boolean caseSensitive ) {
196         super(fieldName, constraintPath, pathFactory, stringFactory, evaluator);
197         this.caseSensitive = caseSensitive;
198     }
199 
200     /**
201      * {@inheritDoc}
202      * 
203      * @see org.modeshape.search.lucene.query.CompareQuery#readFromDocument(org.apache.lucene.index.IndexReader, int)
204      */
205     @Override
206     protected Path readFromDocument( IndexReader reader,
207                                      int docId ) throws IOException {
208         Document doc = reader.document(docId, fieldSelector);
209         String valueString = doc.get(fieldName);
210         if (!caseSensitive) valueString = valueString.toLowerCase();
211         return valueTypeFactory.create(valueString);
212     }
213 
214     /**
215      * {@inheritDoc}
216      * 
217      * @see org.apache.lucene.search.Query#clone()
218      */
219     @Override
220     public Object clone() {
221         return new ComparePathQuery(fieldName, constraintValue, valueTypeFactory, stringFactory, evaluator, caseSensitive);
222     }
223 }