/*
* Portions of this file Copyright 1999-2005 University of Chicago
* Portions of this file Copyright 1999-2005 The University of Southern California.
*
* This file or a portion of this file is licensed under the
* terms of the Globus Toolkit Public License, found at
* http://www.globus.org/toolkit/download/license.html.
* If you redistribute this file, with or without
* modifications, you must include this notice in the file.
*/
package org.globus.mds.bigindex.impl;
import java.rmi.RemoteException;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.globus.wsrf.Constants;
import org.globus.wsrf.WSRFConstants;
import org.globus.wsrf.ResourceProperties;
import org.globus.wsrf.ResourcePropertySet;
import org.globus.wsrf.ResourceContext;
import org.globus.wsrf.NoSuchResourceException;
import org.globus.wsrf.query.QueryEngine;
import org.globus.wsrf.query.UnsupportedQueryDialectException;
import org.globus.wsrf.query.QueryException;
import org.globus.wsrf.query.QueryEvaluationException;
import org.globus.wsrf.query.InvalidQueryExpressionException;
import org.globus.wsrf.utils.AnyHelper;
import org.globus.wsrf.utils.FaultHelper;
import org.globus.wsrf.utils.Resources;
import org.globus.wsrf.impl.servicegroup.ServiceGroupConstants;
import org.globus.wsrf.impl.properties.QueryResourcePropertiesProvider;
import org.globus.util.I18n;
import org.oasis.wsrf.properties.InvalidQueryExpressionFaultType;
import org.oasis.wsrf.properties.InvalidResourcePropertyQNameFaultType;
import org.oasis.wsrf.properties.QueryEvaluationErrorFaultType;
import org.oasis.wsrf.properties.QueryExpressionType;
import org.oasis.wsrf.properties.ResourceUnknownFaultType;
import org.oasis.wsrf.properties.UnknownQueryExpressionDialectFaultType;
import org.oasis.wsrf.properties.QueryResourceProperties_Element;
import org.oasis.wsrf.properties.QueryResourcePropertiesResponse;
import org.globus.mds.bigindex.impl.database.xml.xindice.XindiceIndexDatabase;
/**
* QueryResourceProperties operation implementation. Directly queries the
* database using XPath when the Entry resource property is queried, otherwise
* falls back to the existing implementation for all other resource properties.
* Since not all Entry resource property data is necessarily stored in-memory,
* what can be returned from this method may be different than what is returned
* from GetResourceProperty directly on the Entry resource property.
*/
public class QueryRPProvider extends QueryResourcePropertiesProvider {
static Log logger =
LogFactory.getLog(QueryRPProvider.class.getName());
private static I18n i18n = I18n.getI18n(Resources.class.getName());
public QueryResourcePropertiesResponse queryResourceProperties(QueryResourceProperties_Element request)
throws RemoteException,
InvalidResourcePropertyQNameFaultType,
ResourceUnknownFaultType,
InvalidQueryExpressionFaultType,
QueryEvaluationErrorFaultType,
UnknownQueryExpressionDialectFaultType {
if (request == null) {
throw new RemoteException(
i18n.getMessage("nullArgument", "request"));
}
BigIndexResource resource = null;
try {
resource =
(BigIndexResource)
ResourceContext.getResourceContext().getResource();
} catch (NoSuchResourceException e) {
ResourceUnknownFaultType fault =
new ResourceUnknownFaultType();
FaultHelper faultHelper = new FaultHelper(fault);
faultHelper.addFaultCause(e);
throw fault;
} catch (Exception e) {
throw new RemoteException(
i18n.getMessage("resourceDisoveryFailed"), e);
}
QueryExpressionType query = request.getQueryExpression();
String queryStr;
try {
queryStr = this.getQueryString(query);
} catch (Exception e) {
throw new RemoteException("Query string parsing error", e);
}
if (this.isDatabaseQuery(queryStr))
{
// get db instance
XindiceIndexDatabase db = resource.getDatabase();
if (db == null) {
throw new RemoteException("Error: database instance is null");
}
List results = null;
try {
results = db.query(queryStr, null);
} catch (Exception e) {
e.printStackTrace();
throw new RemoteException("Query error", e);
}
QueryResourcePropertiesResponse response =
new QueryResourcePropertiesResponse();
AnyHelper.setAny(response, results);
return response;
}
else
{
return super.queryResourceProperties(request);
}
}
private String getQueryString(QueryExpressionType expression)
throws Exception
{
if (expression == null) {
throw new QueryException(i18n.getMessage("noQuery"));
}
if (expression.getDialect() == null) {
throw new QueryException(
i18n.getMessage("nullArgument", "expression.dialect"));
}
String dialect = expression.getDialect().toString();
if (!(dialect.equals(WSRFConstants.XPATH_1_DIALECT))) {
throw new UnsupportedQueryDialectException(
i18n.getMessage("invalidQueryExpressionDialect"));
}
if (expression.getValue() == null ||
expression.getValue().toString().trim().length() == 0) {
throw new InvalidQueryExpressionException(
i18n.getMessage("noQueryString"));
}
String query = expression.getValue().toString().trim();
if (logger.isDebugEnabled()) {
logger.debug("Query: " + query);
}
return query;
}
/*
* This pattern matching is imperfect as it will fail with any potential
* wildcard queries against child elements that may exist in the database,
* but where the parent or ancestor element names(s) of that child are not
* found in the query string.
*
* This limitation exists for backward compatibilty reasons. Moving forward
* we need to implement a separate query dialect in order to automatically
* dereference and search Content from the database.
*
* For now, such wildcarded queries are supported via the service-specific
* query interface implemented in QueryProvider.
*/
private boolean isDatabaseQuery(String query)
{
boolean isDatabaseQuery = false;
if (query.length() == 0) {
return isDatabaseQuery;
}
/*
* TODO: find out which is more efficient: default to search root of
* Entry or start with Content (and specific children)?
*
* Starting with Content will cause less database hits, but will force
* the complete resource document to be serialized more often for
* queries against Entry that don't explicitly include Content or
* one of the other Content child elements listed below.
*
*/
isDatabaseQuery =
(
//(query.indexOf("'Entry'")>-1) ||
//(query.indexOf(":Entry")>-1) ||
//(query.indexOf(ServiceGroupConstants.WSSG_NS)>-1) ||
(query.indexOf("'AggregatorData'")>-1) ||
(query.indexOf(":AggregatorData")>-1) ||
(query.indexOf("'AggregatorConfig'")>-1) ||
(query.indexOf(":AggregatorConfig")>-1) ||
(query.indexOf("'Content'")>-1) ||
(query.indexOf(":Content")>-1)
);
return isDatabaseQuery;
}
}