/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/search/basic/BasicQueryEnvelope.java,v 1.8.2.1 2004/02/05 16:05:10 mholz Exp $
* $Revision: 1.8.2.1 $
* $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 org.jdom.Element;
import org.apache.slide.search.PropertyProvider;
import org.apache.slide.search.BadQueryException;
import org.apache.slide.search.QueryScope;
import org.apache.slide.search.SearchQuery;
import org.apache.slide.search.SlideUri;
import org.apache.slide.search.SearchQueryResult;
import org.apache.slide.search.InvalidScopeException;
import org.apache.slide.search.SearchToken;
import org.apache.slide.common.RequestedProperties ;
import org.apache.slide.common.Scope;
import org.apache.slide.common.Uri;
import org.apache.slide.common.SlideRuntimeException;
import org.apache.slide.common.Namespace;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.store.AbstractStore ;
import java.util.HashSet;
import java.util.Set;
import java.util.HashMap;
import java.util.Map;
//import java.util.ArrayList;
//import java.util.List;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.StringTokenizer;
/**
* Envelopes all queries that are necessary, if a scope covers several stores.
* For example: /mycoll is mapped to an SQL store, /mycoll/xml is mapped to an
* XML database. A query with scope /mycoll must be divided in two different
* queries, the result must be joined.
*
* @version $Revision: 1.8.2.1 $
*
* @author <a href="mailto:martin.wallmer@softwareag.com">Martin Wallmer</a>
**/
public class BasicQueryEnvelope extends SearchQuery implements IBasicQuery {
private BasicQueryImpl topLevelQuery;
private QueryScope topLevelQueryScope;
private Map subQueries = new HashMap();
private QueryTree queryTree;
private int queryDepth;
private SlideUri slideUri;
private SearchToken token;
/*
* Constructs a BasicQueryEnvelope
*
* @param token the searchtoken
* @param queryScope the scope of this query
*
* @throws InvalidScopeException
*/
public BasicQueryEnvelope (SearchToken token, QueryScope queryScope)
throws InvalidScopeException
{
this.token = token;
Namespace namespace = token.getNamespace();
Enumeration stores = namespace.enumerateScopes();
this.slideUri = token.getSlideContext();
this.topLevelQueryScope = queryScope;
String slideScope = slideUri.getSlidePath(queryScope.getHref());
Scope topScope = new Scope (slideScope);
Set ex = queryScope.getExcludedScopes();
int size = ex.size();
Scope [] excludedScopes = new Scope [size] ;
Iterator it = ex.iterator();
for (int i = 0; i < size; i++) {
String href = (String)it.next();
excludedScopes [i] = new Scope (slideUri.getSlidePath(href));
}
this.queryTree = new QueryTree (stores, topScope, excludedScopes);
it = queryTree.iterator();
while (it.hasNext()) {
Scope sScope = (Scope)it.next();
// System.out.println("createEnvelope for scope " + sScope);
BasicQueryImpl query = createSubQuery (namespace, sScope.toString(), token);
subQueries.put (sScope, query);
}
topLevelQuery = (BasicQueryImpl) subQueries.get (topScope);
}
/**
* parses all subQueries. The scope must be calculated for each subquery.
*
* @param basicSearchElement an Element
* @param propertyProvider a PropertyProvider
*
* @throws BadQueryException
*
*/
public void parseQueryElement (Element basicSearchElement,
PropertyProvider propertyProvider)
throws BadQueryException
{
//topLevelQuery.parseQueryElement (basicSearchElement, propertyProvider);
// queryDepth = topLevelQueryScope.getDepth();
// WAM restrict depth to what is defined in web.xml
queryDepth = Math.min (topLevelQueryScope.getDepth(), token.getMaxDepth());
Iterator it = subQueries.keySet().iterator();
Set scopesToRemove = new HashSet ();
while (it.hasNext()) {
Scope scope = (Scope)it.next();
// System.out.println ("parseQueryElement for scope " + scope);
QueryScope subQueryScope = calculateSubQueryScope (scope);
if (subQueryScope.getDepth() >= 0) {
BasicQueryImpl query = (BasicQueryImpl)subQueries.get (scope);
query.parseQueryElement (basicSearchElement, propertyProvider, subQueryScope);
}
else {
scopesToRemove.add (scope);
}
}
it = scopesToRemove.iterator();
while (it.hasNext()) {
subQueries.remove(it.next());
}
}
/**
* Executes each involved query and merges the results
*
* @return a SearchQueryResult
*
* @throws ServiceAccessException
*
*/
public SearchQueryResult execute() throws ServiceAccessException {
Iterator it = subQueries.keySet().iterator();
SearchQueryResult result = null;
if (topLevelQuery.orderBy != null) {
result = new SearchQueryResult (topLevelQuery.orderBy.getComparator());
}
else {
result = new SearchQueryResult ();
}
while (it.hasNext()) {
Scope scope = (Scope)it.next();
BasicQuery query = (BasicQuery)subQueries.get (scope);
query.setScope (calculateSubQueryScope(scope));
SearchQueryResult subResult = query.execute();
result.add (subResult);
if (subResult.getStatus() != 0) {
result.setStatus (subResult.getStatus());
result.setDescription (subResult.getDescription());
}
}
return result;
}
/**
* calculates a QueryScope for the defined store
*
* @param scope the scope
*
* @return a QueryScope
*
*/
private QueryScope calculateSubQueryScope (Scope scope) {
int relDepth = queryTree.relativeDepth (scope);
int subQueryDepth;
if (queryTree.hasChildren (scope)) {
subQueryDepth = 1;
}
else if (queryDepth == QueryScope.DEPTH_INFINITY) {
subQueryDepth = QueryScope.DEPTH_INFINITY;
}
else {
subQueryDepth = queryDepth - relDepth;
}
String contextPath = slideUri.getContextPath (scope.toString());
Set inclSet = topLevelQueryScope.getIncludeSet();
Set exclSet = topLevelQueryScope.getExcludeSet();
QueryScope queryScope = new BasicQueryScope
(contextPath, subQueryDepth, inclSet, exclSet);
return queryScope;
}
/**
* Method getDepthOfHRef
*
* @param href a String
*
* @return an int
*
*/
private int getDepthOfHRef (String href) {
StringTokenizer st = new StringTokenizer (href, "/");
return st.countTokens();
}
/**
* creates a subquery
*
* @param namespace a Namespace
* @param slideScope a String
* @param token a SearchToken
*
* @return a BasicQueryImpl
*
* @throws SlideRuntimeException
*
*/
private BasicQueryImpl createSubQuery (Namespace namespace,
String slideScope,
SearchToken token)
throws SlideRuntimeException
{
BasicQueryImpl query = null;
// Uri uri = new Uri (namespace, slideScope);
Uri uri = namespace.getUri(token.getSlideToken(), slideScope);
AbstractStore store = (AbstractStore)uri.getStore();
String className = (String)store.getParameter
(BasicSearchLanguage.BASIC_QUERY_CLASS);
if (className != null) {
try {
Class queryClass = Class.forName (className);
query = (BasicQueryImpl) queryClass.newInstance();
((BasicQueryImpl) query).init (token);
}
catch (Exception e) {
e.printStackTrace();
throw new SlideRuntimeException (e.getMessage());
}
}
else {
query = new BasicQueryImpl(token);
}
return query;
}
/**
* Method getStore
*
* @return an AbstractStore
*
*/
public AbstractStore getStore() {
return topLevelQuery.getStore();
}
/**
* Method getScope
*
* @return a QueryScope
*
*/
public QueryScope getScope() {
return topLevelQueryScope;
}
/**
* Method getPropertyProvider
*
* @return a PropertyProvider
*
*/
public PropertyProvider getPropertyProvider() {
return topLevelQuery.getPropertyProvider();
}
/**
* Method isLimitDefined
*
* @return a boolean
*
*/
public boolean isLimitDefined() {
return topLevelQuery.isLimitDefined();
}
/**
* Method getLimit
*
* @return an int
*
*/
public int getLimit() {
return topLevelQuery.getLimit();
}
/**
* Method getExpression
*
* @return an IBasicExpression
*
*/
public IBasicExpression getExpression() {
return topLevelQuery.getExpression();
}
/**
* Method requestedProperties
*
* @return a RequestedProperties
*
*/
public RequestedProperties requestedProperties() {
return topLevelQuery.requestedProperties;
}
/**
* Method getSlidePath
*
* @return a String
*
* @throws InvalidScopeException
*
*/
public String getSlidePath() throws InvalidScopeException {
return topLevelQuery.getSlidePath();
}
/**
* Method getSearchToken
*
* @return a SearchToken
*
*/
public SearchToken getSearchToken() {
return topLevelQuery.getSearchToken();
}
public IBasicExpressionFactory getExpressionFactory() {
return null;
}
public void init (SearchToken token) {
this.token = token;
}
}