001: /*
002: * $Header$
003: * $Revision: 6575 $
004: * $Date: 2007-06-04 04:12:05 -0700 $
005: *
006: * ====================================================================
007: *
008: * Copyright 1999-2004 The Apache Software Foundation
009: *
010: * Licensed under the Apache License, Version 2.0 (the "License");
011: * you may not use this file except in compliance with the License.
012: * You may obtain a copy of the License at
013: *
014: * http://www.apache.org/licenses/LICENSE-2.0
015: *
016: * Unless required by applicable law or agreed to in writing, software
017: * distributed under the License is distributed on an "AS IS" BASIS,
018: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019: * See the License for the specific language governing permissions and
020: * limitations under the License.
021: *
022: */
023: package org.apache.slide.index.lucene;
024:
025: import java.util.ArrayList;
026: import java.util.Collection;
027: import java.util.Iterator;
028: import java.util.List;
029:
030: import org.apache.slide.content.NodeProperty;
031: import org.apache.slide.index.lucene.expressions.AbstractLuceneExpression;
032: import org.apache.slide.index.lucene.expressions.BetweenExpression;
033: import org.apache.slide.index.lucene.expressions.ContainsExpression;
034: import org.apache.slide.index.lucene.expressions.EqExpression;
035: import org.apache.slide.index.lucene.expressions.GtExpression;
036: import org.apache.slide.index.lucene.expressions.EmptyExpression;
037: import org.apache.slide.index.lucene.expressions.IsCollectionExpression;
038: import org.apache.slide.index.lucene.expressions.IsDefinedExpression;
039: import org.apache.slide.index.lucene.expressions.IsPrincipalExpression;
040: import org.apache.slide.index.lucene.expressions.IsVersionHistoryExpression;
041: import org.apache.slide.index.lucene.expressions.LikeExpression;
042: import org.apache.slide.index.lucene.expressions.LtExpression;
043: import org.apache.slide.index.lucene.expressions.MergeExpression;
044: import org.apache.slide.index.lucene.expressions.PropSearchExpression;
045: import org.apache.slide.index.lucene.expressions.PropcontainsExpression;
046: import org.apache.slide.index.lucene.expressions.PropertyContainsExpression;
047: import org.apache.slide.index.lucene.expressions.StrictPropertyContainsExpression;
048: import org.apache.slide.search.BadQueryException;
049: import org.apache.slide.search.PropertyProvider;
050: import org.apache.slide.search.basic.BasicExpressionFactory;
051: import org.apache.slide.search.basic.IBasicExpression;
052: import org.apache.slide.search.basic.IBasicQuery;
053: import org.apache.slide.search.basic.Literals;
054: import org.jdom.Element;
055:
056: /**
057: */
058: public class LuceneExpressionFactory extends BasicExpressionFactory {
059:
060: private Index index;
061:
062: /**
063: * Constructor
064: *
065: */
066: public LuceneExpressionFactory(Index index) {
067: this .index = index;
068: }
069:
070: public Index getIndex() {
071: return this .index;
072: }
073:
074: public IBasicExpression createMergeExpression(String mergeOperator,
075: String namespace, Collection expressionsToMerge)
076: throws BadQueryException {
077: IBasicExpression result = null;
078:
079: if (expressionsToMerge.size() == 0) {
080: if (index.getLogger().isDebugEnabled())
081: index.getLogger().debug(
082: "Factory: Making merge expression '"
083: + mergeOperator
084: + "' but no expressions to merge!");
085: return null; // TOCHECK
086: }
087:
088: List luceneExpressions = new ArrayList(expressionsToMerge
089: .size());
090: List basicExpressions = new ArrayList(expressionsToMerge.size());
091: for (Iterator i = expressionsToMerge.iterator(); i.hasNext();) {
092: Object o = i.next();
093: if (o instanceof AbstractLuceneExpression) {
094: luceneExpressions.add(o);
095: } else {
096: basicExpressions.add(o);
097: }
098: }
099:
100: if (index.getLogger().isDebugEnabled())
101: index.getLogger().debug(
102: "Factory: Making merge expression '"
103: + mergeOperator + "' ("
104: + basicExpressions.size() + "/"
105: + luceneExpressions.size() + ")");
106:
107: if (namespace.equals(NodeProperty.NamespaceCache.DEFAULT_URI)) {
108: if (mergeOperator.equals(Literals.OR)) {
109: if (basicExpressions.size() > 0
110: && luceneExpressions.size() > 0) {
111: // a mixture
112: IBasicExpression e1 = new MergeExpression(
113: this .index, false, luceneExpressions);
114: e1.setFactory(this );
115: basicExpressions.add(0, e1);
116: result = super .createMergeExpression(Literals.OR,
117: namespace, basicExpressions);
118: } else if (luceneExpressions.size() > 0) {
119: // lucene expressions only
120: if (index.getLogger().isDebugEnabled())
121: index.getLogger().debug(
122: "Factory: Making lucene OR");
123: result = new MergeExpression(this .index, false,
124: expressionsToMerge);
125: } else {
126: // basic expressions only
127: result = super .createMergeExpression(mergeOperator,
128: namespace, expressionsToMerge);
129: }
130: } else if (mergeOperator.equals(Literals.AND)) {
131: if (basicExpressions.size() > 0
132: && luceneExpressions.size() > 0) {
133: // a mixture between fast lucene expr. and slow basic expr.
134: IBasicExpression e = new MergeExpression(
135: this .index, true, luceneExpressions);
136: e.setFactory(this );
137: basicExpressions.add(0, e);
138: result = super .createMergeExpression(Literals.AND,
139: namespace, basicExpressions);
140: } else if (luceneExpressions.size() > 0) {
141: // lucene expressions only
142: if (index.getLogger().isDebugEnabled())
143: index.getLogger().debug(
144: "Factory: Making lucene AND");
145: result = new MergeExpression(this .index, true,
146: expressionsToMerge);
147: } else {
148: // basic expressions only
149: result = super .createMergeExpression(mergeOperator,
150: namespace, expressionsToMerge);
151: }
152: } else {
153: super .createMergeExpression(mergeOperator, namespace,
154: expressionsToMerge);
155: }
156: }
157: if (result != null) {
158: result.setFactory(this );
159: }
160:
161: return result;
162: }
163:
164: public IBasicExpression createExpression(Element element)
165: throws BadQueryException {
166: IBasicExpression result = null;
167:
168: if (index.getLogger().isDebugEnabled())
169: index.getLogger().debug(
170: "Factory: Making expression '" + element + "'");
171:
172: if (element == null) {
173: //return super.createExpression(element);
174: result = new EmptyExpression(this .index);
175: } else {
176: String namespace = element.getNamespace().getURI();
177: if (namespace
178: .equals(NodeProperty.NamespaceCache.DEFAULT_URI)) {
179: result = createDAVExpression(element);
180: } else if (namespace
181: .equals(NodeProperty.NamespaceCache.SLIDE_URI)) {
182: result = createSlideExpression(element);
183: } else {
184: result = super .createExpression(element);
185: }
186: }
187: if (result != null) {
188: result.setFactory(this );
189: }
190: return result;
191: }
192:
193: private IBasicExpression createDAVExpression(Element e)
194: throws BadQueryException {
195: String operator = e.getName();
196:
197: if (index.getLogger().isDebugEnabled())
198: index.getLogger().debug(
199: "Factory: Making dav expression '" + e.toString()
200: + "'");
201:
202: if (operator.equals(Literals.ISCOLLECTION)) {
203: return new IsCollectionExpression(this .index, false);
204: }
205: if (operator.equals(Literals.NOT_ISCOLLECTION)) {
206: return new IsCollectionExpression(this .index, true);
207: } else if (operator.equals(Literals.CONTAINS)) {
208: return new ContainsExpression(this .index, e, false);
209: } else if (operator.equals(Literals.NOT_CONTAINS)) {
210: return new ContainsExpression(this .index, e, true);
211: }
212:
213: // the following expressions all are property related and
214: // must have a <DAV:prop> element
215: Element property = AbstractLuceneExpression
216: .getPropertyElement(e);
217: String namespace = property.getNamespaceURI();
218: String name = property.getName();
219: IndexConfiguration configuration = index.getConfiguration();
220:
221: if (operator.equals(Literals.EQ)) {
222: if (configuration.isComparableProperty(namespace, name)) {
223: return new EqExpression(this .index, e, false);
224: }
225: } else if (operator.equals(Literals.NOT_EQ)) {
226: if (configuration.isComparableProperty(namespace, name)) {
227: return new EqExpression(this .index, e, true);
228: }
229: } else if (operator.equals(Literals.LT)
230: || operator.equals(Literals.NOT_GTE)) {
231: if (configuration.isComparableProperty(namespace, name)) {
232: return new LtExpression(this .index, e, false);
233: }
234: } else if (operator.equals(Literals.LTE)
235: || operator.equals(Literals.NOT_GT)) {
236: if (configuration.isComparableProperty(namespace, name)) {
237: return new LtExpression(this .index, e, true);
238: }
239: } else if (operator.equals(Literals.GT)
240: || operator.equals(Literals.NOT_LTE)) {
241: if (configuration.isComparableProperty(namespace, name)) {
242: return new GtExpression(this .index, e, false);
243: }
244: } else if (operator.equals(Literals.GTE)
245: || operator.equals(Literals.NOT_LT)) {
246: if (configuration.isComparableProperty(namespace, name)) {
247: return new GtExpression(this .index, e, true);
248: }
249: } else if (operator.equals(Literals.LIKE)) {
250: if (configuration.isStringProperty(namespace, name)) {
251: return new LikeExpression(this .index, e, false);
252: }
253: } else if (operator.equals(Literals.NOT_LIKE)) {
254: if (configuration.isStringProperty(namespace, name)) {
255: return new LikeExpression(this .index, e, true);
256: }
257: } else if (operator.equals(Literals.ISDEFINED)) {
258: if (configuration.supportsIsDefined(namespace, name)) {
259: return new IsDefinedExpression(this .index, e, false);
260: }
261: } else if (operator.equals(Literals.NOT_ISDEFINED)) {
262: if (configuration.supportsIsDefined(namespace, name)) {
263: return new IsDefinedExpression(this .index, e, true);
264: }
265: }
266:
267: // fallback: if we don't know the operator or the property is not
268: // supported with the given operator
269:
270: // [BvdS] : Slide fails on fallback mode on large namespaces..
271:
272: if (index.getLogger().isDebugEnabled())
273: index.getLogger().debug(
274: "Factory: Uncomparable expression '" + e.getName()
275: + "' for property '" + name + "'.");
276: throw new BadQueryException(
277: "Factory: Uncomparable expression '" + e.getName()
278: + "' for property '" + name + "'.");
279: //return super.createExpression(e);
280: }
281:
282: private IBasicExpression createSlideExpression(Element e)
283: throws BadQueryException {
284: String operator = e.getName();
285:
286: if (index.getLogger().isDebugEnabled())
287: index.getLogger().debug(
288: "Factory: Making slide expression '" + e.toString()
289: + "'");
290:
291: if (operator.equals(Literals.ISPRINCIPAL)) {
292: return new IsPrincipalExpression(this .index, false);
293: }
294: if (operator.equals(Literals.NOT_ISPRINCIPAL)) {
295: return new IsPrincipalExpression(this .index, true);
296: }
297: if (operator.equals("is-version-history")) {
298: return new IsVersionHistoryExpression(index, false);
299: }
300: if (operator.equals("not-is-version-history")) {
301: return new IsVersionHistoryExpression(index, true);
302: }
303:
304: Element property = AbstractLuceneExpression
305: .getPropertyElement(e);
306: String namespace = property.getNamespaceURI();
307: String name = property.getName();
308: IndexConfiguration configuration = index.getConfiguration();
309:
310: // TODO not-between
311: if (operator.equals("between")) {
312: if (configuration.isComparableProperty(namespace, name)) {
313: return new BetweenExpression(this .index, e, false,
314: false);
315: }
316: }
317: if (operator.equals("between-inclusive")) {
318: if (configuration.isComparableProperty(namespace, name)) {
319: return new BetweenExpression(this .index, e, true, false);
320: }
321: }
322: if (operator.equals("property-contains")) {
323: if (configuration.isTextProperty(namespace, name)) {
324: return new PropertyContainsExpression(this .index, e,
325: false);
326: }
327: }
328: if (operator.equals("propsearch")) {
329: if (configuration.isStringProperty(namespace, name)) {
330: return new PropSearchExpression(this .index, e, false);
331: }
332: }
333: if (operator.equals("not-property-contains")) {
334: if (configuration.isTextProperty(namespace, name)) {
335: return new PropertyContainsExpression(this .index, e,
336: true);
337: }
338: }
339: // *************** new method for use with comma-separated-list properties WITH SPACES
340: if (operator.equals("strict-property-contains")) {
341: if (configuration.isTextProperty(namespace, name)) {
342: return new StrictPropertyContainsExpression(this .index,
343: e, false);
344: }
345: }
346: if (operator.equals("not-strict-property-contains")) {
347: if (configuration.isTextProperty(namespace, name)) {
348: return new StrictPropertyContainsExpression(this .index,
349: e, true);
350: }
351: }
352: // *******************************************************************
353:
354: if (operator.equals(Literals.PROPCONTAINS)) {
355: if (configuration.isStringProperty(namespace, name)
356: || configuration.isTextProperty(namespace, name)) {
357: return new PropcontainsExpression(this .index, e, false);
358: }
359: }
360: if (operator.equals(Literals.NOT_PROPCONTAINS)) {
361: if (configuration.isStringProperty(namespace, name)
362: || configuration.isTextProperty(namespace, name)) {
363: return new PropcontainsExpression(this .index, e, true);
364: }
365: }
366:
367: // fallback: if we don't know the operator or the property is not
368: // supported with the given operator
369:
370: // [BvdS] : Slide fails on fallback mode on large namespaces..
371: if (index.getLogger().isDebugEnabled())
372: index.getLogger().debug(
373: "Factory: Uncomparable expression '" + e.getName()
374: + "' for property '" + name + "'.");
375: throw new BadQueryException(
376: "Factory: Uncomparable expression '" + e.getName()
377: + "' for property '" + name + "'.");
378: //return super.createExpression(e);
379: }
380:
381: /**
382: * called by BasicExpressionCompiler after construction.
383: *
384: * @param query the associated BasicQuery
385: * @param propertyProvider the PropertyProvider for this expression.
386: *
387: * @throws BadQueryException
388: *
389: */
390: public void init(IBasicQuery query,
391: PropertyProvider propertyProvider) throws BadQueryException {
392: this.query = query;
393: this.propertyProvider = propertyProvider;
394: }
395: }
|