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 }