/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/search/basic/BasicQueryImpl.java,v 1.10.2.2 2004/02/05 16:05:10 mholz Exp $
* $Revision: 1.10.2.2 $
* $Date: 2004/02/05 16:05:10 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.slide.search.basic;
import java.util.List;
import org.apache.slide.common.PropertyParseException;
import org.apache.slide.common.RequestedProperties;
import org.apache.slide.common.RequestedPropertiesImpl;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.Uri;
import org.apache.slide.search.BadQueryException;
import org.apache.slide.search.InvalidQueryException;
import org.apache.slide.search.InvalidScopeException;
import org.apache.slide.search.PropertyProvider;
import org.apache.slide.search.QueryScope;
import org.apache.slide.search.SearchException;
import org.apache.slide.search.SearchQueryResult;
import org.apache.slide.search.SearchToken;
import org.apache.slide.store.AbstractStore;
import org.jdom.Element;
import org.jdom.Namespace;
/**
* BasicQueryImpl represents the generic (store independent) implementation of
* BasicSearch.
*
* @author <a href="mailto:martin.wallmer@softwareag.com">Martin Wallmer</a>
* @version $Revision: 1.10.2.2 $
*/
public class BasicQueryImpl extends BasicQuery implements IBasicQuery {
/**
* Message of a BadQueryException that is thrown if the query element
* is <code>null</code>.
*/
public static final String NO_QUERY_ELEMENT = "No query element";
/**
* Message of a BadQueryException that is thrown if the query element
* does not contain a <from> element.
*/
public static final String FROM_ELEMENT_MISSING = "Required element <from> not supplied";
/**
* Message of a BadQueryException that is thrown if the query element
* does not contain a <select> element.
*/
public static final String SELECT_ELEMENT_MISSING = "Required element <select> not supplied";
/**
* Message of a BadQueryException that is thrown if the query element
* neither contains a <from> nor a <from> element.
*/
public static final String PROP_OR_ALLPROP_ELEMENT_MISSING = "Required element <prop> or <allprop> not supplied";
/**
* Message of a BadQueryException that is thrown if the query element
* neither contains a <from> nor a <from> element.
*/
public static final String NRESULTS_MISSING = "Required element <nresults> (when limit is supplied) not supplied";
/** the NotNormalizer, may be overridden in extending classes */
protected NotNormalizer notNormalizer;
IBasicExpressionFactory expressionFactory = new BasicExpressionFactory ();
/**
* Creates a BasicQueryImpl.
*/
public BasicQueryImpl (SearchToken searchToken) {
super.init (searchToken);
notNormalizer = new NotNormalizer ();
}
/**
* Default constructor, to enable creation by reflection
*/
public BasicQueryImpl() {
notNormalizer = new NotNormalizer ();
}
/**
* Initailize
*
* @param token a SearchToken
*
*/
/**
* Creates a BasicQueryImpl. Used for testing
*
* @param expressionCompilerProvider the provider which delivers the
* expression compiler to use.
*/
public BasicQueryImpl(SearchToken searchToken, IBasicExpressionCompilerProvider expressionCompilerProvider) {
init (searchToken);
this.expressionCompilerProvider = expressionCompilerProvider;
}
/**
* Executes a request.
*
* @return a SearchQueryResult
*
* @throws ServiceAccessException
*
*/
public SearchQueryResult execute () throws ServiceAccessException {
SearchQueryResult result = null;
try {
IBasicResultSet resultSet = getExpression().execute();
if (orderBy != null) {
if (isLimitDefined()) {
result = new SearchQueryResult (resultSet,
orderBy.getComparator(),
limit);
}
else {
result = new SearchQueryResult (resultSet,
orderBy.getComparator());
}
}
else {
result = new SearchQueryResult (resultSet);
}
if (resultSet.isPartialResultSet()) {
result.setStatus(SearchQueryResult.STATUS_PARTIAL_RESULT);
result.setDescription ("The server truncated the result set");
}
}
catch (InvalidScopeException e) {
result = new SearchQueryResult ();
result.setStatus (SearchQueryResult.STATUS_INVALID_SCOPE);
result.setHref (queryScope.getHref());
}
catch (BadQueryException e) { // is this only INVALID_SCOPE?
result = new SearchQueryResult ();
result.setStatus (SearchQueryResult.STATUS_BAD_QUERY);
result.setDescription (e.getMessage());
result.setHref (queryScope.getHref());
}
catch (SearchException e) { // is this only INVALID_SCOPE?
result = new SearchQueryResult ();
result.setStatus (SearchQueryResult.STATUS_BAD_QUERY);
result.setDescription (e.getMessage());
result.setHref (queryScope.getHref());
}
return result;
}
/**
* builds the internal structure from the JDOM tree
*
* @param expressionElement the (root) expression Element.
* @param propertyProvider the PropertyProvider to use (may be
* <code>null</code>).
*
* @throws BadQueryException
*/
public void parseQuery(Element expressionElement, PropertyProvider propertyProvider)
throws BadQueryException {
parseQueryWithoutExpression (expressionElement);
IBasicExpressionCompiler expressionCompiler = expressionCompilerProvider.getCompiler(this, propertyProvider);
// <where> is not mandatory
if (whereElement != null) {
List expressionList = whereElement.getChildren();
if (expressionList.size() != 1) {
throw new BadQueryException ("where must have exactly one nested element");
}
Element whereWithoutNot =
notNormalizer.getQueryWithoutNotExpression((Element)expressionList.get (0));
rootExpression = expressionCompiler.compile(whereWithoutNot);
}
else {
rootExpression = expressionCompiler.compile(null);
}
}
/**
* Method getSelectedProperties
*
* @return a SelectedPropertyList
*/
public RequestedProperties requestedProperties () {
return requestedProperties;
}
/**
* Method getExpression
*
* @return a BasicExpression
*
*/
// public IBasicExpression getExpression () {
// return rootExpression;
// }
/**
* Method getLimit
*
* @return the value of <limit>
*/
// public int getLimit () {
// return limit;
// }
/**
* Method getPropertyProvider
*
* @return a PropertyProvider
*
*/
// public PropertyProvider getPropertyProvider () {
// return propertyProvider;
// }
//
/**
* QueryScope accessor
*
* @return the Scope
*
*/
// public QueryScope getScope () {
// return queryScope;
// }
/**
* Method setScope
*
* @param queryScope a QueryScope
*
*/
// public void setScope (QueryScope queryScope) {
// this.queryScope = queryScope;
// }
/**
* Method getSlidePath
*
* @return a String
*
* @throws InvalidScopeException
*
*/
// public String getSlidePath () throws InvalidScopeException {
// return slideUri.getSlidePath (queryScope.getHref());
// }
/**
* Method getSearchToken
*
* @return a SearchToken
*
*/
// public SearchToken getSearchToken (){
// return searchToken;
// }
/**
* Method getStore
*
* @return an AbstractStore
*
*/
// public AbstractStore getStore () {
// return store;
// }
//
/**
* Builds the internal structure from the JDOM tree. Concrete implementations
* may use parseQueryElementWithoutExpression to create most of the
* objects describing the query.
*
* @param basicSearchElement the (root) expression Element.
* @param propertyProvider the PropertyProvider to use (may be
* <code>null</code>).
*
* @throws BadQueryException
*/
public void parseQueryElement (Element basicSearchElement,
PropertyProvider propertyProvider)
throws BadQueryException {
this.parseQueryElement (basicSearchElement,
propertyProvider,
getScope(basicSearchElement));
}
/**
* Builds the internal structure from the JDOM tree. Concrete implementations
* may use parseQueryElementWithoutExpression to create most of the
* objects describing the query.
*
* @param basicSearchElement the (root) expression Element.
* @param propertyProvider the PropertyProvider to use (may be
* <code>null</code>).
*
* @throws BadQueryException
*/
public void parseQueryElement (Element basicSearchElement,
PropertyProvider propertyProvider,
QueryScope queryScope)
throws BadQueryException {
this.queryScope = queryScope;
this.propertyProvider = propertyProvider;
// might be null in testsuite
if (searchToken.getNamespace() != null) {
// Uri uri = new Uri (searchToken.getNamespace(), slideUri.getSlidePath(queryScope.getHref()));
Uri uri = searchToken.getNamespace().getUri(this.getSearchToken().getSlideToken(), slideUri.getSlidePath(queryScope.getHref()));
store = (AbstractStore)uri.getStore();
}
parseQuery(basicSearchElement, propertyProvider);
}
/**
* Method isLimitDefined
*
* @return true if <limit> was specified
*/
// public boolean isLimitDefined () {
// return limitDefined;
// }
/**
* Needed to decide, which implementation of BasicQuery to load
* (hier rausschmeissen, nach BasicSearchLanguage)
* @param basicSearchElementJDOM an Element
*
* @return a QueryScope
*
* @throws BadQueryException
*
*/
public static QueryScope getScope(Element basicSearchElementJDOM)
throws BadQueryException {
if (basicSearchElementJDOM == null)
throw new BadQueryException (NO_QUERY_ELEMENT);
Namespace namespace = basicSearchElementJDOM.getNamespace();
Element fromElement = basicSearchElementJDOM.getChild
(Literals.FROM, namespace);
// FROM is mandatory
if (fromElement == null)
throw new BadQueryException (FROM_ELEMENT_MISSING);
return new BasicQueryScope (fromElement);
}
/**
* builds the internal structure from the JDOM tree. It may be used by the
* concrete implementation of BasicQuery. It does NOT create the tree of
* Expressions. This must be done in the specific implementation.
*
* @param basicSearchElement an Element
*
* @throws BadQueryException
*/
protected void parseQueryWithoutExpression (Element basicSearchElement)
throws BadQueryException {
if (basicSearchElement == null)
throw new BadQueryException (NO_QUERY_ELEMENT);
namespace = basicSearchElement.getNamespace();
Element selectElement = basicSearchElement.getChild
(Literals.SELECT, namespace);
// SELECT is mandatory
if (selectElement == null)
throw new BadQueryException (SELECT_ELEMENT_MISSING);
Element fromElement = basicSearchElement.getChild
(Literals.FROM, namespace);
// FROM is mandatory
if (fromElement == null) {
throw new BadQueryException (FROM_ELEMENT_MISSING);
}
whereElement = basicSearchElement.getChild
(Literals.WHERE, namespace);
Element orderByElement = basicSearchElement.getChild
(Literals.ORDERBY, namespace);
Element limitElement = basicSearchElement.getChild
(Literals.LIMIT, namespace);
Element propElement = selectElement.getChild (Literals.PROP, namespace);
if (propElement == null) {
propElement = selectElement.getChild (Literals.ALLPROP, namespace);
}
if (propElement == null) {
throw new BadQueryException(PROP_OR_ALLPROP_ELEMENT_MISSING);
}
requestedProperties = createRequestedProperties (propElement);
//queryScope = new BasicQueryScope (fromElement);
if (orderByElement != null) {
orderBy = createNewOrderBy (orderByElement);
}
if (limitElement != null) {
Element nResElem = limitElement.getChild (Literals.NRESULTS, namespace);
if (nResElem == null)
throw new BadQueryException (NRESULTS_MISSING);
limit = new Integer (nResElem.getTextTrim()).intValue();
limitDefined = true;
}
}
public IBasicExpressionFactory getExpressionFactory() {
return expressionFactory;
}
protected OrderBy createNewOrderBy (Element orderByElement) throws InvalidQueryException {
OrderBy result = new OrderBy ();
result.init(orderByElement);
return result;
}
/**
* This method may be overridden, if a store specific implementation adds
* new property semantic.
*
* @param propElement an Element
*
* @return a RequestedProperties
*
*/
protected RequestedProperties createRequestedProperties (Element propElement) throws BadQueryException {
try {
return new RequestedPropertiesImpl (propElement);
}
catch (PropertyParseException e) {
throw new BadQueryException (e.getMessage(), e);
}
}
}