diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/query/GQL.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/query/GQL.java index 1ad1989..d61e1cf 100644 --- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/query/GQL.java +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/query/GQL.java @@ -26,6 +26,7 @@ import java.util.NoSuchElementException; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; +import javax.jcr.NodeIterator; import javax.jcr.RangeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; @@ -38,9 +39,11 @@ import javax.jcr.nodetype.NodeTypeManager; import javax.jcr.nodetype.PropertyDefinition; import javax.jcr.query.Query; import javax.jcr.query.QueryManager; +import javax.jcr.query.QueryResult; import javax.jcr.query.Row; import javax.jcr.query.RowIterator; +import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter; import org.apache.jackrabbit.commons.iterator.RowIteratorAdapter; import org.apache.jackrabbit.util.ISO9075; import org.apache.jackrabbit.util.Text; @@ -285,10 +288,12 @@ public final class GQL { * @param statement the GQL query. * @param session the session that will execute the query. * @return the result. + * + * @deprecated */ public static RowIterator execute(String statement, Session session) { - return execute(statement, session, null); + return execute(statement, session, null, RowIterator.class); } /** @@ -298,11 +303,13 @@ public final class GQL { * @param session the session that will execute the query. * @param commonPathPrefix a common path prefix for the GQL query. * @return the result. + * + * @deprecated */ public static RowIterator execute(String statement, Session session, String commonPathPrefix) { - return execute(statement, session, commonPathPrefix, null); + return execute(statement, session, commonPathPrefix, RowIterator.class); } /** @@ -313,16 +320,64 @@ public final class GQL { * @param commonPathPrefix a common path prefix for the GQL query. * @param filter an optional filter that may include/exclude result rows. * @return the result. + * + * @deprecated */ public static RowIterator execute(String statement, Session session, String commonPathPrefix, Filter filter) { - GQL query = new GQL(statement, session, commonPathPrefix, filter); - return query.execute(); + return execute(statement, session, commonPathPrefix, filter, RowIterator.class); } /** + * Executes the GQL query and returns the result. + * + * @param statement the GQL query. + * @param session the session that will execute the query. + * @param resultType the desired result type (either RowIterator or QueryResult). + * @return the result. + */ + public static T execute(String statement, + Session session, Class resultType) { + return execute(statement, session, null, resultType); + } + + /** + * Executes the GQL query and returns the result as a row iterator. + * + * @param statement the GQL query. + * @param session the session that will execute the query. + * @param commonPathPrefix a common path prefix for the GQL query. + * @param resultType the desired result type (either RowIterator or QueryResult). + * @return the result. + */ + public static T execute(String statement, + Session session, + String commonPathPrefix, + Class resultType) { + return execute(statement, session, commonPathPrefix, null, resultType); + } + + /** + * Executes the GQL query and returns the result as a row iterator. + * + * @param statement the GQL query. + * @param session the session that will execute the query. + * @param commonPathPrefix a common path prefix for the GQL query. + * @param filter an optional filter that may include/exclude result rows. + * @param resultType the desired result type (either RowIterator or QueryResult). + * @return the result. + */ + public static T execute(String statement, + Session session, + String commonPathPrefix, + Filter filter, Class resultType) { + GQL query = new GQL(statement, session, commonPathPrefix, filter); + return query.execute(resultType); + } + + /** * Parses the given statement and generates callbacks for each * GQL term parsed. * @@ -380,39 +435,64 @@ public final class GQL { //-----------------------------< internal >--------------------------------- /** - * Executes the GQL query and returns the result as a row iterator. + * Executes the GQL query and returns the result as either a row iterator + * or a query result. * + * @param resultType the desired result type * @return the result. */ - private RowIterator execute() { + private T execute(Class resultType) { try { String stmt = translateStatement(); QueryManager qm = session.getWorkspace().getQueryManager(); - RowIterator nodes = qm.createQuery(stmt, Query.XPATH).execute().getRows(); + SkippableQueryResult nodes = new SkippableQueryResultAdapter(qm.createQuery(stmt, Query.XPATH).execute()); if (filter != null) { - nodes = new FilteredRowIterator(nodes); + nodes = new FilteredQueryResult(nodes); } if (offset > 0) { try { nodes.skip(offset); } catch (NoSuchElementException e) { - return RowIteratorAdapter.EMPTY; + return empty(resultType); } } if (numResults == Integer.MAX_VALUE) { - return new RowIterAdapter(nodes, nodes.getSize()); + return getResult(new QueryResultAdapter(nodes), resultType); } + RowIterator rows = nodes.getRows(); List resultRows = new ArrayList(); - while (numResults-- > 0 && nodes.hasNext()) { - resultRows.add(nodes.nextRow()); + while (numResults-- > 0 && rows.hasNext()) { + resultRows.add(rows.nextRow()); } - return new RowIterAdapter(resultRows, resultRows.size()); + return getResult(new QueryResultAdapter(nodes, resultRows, resultRows.size()), resultType); } catch (RepositoryException e) { // in case of error return empty result - return RowIteratorAdapter.EMPTY; + return empty(resultType); } } - + + @SuppressWarnings("unchecked") + private T empty(Class resultType) { + if (resultType == QueryResult.class) { + return (T) EMPTY_QUERY_RESULT; + } else if (resultType == RowIterator.class) { + return (T) RowIterAdapter.EMPTY; + } else { + throw new IllegalArgumentException(String.format("Class %s is not a valid result type for GQL", resultType.getName())); + } + } + + @SuppressWarnings("unchecked") + private T getResult(QueryResult result, Class resultType) throws RepositoryException { + if (resultType == QueryResult.class) { + return (T) result; + } else if (resultType == RowIterator.class) { + return (T) result.getRows(); + } else { + throw new IllegalArgumentException(String.format("Class %s is not a valid result type for GQL", resultType.getName())); + } + } + /** * Translates the GQL query into a XPath statement. * @@ -1291,5 +1371,140 @@ public final class GQL { } } } + + private interface SkippableQueryResult extends QueryResult { + public void skip(long skipNum); + } + + private class SkippableQueryResultAdapter implements SkippableQueryResult { + + private final String[] columnNames; + + private final String[] selectorNames; + + private final RowIterator rows; + + public SkippableQueryResultAdapter(QueryResult result) throws RepositoryException { + this.columnNames = result.getColumnNames(); + this.selectorNames = result.getSelectorNames(); + this.rows = result.getRows(); + } + + public String[] getColumnNames() throws RepositoryException { + return columnNames; + } + + public NodeIterator getNodes() throws RepositoryException { + throw new UnsupportedOperationException("FilteredQueryResult does not support getNodes()"); + } + + public RowIterator getRows() throws RepositoryException { + return rows; + } + + public String[] getSelectorNames() throws RepositoryException { + return selectorNames; + } + + public void skip(long skipNum) { + rows.skip(skipNum); + } + + } + + private class FilteredQueryResult implements SkippableQueryResult { + + private final String[] columnNames; + + private final String[] selectorNames; + + private final RowIterator rows; + + public FilteredQueryResult(QueryResult result) throws RepositoryException { + this.columnNames = result.getColumnNames(); + this.selectorNames = result.getSelectorNames(); + this.rows = new FilteredRowIterator(result.getRows()); + } + + public String[] getColumnNames() throws RepositoryException { + return columnNames; + } + + public NodeIterator getNodes() throws RepositoryException { + throw new UnsupportedOperationException("FilteredQueryResult does not support getNodes()"); + } + + public RowIterator getRows() throws RepositoryException { + return rows; + } + + public String[] getSelectorNames() throws RepositoryException { + return selectorNames; + } + + public void skip(long skipNum) { + rows.skip(skipNum); + } + + } + + private class QueryResultAdapter implements QueryResult { + + private final String[] columnNames; + + private final String[] selectorNames; + + private final RowIterator rows; + + public QueryResultAdapter(QueryResult result) throws RepositoryException { + this.columnNames = result.getColumnNames(); + this.selectorNames = result.getSelectorNames(); + RowIterator resultRows = result.getRows(); + this.rows = new RowIterAdapter(resultRows, resultRows.getSize()); + } + + public QueryResultAdapter(QueryResult result, List resultRows, int size) throws RepositoryException { + this.columnNames = result.getColumnNames(); + this.selectorNames = result.getSelectorNames(); + this.rows = new RowIterAdapter(resultRows, size); + } + + public String[] getColumnNames() throws RepositoryException { + return columnNames; + } + + public RowIterator getRows() throws RepositoryException { + return rows; + } + + public NodeIterator getNodes() throws RepositoryException { + throw new UnsupportedOperationException("QueryResultAdapter does not support getNodes()"); + + } + + public String[] getSelectorNames() throws RepositoryException { + return selectorNames; + } + + } + + private static final QueryResult EMPTY_QUERY_RESULT = new QueryResult() { + + public String[] getSelectorNames() throws RepositoryException { + return new String[0]; + } + + public RowIterator getRows() throws RepositoryException { + return RowIterAdapter.EMPTY; + } + + public NodeIterator getNodes() throws RepositoryException { + return NodeIteratorAdapter.EMPTY; + } + + public String[] getColumnNames() throws RepositoryException { + return new String[0]; + } + }; }