001: /*
002: * $Header$
003: * $Revision: 7953 $
004: * $Date: 2007-08-23 03:42:37 -0700 $
005: *
006: * ====================================================================
007: *
008: * Copyright 1999-2002 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:
024: package org.apache.slide.search.basic;
025:
026: import java.util.List;
027:
028: import org.apache.slide.common.ServiceAccessException;
029: import org.apache.slide.content.NodeProperty;
030: import org.apache.slide.index.lucene.LuceneExpressionFactory;
031: import org.apache.slide.index.lucene.LuceneOrderBy;
032: import org.apache.slide.index.lucene.expressions.AbstractLuceneExpression;
033: import org.apache.slide.search.BadQueryException;
034: import org.apache.slide.search.InvalidQueryException;
035: import org.apache.slide.search.InvalidScopeException;
036: import org.apache.slide.search.LuceneSearchQueryResult;
037: import org.apache.slide.search.QueryScope;
038: import org.apache.slide.search.SearchException;
039: import org.apache.slide.search.SearchQueryResult;
040: import org.apache.slide.search.SearchToken;
041: import org.jdom.Element;
042: import org.jdom.Namespace;
043:
044: /**
045: * BasicQueryImpl represents the generic (store independent) implementation of
046: * BasicSearch.
047: *
048: * @version $Revision: 7953 $
049: */
050: public class LuceneBasicQuery extends BasicQueryImpl {
051:
052: /**
053: * Message of a BadQueryException that is thrown if the <nresults> element
054: * is not an integer.
055: */
056: public static final String OFFSET_MUST_BE_AN_INTEGER = "<offset> should be an integer";
057:
058: /**
059: * some specific instance vars, like offset parsed from query
060: */
061: protected int offset = 0;
062: protected boolean offsetDefined = false;
063:
064: /**
065: * Creates a BasicQueryImpl.
066: */
067: public LuceneBasicQuery(SearchToken searchToken) {
068: super (searchToken);
069:
070: }
071:
072: /**
073: * Default constructor, to enable creation by reflection
074: */
075: public LuceneBasicQuery() {
076: super ();
077:
078: }
079:
080: /**
081: * Creates a BasicQueryImpl. Used for testing
082: *
083: * @param expressionCompilerProvider the provider which delivers the
084: * expression compiler to use.
085: */
086: public LuceneBasicQuery(SearchToken searchToken,
087: IBasicExpressionCompilerProvider expressionCompilerProvider) {
088: super (searchToken, expressionCompilerProvider);
089:
090: }
091:
092: /**
093: * Executes a request.
094: *
095: * @return a SearchQueryResult
096: *
097: * @throws ServiceAccessException
098: *
099: */
100: public SearchQueryResult execute() throws ServiceAccessException {
101: SearchQueryResult result = null;
102:
103: try {
104:
105: IBasicExpression expression = getExpression();
106: IBasicResultSet resultSet = null;
107:
108: int _limit = -1;
109: if (isLimitDefined())
110: _limit = limit;
111:
112: if (expression instanceof AbstractLuceneExpression) {
113: AbstractLuceneExpression luceneexp = (AbstractLuceneExpression) expression;
114:
115: if (isOffsetDefined())
116: luceneexp.setOffset(this .offset);
117:
118: resultSet = luceneexp.execute(orderBy, _limit);
119:
120: if (orderBy != null) {
121: result = new LuceneSearchQueryResult(resultSet,
122: orderBy.getComparator(), _limit);
123: } else {
124: result = new LuceneSearchQueryResult(resultSet,
125: null, _limit);
126: }
127:
128: } else {
129: resultSet = expression.execute();
130:
131: if (orderBy != null) {
132: result = new SearchQueryResult(resultSet, orderBy
133: .getComparator(), _limit);
134: } else {
135: result = new SearchQueryResult(resultSet);
136: }
137: }
138:
139: if (resultSet != null && resultSet.isPartialResultSet()) {
140: result
141: .setStatus(SearchQueryResult.STATUS_PARTIAL_RESULT);
142: result
143: .setDescription("The server truncated the result set");
144: }
145:
146: }
147:
148: catch (InvalidScopeException e) {
149: result = new SearchQueryResult();
150: result.setStatus(SearchQueryResult.STATUS_INVALID_SCOPE);
151: String href = null;
152: if (queryScope.length != 0)
153: href = queryScope[0].getHref();
154: result.setHref(href);
155: }
156:
157: catch (BadQueryException e) { // is this only INVALID_SCOPE?
158: result = new SearchQueryResult();
159: result.setStatus(SearchQueryResult.STATUS_BAD_QUERY);
160: result.setDescription(e.getMessage());
161: String href = null;
162: if (queryScope.length != 0)
163: href = queryScope[0].getHref();
164: result.setHref(href);
165: }
166:
167: catch (SearchException e) { // is this only INVALID_SCOPE?
168: result = new SearchQueryResult();
169: result.setStatus(SearchQueryResult.STATUS_BAD_QUERY);
170: result.setDescription(e.getMessage());
171: String href = null;
172: if (queryScope.length != 0)
173: href = queryScope[0].getHref();
174: result.setHref(href);
175: }
176:
177: return result;
178: }
179:
180: protected OrderBy createNewOrderBy(Element orderByElement)
181: throws InvalidQueryException {
182:
183: IBasicExpressionFactory fac = getPropertiesExpressionFactory();
184:
185: OrderBy result = null;
186:
187: if (fac != null && fac instanceof LuceneExpressionFactory) {
188: //result = new LuceneOrderBy (((LuceneExpressionFactory)fac).getIndex());
189: result = new LuceneOrderBy();
190: } else
191: result = new OrderBy();
192:
193: result.init(orderByElement);
194: return result;
195: }
196:
197: /**
198: * builds the internal structure from the JDOM tree. It may be used by the
199: * concrete implementation of BasicQuery. It does NOT create the tree of
200: * Expressions. This must be done in the specific implementation.
201: *
202: * @param basicSearchElement an Element
203: *
204: * @throws BadQueryException
205: */
206: protected void parseQueryWithoutExpression(
207: Element basicSearchElement) throws BadQueryException {
208:
209: if (basicSearchElement == null)
210: throw new BadQueryException(NO_QUERY_ELEMENT);
211:
212: namespace = basicSearchElement.getNamespace();
213:
214: Element selectElement = basicSearchElement.getChild(
215: Literals.SELECT, namespace);
216:
217: // SELECT is mandatory
218: if (selectElement == null)
219: throw new BadQueryException(SELECT_ELEMENT_MISSING);
220:
221: Element fromElement = basicSearchElement.getChild(
222: Literals.FROM, namespace);
223:
224: // FROM is mandatory
225: if (fromElement == null) {
226: throw new BadQueryException(FROM_ELEMENT_MISSING);
227: }
228:
229: whereElement = basicSearchElement.getChild(Literals.WHERE,
230: namespace);
231:
232: Element orderByElement = basicSearchElement.getChild(
233: Literals.ORDERBY, namespace);
234:
235: Element limitElement = basicSearchElement.getChild(
236: Literals.LIMIT, namespace);
237:
238: Element propElement = selectElement.getChild(Literals.PROP,
239: namespace);
240: if (propElement == null) {
241: propElement = selectElement.getChild(Literals.ALLPROP,
242: namespace);
243: }
244:
245: if (propElement == null) {
246: throw new BadQueryException(PROP_OR_ALLPROP_ELEMENT_MISSING);
247: }
248:
249: requestedProperties = createRequestedProperties(propElement);
250:
251: queryScope = getScope(fromElement);
252:
253: if (orderByElement != null) {
254: orderBy = createNewOrderBy(orderByElement);
255: }
256:
257: if (limitElement != null) {
258: Element nResElem = limitElement.getChild(Literals.NRESULTS,
259: namespace);
260: if (nResElem == null)
261: throw new BadQueryException(NRESULTS_MISSING);
262: try {
263: limit = new Integer(nResElem.getTextTrim()).intValue();
264: } catch (NumberFormatException e) {
265: throw new BadQueryException(NRESULTS_MUST_BE_AN_INTEGER);
266: }
267: limitDefined = true;
268:
269: nResElem = limitElement.getChild("offset",
270: NodeProperty.NamespaceCache.SLIDE_NAMESPACE);
271:
272: if (nResElem != null) {
273: try {
274: offset = new Integer(nResElem.getTextTrim())
275: .intValue();
276: } catch (NumberFormatException e) {
277: throw new BadQueryException(
278: OFFSET_MUST_BE_AN_INTEGER);
279: } catch (Exception IGNORE) {
280: } // maybe NPE if element doesn't exist
281: offsetDefined = true;
282: }
283: }
284: }
285:
286: /**
287: * Method isOffsetDefined
288: *
289: * @return true if <offset> was specified
290: */
291: public boolean isOffsetDefined() {
292: return offsetDefined;
293: }
294:
295: /**
296: * Method getOffset
297: *
298: * @return the value of <offset>
299: */
300: public int getOffset() {
301: return offset;
302: }
303:
304: /**
305: * Needed to decide, which implementation of BasicQuery to load
306: *
307: * @param basicSearchElementJDOM an Element
308: *
309: * @return a QueryScope
310: *
311: * @throws BadQueryException
312: *
313: */
314: public static QueryScope[] getScope(Element basicSearchElementJDOM)
315: throws BadQueryException {
316: if (basicSearchElementJDOM == null)
317: throw new BadQueryException(NO_QUERY_ELEMENT);
318:
319: Namespace namespace = basicSearchElementJDOM.getNamespace();
320: String name = basicSearchElementJDOM.getName();
321:
322: Element fromElement = null;
323: if (name.equals(Literals.FROM))
324: fromElement = basicSearchElementJDOM;
325: else
326: fromElement = basicSearchElementJDOM.getChild(
327: Literals.FROM, namespace);
328:
329: // FROM is mandatory
330: if (fromElement == null)
331: throw new BadQueryException(FROM_ELEMENT_MISSING);
332:
333: if (fromElement.getChildren(Literals.SCOPE, namespace).size() == 0)
334: throw new BadQueryException(SCOPE_ELEMENT_MISSING);
335:
336: List scopeElems = fromElement.getChildren(Literals.SCOPE,
337: namespace);
338: QueryScope[] scopes = new QueryScope[scopeElems.size()];
339: for (int i = 0; i < scopes.length; i++) {
340: Element s = (Element) scopeElems.get(i);
341: scopes[i] = new LuceneBasicQueryScope(s);
342: }
343:
344: return scopes;
345: }
346:
347: }
|