You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2012/02/23 16:34:29 UTC
svn commit: r1292828 [1/3] - in
/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query:
./ index/ qom/ qom/tree/
Author: thomasm
Date: Thu Feb 23 15:34:27 2012
New Revision: 1292828
URL: http://svn.apache.org/viewvc?rev=1292828&view=rev
Log:
Query implementation (WIP)
Added:
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/NamespaceRegistryImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserXPath.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryManagerImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryResultImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RangeIteratorImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowIteratorImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/index/
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/index/Index.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/QueryObjectModelFactoryImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/QueryObjectModelImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/AndImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/BindVariableValueImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/ChildNodeImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/ChildNodeJoinConditionImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/ColumnImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/ComparisonImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/ConstraintImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/DescendantNodeImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/DescendantNodeJoinConditionImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/DynamicOperandImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/EquiJoinConditionImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/FullTextSearchImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/FullTextSearchScoreImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinConditionImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinType.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/LengthImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/LiteralImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/LowerCaseImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/NodeLocalNameImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/NodeNameImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/NotImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/Operator.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/OrImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/Order.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/OrderingImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/PropertyExistenceImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/PropertyValueImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/QOMNode.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/QOMTreeVisitor.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/QOMVisitor.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SameNodeImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SameNodeJoinConditionImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SelectorImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SourceImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/StaticOperandImpl.java
jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/UpperCaseImpl.java
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/NamespaceRegistryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/NamespaceRegistryImpl.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/NamespaceRegistryImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/NamespaceRegistryImpl.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.NamespaceException;
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import org.apache.jackrabbit.query.val.ExceptionFactory;
+import org.apache.jackrabbit.query.val.Val;
+
+/**
+ * The implementation of the corresponding JCR interface.
+ */
+public class NamespaceRegistryImpl implements NamespaceRegistry {
+
+ public static final NamespaceRegistryImpl BUILT_IN = new NamespaceRegistryImpl(null);
+
+ static {
+ NamespaceRegistryImpl registry = BUILT_IN;
+ registry.register(PREFIX_JCR, NAMESPACE_JCR);
+ registry.register(PREFIX_NT, NAMESPACE_NT);
+ registry.register(PREFIX_MIX, NAMESPACE_MIX);
+ registry.register(PREFIX_XML, NAMESPACE_XML);
+ registry.register(PREFIX_EMPTY, NAMESPACE_EMPTY);
+ registry.register("rep", "internal");
+ }
+
+ private final NamespaceRegistryImpl parent;
+ private LinkedHashMap<String, String> prefixToUri = new LinkedHashMap<String, String>();
+ private HashMap<String, String> uriToPrefix = new HashMap<String, String>();
+ private boolean shareMapsWithParent;
+
+ private NamespaceRegistryImpl(NamespaceRegistryImpl parent) {
+ this.parent = parent;
+ if (parent != null) {
+ prefixToUri = parent.prefixToUri;
+ uriToPrefix = parent.uriToPrefix;
+ shareMapsWithParent = true;
+ }
+ }
+
+ public static NamespaceRegistryImpl createLocalInstance() {
+ return new NamespaceRegistryImpl(BUILT_IN);
+ }
+
+ public String nameToString(Val name) {
+ if (name.getType() == Val.TYPE_MULTI_VALUE) {
+ Val[] namePair = name.getArray();
+ String uri = getPrefix(namePair[0].getString());
+ String localName = namePair[1].getString();
+ StringBuilder buff = new StringBuilder(uri.length() + 1 + localName.length());
+ buff.append(uri).append(':').append(localName);
+ return buff.toString();
+ }
+ return name.getString();
+ }
+
+ public Val parseName(String name) {
+ if (name.charAt(0) == '{') {
+ int index = name.indexOf('}');
+ Val namespace = Val.get(name.substring(1, index));
+ Val localName = Val.get(name.substring(index + 1));
+ return Val.get(namespace, localName);
+ }
+ int index = name.indexOf(':');
+ if (index < 0) {
+ return Val.get(name);
+ }
+ String prefix = name.substring(0, index);
+ String ns = getURI(prefix);
+ if (ns == null) {
+ throw ExceptionFactory.illegalArgument("Not URI found for prefix: {0}", prefix);
+ }
+ Val namespace = Val.get(ns);
+ Val localName = Val.get(name.substring(index + 1));
+ return Val.get(namespace, localName);
+ }
+
+ public String getPrefix(String uri) {
+ return uriToPrefix.get(uri);
+ }
+
+ public synchronized String[] getPrefixes() throws RepositoryException {
+ String[] prefixes = new String[prefixToUri.size()];
+ prefixToUri.keySet().toArray(prefixes);
+ return prefixes;
+ }
+
+ public String getURI(String prefix) {
+ return prefixToUri.get(prefix);
+ }
+
+ public synchronized String[] getURIs() throws RepositoryException {
+ String[] uris = new String[uriToPrefix.size()];
+ uriToPrefix.keySet().toArray(uris);
+ return uris;
+ }
+
+ public void registerNamespace(String prefix, String uri) throws NamespaceException,
+ UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {
+ if (parent.prefixToUri.containsKey(prefix) || parent.uriToPrefix.containsKey(uri)) {
+ if (!parent.prefixToUri.get(prefix).equals(uri)) {
+ throw ExceptionFactory.namespace("Can not redefine built-in prefix: {0}", prefix);
+ }
+ } else if (prefix.equalsIgnoreCase("xml")) {
+ throw ExceptionFactory.namespace("Can not (re-)define an xml variant: {0}", prefix);
+ }
+ register(prefix, uri);
+ }
+
+ private synchronized void register(String prefix, String uri) {
+ if (shareMapsWithParent) {
+ prefixToUri = new LinkedHashMap<String, String>(prefixToUri);
+ uriToPrefix = new HashMap<String, String>(uriToPrefix);
+ shareMapsWithParent = false;
+ }
+ prefixToUri.put(prefix, uri);
+ uriToPrefix.put(uri, prefix);
+ }
+
+ public synchronized void unregisterNamespace(String prefix) throws NamespaceException, UnsupportedRepositoryOperationException,
+ AccessDeniedException, RepositoryException {
+ if (parent.prefixToUri.containsKey(prefix)) {
+ throw ExceptionFactory.namespace("Can not unregister a built-in prefix: {0}", prefix);
+ }
+ if (!prefixToUri.containsKey(prefix)) {
+ throw ExceptionFactory.namespace("Not registered: {0}", prefix);
+ }
+ String uri = prefixToUri.remove(prefix);
+ uriToPrefix.remove(uri);
+ }
+
+ public String toString() {
+ StringBuilder buff = new StringBuilder();
+ for (Entry<String, String> e : prefixToUri.entrySet()) {
+ buff.append('<').append(e.getKey()).append('=').append(e.getValue()).append('>');
+ }
+ return buff.toString();
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,1002 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.qom.BindVariableValue;
+import javax.jcr.query.qom.Column;
+import javax.jcr.query.qom.Constraint;
+import javax.jcr.query.qom.DynamicOperand;
+import javax.jcr.query.qom.JoinCondition;
+import javax.jcr.query.qom.Literal;
+import javax.jcr.query.qom.Ordering;
+import javax.jcr.query.qom.PropertyExistence;
+import javax.jcr.query.qom.PropertyValue;
+import javax.jcr.query.qom.QueryObjectModel;
+import javax.jcr.query.qom.QueryObjectModelConstants;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+import javax.jcr.query.qom.Selector;
+import javax.jcr.query.qom.Source;
+import javax.jcr.query.qom.StaticOperand;
+import org.apache.jackrabbit.query.val.ExceptionFactory;
+
+/**
+ * The SQL2 parser can convert a JCR-SQL2 query to a QueryObjectModel.
+ */
+public class ParserSQL2 {
+
+ // Character types, used during the tokenizer phase
+ private static final int CHAR_END = -1, CHAR_VALUE = 2, CHAR_QUOTED = 3;
+ private static final int CHAR_NAME = 4, CHAR_SPECIAL_1 = 5, CHAR_SPECIAL_2 = 6;
+ private static final int CHAR_STRING = 7, CHAR_DECIMAL = 8;
+
+ // Token types
+ private static final int KEYWORD = 1, IDENTIFIER = 2, PARAMETER = 3, END = 4, VALUE = 5;
+ private static final int MINUS = 12, PLUS = 13, OPEN = 14, CLOSE = 15;
+
+ // The query as an array of characters and character types
+ private String statement;
+ private char[] statementChars;
+ private int[] characterTypes;
+
+ // The current state of the parser
+ private int parseIndex;
+ private int currentTokenType;
+ private String currentToken;
+ private boolean currentTokenQuoted;
+ private Value currentValue;
+ private ArrayList<String> expected;
+
+ // The bind variables
+ private HashMap<String, BindVariableValue> bindVariables;
+
+ // The list of selectors of this query
+ private ArrayList<Selector> selectors;
+
+ // SQL injection protection: if disabled, literals are not allowed
+ private boolean allowTextLiterals = true, allowNumberLiterals = true;
+
+ private QueryObjectModelFactory factory;
+ private ValueFactory valueFactory;
+
+ /**
+ * Create a new parser. A parser can be re-used, but it is not thread safe.
+ *
+ * @param factory the query object model factory
+ * @param valueFactory the value factory
+ */
+ public ParserSQL2(QueryObjectModelFactory factory, ValueFactory valueFactory) {
+ this.factory = factory;
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Parse a JCR-SQL2 query and return the query object model
+ *
+ * @param query the query string
+ * @return the query object model
+ * @throws RepositoryException if parsing failed
+ */
+ public QueryObjectModel createQueryObjectModel(String query) throws RepositoryException {
+ initialize(query);
+ selectors = new ArrayList<Selector>();
+ expected = new ArrayList<String>();
+ bindVariables = new HashMap<String, BindVariableValue>();
+ read();
+ read("SELECT");
+ ArrayList<ColumnOrWildcard> list = parseColumns();
+ read("FROM");
+ Source source = parseSource();
+ Column[] columnArray = resolveColumns(list);
+ Constraint constraint = null;
+ if (readIf("WHERE")) {
+ constraint = parseConstraint();
+ }
+ Ordering[] orderings = null;
+ if (readIf("ORDER")) {
+ read("BY");
+ orderings = parseOrder();
+ }
+ if (currentToken.length() > 0) {
+ throw getSyntaxError("<end>");
+ }
+ return factory.createQuery(source, constraint, orderings, columnArray);
+ }
+
+ private Selector parseSelector() throws RepositoryException {
+ String nodeTypeName = readName();
+ if (readIf("AS")) {
+ String selectorName = readName();
+ return factory.selector(nodeTypeName, selectorName);
+ } else {
+ return factory.selector(nodeTypeName, nodeTypeName);
+ }
+ }
+
+ private String readName() throws RepositoryException {
+ if (readIf("[")) {
+ if (currentTokenType == VALUE) {
+ Value value = readString();
+ read("]");
+ return value.getString();
+ } else {
+ int level = 1;
+ StringBuilder buff = new StringBuilder();
+ while (true) {
+ if (isToken("]")) {
+ if (--level <= 0) {
+ read();
+ break;
+ }
+ } else if (isToken("[")) {
+ level++;
+ }
+ buff.append(readAny());
+ }
+ return buff.toString();
+ }
+ } else {
+ return readAny();
+ }
+ }
+
+ private Source parseSource() throws RepositoryException {
+ Selector selector = parseSelector();
+ selectors.add(selector);
+ Source source = selector;
+ while (true) {
+ String joinType;
+ if (readIf("RIGHT")) {
+ read("OUTER");
+ joinType = QueryObjectModelConstants.JCR_JOIN_TYPE_RIGHT_OUTER;
+ } else if (readIf("LEFT")) {
+ read("OUTER");
+ joinType = QueryObjectModelConstants.JCR_JOIN_TYPE_LEFT_OUTER;
+ } else if (readIf("INNER")) {
+ joinType = QueryObjectModelConstants.JCR_JOIN_TYPE_INNER;
+ } else {
+ break;
+ }
+ read("JOIN");
+ selector = parseSelector();
+ selectors.add(selector);
+ read("ON");
+ JoinCondition on = parseJoinCondition();
+ source = factory.join(source, selector, joinType, on);
+ }
+ return source;
+ }
+
+ private JoinCondition parseJoinCondition() throws RepositoryException {
+ boolean identifier = currentTokenType == IDENTIFIER;
+ String name = readName();
+ JoinCondition c;
+ if (identifier && readIf("(")) {
+ if ("ISSAMENODE".equalsIgnoreCase(name)) {
+ String selector1 = readName();
+ read(",");
+ String selector2 = readName();
+ if (readIf(",")) {
+ c = factory.sameNodeJoinCondition(selector1, selector2, readPath());
+ } else {
+ // TODO verify "." is correct
+ c = factory.sameNodeJoinCondition(selector1, selector2, ".");
+ }
+ } else if ("ISCHILDNODE".equalsIgnoreCase(name)) {
+ String childSelector = readName();
+ read(",");
+ c = factory.childNodeJoinCondition(childSelector, readName());
+ } else if ("ISDESCENDANTNODE".equalsIgnoreCase(name)) {
+ String descendantSelector = readName();
+ read(",");
+ c = factory.descendantNodeJoinCondition(descendantSelector, readName());
+ } else {
+ throw getSyntaxError("ISSAMENODE, ISCHILDNODE, or ISDESCENDANTNODE");
+ }
+ read(")");
+ return c;
+ } else {
+ String selector1 = name;
+ read(".");
+ String property1 = readName();
+ read("=");
+ String selector2 = readName();
+ read(".");
+ return factory.equiJoinCondition(selector1, property1, selector2, readName());
+ }
+ }
+
+ private Constraint parseConstraint() throws RepositoryException {
+ Constraint a = parseAnd();
+ while (readIf("OR")) {
+ a = factory.or(a, parseAnd());
+ }
+ return a;
+ }
+
+ private Constraint parseAnd() throws RepositoryException {
+ Constraint a = parseCondition();
+ while (readIf("AND")) {
+ a = factory.and(a, parseCondition());
+ }
+ return a;
+ }
+
+ private Constraint parseCondition() throws RepositoryException {
+ Constraint a;
+ if (readIf("NOT")) {
+ a = factory.not(parseConstraint());
+ } else if (readIf("(")) {
+ a = parseConstraint();
+ read(")");
+ } else if (currentTokenType == IDENTIFIER) {
+ String identifier = readName();
+ if (readIf("(")) {
+ a = parseConditionFuntionIf(identifier);
+ if (a == null) {
+ DynamicOperand op = parseExpressionFunction(identifier);
+ a = parseCondition(op);
+ }
+ } else if (readIf(".")) {
+ a = parseCondition(factory.propertyValue(identifier, readName()));
+ } else {
+ a = parseCondition(factory.propertyValue(getOnlySelectorName(), identifier));
+ }
+ } else if ("[".equals(currentToken)) {
+ String name = readName();
+ if (readIf(".")) {
+ a = parseCondition(factory.propertyValue(name, readName()));
+ } else {
+ a = parseCondition(factory.propertyValue(getOnlySelectorName(), name));
+ }
+ } else {
+ throw getSyntaxError();
+ }
+ return a;
+ }
+
+ private Constraint parseCondition(DynamicOperand left) throws RepositoryException {
+ Constraint c;
+
+ if (readIf("=")) {
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ } else if (readIf("<>")) {
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_NOT_EQUAL_TO;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ } else if (readIf("<")) {
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ } else if (readIf(">")) {
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ } else if (readIf("<=")) {
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ } else if (readIf(">=")) {
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ } else if (readIf("LIKE")) {
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_LIKE;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ } else if (readIf("IS")) {
+ boolean not = readIf("NOT");
+ read("NULL");
+ if (!(left instanceof PropertyValue)) {
+ throw getSyntaxError("propertyName (NOT NULL is only supported for properties)");
+ }
+ PropertyValue p = (PropertyValue) left;
+ c = getPropertyExistence(p);
+ if (!not) {
+ c = factory.not(c);
+ }
+ } else if (readIf("NOT")) {
+ if (readIf("IS")) {
+ read("NULL");
+ if (!(left instanceof PropertyValue)) {
+ throw ExceptionFactory.repository(
+ "Only property values can be tested for NOT IS NULL; got: "
+ + left.getClass().getName());
+ }
+ PropertyValue pv = (PropertyValue) left;
+ c = getPropertyExistence(pv);
+ } else {
+ read("LIKE");
+ String operator = QueryObjectModelConstants.JCR_OPERATOR_LIKE;
+ c = factory.comparison(left, operator, parseStaticOperand());
+ c = factory.not(c);
+ }
+ } else {
+ throw getSyntaxError();
+ }
+ return c;
+ }
+
+ private PropertyExistence getPropertyExistence(PropertyValue p) throws InvalidQueryException, RepositoryException {
+ return factory.propertyExistence(p.getSelectorName(), p.getPropertyName());
+ }
+
+ private Constraint parseConditionFuntionIf(String functionName) throws RepositoryException {
+ Constraint c;
+ if ("CONTAINS".equalsIgnoreCase(functionName)) {
+ String name = readName();
+ if (readIf(".")) {
+ if (readIf("*")) {
+ read(",");
+ c = factory.fullTextSearch(
+ name, null, parseStaticOperand());
+ } else {
+ String selector = name;
+ name = readName();
+ read(",");
+ c = factory.fullTextSearch(
+ selector, name, parseStaticOperand());
+ }
+ } else {
+ read(",");
+ c = factory.fullTextSearch(
+ getOnlySelectorName(), name,
+ parseStaticOperand());
+ }
+ } else if ("ISSAMENODE".equalsIgnoreCase(functionName)) {
+ String name = readName();
+ if (readIf(",")) {
+ c = factory.sameNode(name, readPath());
+ } else {
+ c = factory.sameNode(getOnlySelectorName(), name);
+ }
+ } else if ("ISCHILDNODE".equalsIgnoreCase(functionName)) {
+ String name = readName();
+ if (readIf(",")) {
+ c = factory.childNode(name, readPath());
+ } else {
+ c = factory.childNode(getOnlySelectorName(), name);
+ }
+ } else if ("ISDESCENDANTNODE".equalsIgnoreCase(functionName)) {
+ String name = readName();
+ if (readIf(",")) {
+ c = factory.descendantNode(name, readPath());
+ } else {
+ c = factory.descendantNode(getOnlySelectorName(), name);
+ }
+ } else {
+ return null;
+ }
+ read(")");
+ return c;
+ }
+
+ private String readPath() throws RepositoryException {
+ return readName();
+ }
+
+ private DynamicOperand parseDynamicOperand() throws RepositoryException {
+ boolean identifier = currentTokenType == IDENTIFIER;
+ String name = readName();
+ if (identifier && readIf("(")) {
+ return parseExpressionFunction(name);
+ } else {
+ return parsePropertyValue(name);
+ }
+ }
+
+ private DynamicOperand parseExpressionFunction(String functionName) throws RepositoryException {
+ DynamicOperand op;
+ if ("LENGTH".equalsIgnoreCase(functionName)) {
+ op = factory.length(parsePropertyValue(readName()));
+ } else if ("NAME".equalsIgnoreCase(functionName)) {
+ if (isToken(")")) {
+ op = factory.nodeName(getOnlySelectorName());
+ } else {
+ op = factory.nodeName(readName());
+ }
+ } else if ("LOCALNAME".equalsIgnoreCase(functionName)) {
+ if (isToken(")")) {
+ op = factory.nodeLocalName(getOnlySelectorName());
+ } else {
+ op = factory.nodeLocalName(readName());
+ }
+ } else if ("SCORE".equalsIgnoreCase(functionName)) {
+ if (isToken(")")) {
+ op = factory.fullTextSearchScore(getOnlySelectorName());
+ } else {
+ op = factory.fullTextSearchScore(readName());
+ }
+ } else if ("LOWER".equalsIgnoreCase(functionName)) {
+ op = factory.lowerCase(parseDynamicOperand());
+ } else if ("UPPER".equalsIgnoreCase(functionName)) {
+ op = factory.upperCase(parseDynamicOperand());
+ } else {
+ throw getSyntaxError("LENGTH, NAME, LOCALNAME, SCORE, LOWER, UPPER, or CAST");
+ }
+ read(")");
+ return op;
+ }
+
+ private PropertyValue parsePropertyValue(String name) throws RepositoryException {
+ if (readIf(".")) {
+ return factory.propertyValue(name, readName());
+ } else {
+ return factory.propertyValue(getOnlySelectorName(), name);
+ }
+ }
+
+ private StaticOperand parseStaticOperand() throws RepositoryException {
+ if (currentTokenType == PLUS) {
+ read();
+ } else if (currentTokenType == MINUS) {
+ read();
+ if (currentTokenType != VALUE) {
+ throw getSyntaxError("number");
+ }
+ int valueType = currentValue.getType();
+ switch (valueType) {
+ case PropertyType.LONG:
+ currentValue = valueFactory.createValue(-currentValue.getLong());
+ break;
+ case PropertyType.DOUBLE:
+ currentValue = valueFactory.createValue(-currentValue.getDouble());
+ break;
+ case PropertyType.BOOLEAN:
+ currentValue = valueFactory.createValue(!currentValue.getBoolean());
+ break;
+ case PropertyType.DECIMAL:
+ currentValue = valueFactory.createValue(currentValue.getDecimal().negate());
+ break;
+ default:
+ throw getSyntaxError("Illegal operation: -" + currentValue);
+ }
+ }
+ if (currentTokenType == VALUE) {
+ Literal literal = getUncastLiteral(currentValue);
+ read();
+ return literal;
+ } else if (currentTokenType == PARAMETER) {
+ read();
+ String name = readName();
+ if (readIf(":")) {
+ name = name + ":" + readName();
+ }
+ BindVariableValue var = bindVariables.get(name);
+ if (var == null) {
+ var = factory.bindVariable(name);
+ bindVariables.put(name, var);
+ }
+ return var;
+ } else if (readIf("TRUE")) {
+ Literal literal = getUncastLiteral(valueFactory.createValue(true));
+ return literal;
+ } else if (readIf("FALSE")) {
+ Literal literal = getUncastLiteral(valueFactory.createValue(false));
+ return literal;
+ } else if (readIf("CAST")) {
+ read("(");
+ StaticOperand op = parseStaticOperand();
+ if (!(op instanceof Literal)) {
+ throw getSyntaxError("literal");
+ }
+ Literal literal = (Literal) op;
+ Value value = literal.getLiteralValue();
+ read("AS");
+ value = parseCastAs(value);
+ read(")");
+ // CastLiteral
+ literal = factory.literal(value);
+ return literal;
+ } else {
+ throw getSyntaxError("static operand");
+ }
+ }
+
+ /**
+ * Create a literal from a parsed value.
+ *
+ * @param value the original value
+ * @return the literal
+ */
+ private Literal getUncastLiteral(Value value) throws RepositoryException {
+ return factory.literal(value);
+ }
+
+ private Value parseCastAs(Value value) throws RepositoryException {
+ if (readIf("STRING")) {
+ return valueFactory.createValue(value.getString());
+ } else if (readIf("BINARY")) {
+ return valueFactory.createValue(value.getBinary());
+ } else if (readIf("DATE")) {
+ return valueFactory.createValue(value.getDate());
+ } else if (readIf("LONG")) {
+ return valueFactory.createValue(value.getLong());
+ } else if (readIf("DOUBLE")) {
+ return valueFactory.createValue(value.getDouble());
+ } else if (readIf("DECIMAL")) {
+ return valueFactory.createValue(value.getDecimal());
+ } else if (readIf("BOOLEAN")) {
+ return valueFactory.createValue(value.getBoolean());
+ } else if (readIf("NAME")) {
+ return valueFactory.createValue(value.getString(), PropertyType.NAME);
+ } else if (readIf("PATH")) {
+ return valueFactory.createValue(value.getString(), PropertyType.PATH);
+ } else if (readIf("REFERENCE")) {
+ return valueFactory.createValue(value.getString(), PropertyType.REFERENCE);
+ } else if (readIf("WEAKREFERENCE")) {
+ return valueFactory.createValue(value.getString(), PropertyType.WEAKREFERENCE);
+ } else if (readIf("URI")) {
+ return valueFactory.createValue(value.getString(), PropertyType.URI);
+ } else {
+ throw getSyntaxError("data type (STRING|BINARY|...)");
+ }
+ }
+
+ private Ordering[] parseOrder() throws RepositoryException {
+ ArrayList<Ordering> orderList = new ArrayList<Ordering>();
+ do {
+ Ordering ordering;
+ DynamicOperand op = parseDynamicOperand();
+ if (readIf("DESC")) {
+ ordering = factory.descending(op);
+ } else {
+ readIf("ASC");
+ ordering = factory.ascending(op);
+ }
+ orderList.add(ordering);
+ } while (readIf(","));
+ Ordering[] orderings = new Ordering[orderList.size()];
+ orderList.toArray(orderings);
+ return orderings;
+ }
+
+ private ArrayList<ColumnOrWildcard> parseColumns() throws RepositoryException {
+ ArrayList<ColumnOrWildcard> list = new ArrayList<ColumnOrWildcard>();
+ if (readIf("*")) {
+ list.add(new ColumnOrWildcard());
+ } else {
+ do {
+ ColumnOrWildcard column = new ColumnOrWildcard();
+ column.propertyName = readName();
+ if (readIf(".")) {
+ column.selectorName = column.propertyName;
+ if (readIf("*")) {
+ column.propertyName = null;
+ } else {
+ column.propertyName = readName();
+ if (readIf("AS")) {
+ column.columnName = readName();
+ }
+ }
+ } else {
+ if (readIf("AS")) {
+ column.columnName = readName();
+ }
+ }
+ list.add(column);
+ } while (readIf(","));
+ }
+ return list;
+ }
+
+ private Column[] resolveColumns(ArrayList<ColumnOrWildcard> list) throws RepositoryException {
+ ArrayList<Column> columns = new ArrayList<Column>();
+ for (ColumnOrWildcard c : list) {
+ if (c.propertyName == null) {
+ for (Selector selector : selectors) {
+ if (c.selectorName == null
+ || c.selectorName
+ .equals(selector.getSelectorName())) {
+ Column column = factory.column(selector
+ .getSelectorName(), null, null);
+ columns.add(column);
+ }
+ }
+ } else {
+ Column column;
+ if (c.selectorName != null) {
+ column = factory.column(c.selectorName, c.propertyName, c.columnName);
+ } else if (c.columnName != null) {
+ column = factory.column(getOnlySelectorName(), c.propertyName, c.columnName);
+ } else {
+ column = factory.column(getOnlySelectorName(), c.propertyName, c.propertyName);
+ }
+ columns.add(column);
+ }
+ }
+ Column[] array = new Column[columns.size()];
+ columns.toArray(array);
+ return array;
+ }
+
+ private boolean readIf(String token) throws RepositoryException {
+ if (isToken(token)) {
+ read();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isToken(String token) {
+ boolean result = token.equalsIgnoreCase(currentToken) && !currentTokenQuoted;
+ if (result) {
+ return true;
+ }
+ addExpected(token);
+ return false;
+ }
+
+ private void read(String expected) throws RepositoryException {
+ if (!expected.equalsIgnoreCase(currentToken) || currentTokenQuoted) {
+ throw getSyntaxError(expected);
+ }
+ read();
+ }
+
+ private String readAny() throws RepositoryException {
+ if (currentTokenType == END) {
+ throw getSyntaxError("a token");
+ }
+ String s;
+ if (currentTokenType == VALUE) {
+ s = currentValue.getString();
+ } else {
+ s = currentToken;
+ }
+ read();
+ return s;
+ }
+
+ private Value readString() throws RepositoryException {
+ if (currentTokenType != VALUE) {
+ throw getSyntaxError("string value");
+ }
+ Value value = currentValue;
+ read();
+ return value;
+ }
+
+ private void addExpected(String token) {
+ if (expected != null) {
+ expected.add(token);
+ }
+ }
+
+ private void initialize(String query) throws InvalidQueryException {
+ if (query == null) {
+ query = "";
+ }
+ statement = query;
+ int len = query.length() + 1;
+ char[] command = new char[len];
+ int[] types = new int[len];
+ len--;
+ query.getChars(0, len, command, 0);
+ command[len] = ' ';
+ int startLoop = 0;
+ for (int i = 0; i < len; i++) {
+ char c = command[i];
+ int type = 0;
+ switch (c) {
+ case '/':
+ case '-':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '*':
+ case ',':
+ case ';':
+ case '+':
+ case '%':
+ case '?':
+ case '$':
+ case '[':
+ case ']':
+ type = CHAR_SPECIAL_1;
+ break;
+ case '!':
+ case '<':
+ case '>':
+ case '|':
+ case '=':
+ case ':':
+ type = CHAR_SPECIAL_2;
+ break;
+ case '.':
+ type = CHAR_DECIMAL;
+ break;
+ case '\'':
+ type = CHAR_STRING;
+ types[i] = CHAR_STRING;
+ startLoop = i;
+ while (command[++i] != '\'') {
+ checkRunOver(i, len, startLoop);
+ }
+ break;
+ case '\"':
+ type = CHAR_QUOTED;
+ types[i] = CHAR_QUOTED;
+ startLoop = i;
+ while (command[++i] != '\"') {
+ checkRunOver(i, len, startLoop);
+ }
+ break;
+ case '_':
+ type = CHAR_NAME;
+ break;
+ default:
+ if (c >= 'a' && c <= 'z') {
+ type = CHAR_NAME;
+ } else if (c >= 'A' && c <= 'Z') {
+ type = CHAR_NAME;
+ } else if (c >= '0' && c <= '9') {
+ type = CHAR_VALUE;
+ } else {
+ if (Character.isJavaIdentifierPart(c)) {
+ type = CHAR_NAME;
+ }
+ }
+ }
+ types[i] = (byte) type;
+ }
+ statementChars = command;
+ types[len] = CHAR_END;
+ characterTypes = types;
+ parseIndex = 0;
+ }
+
+ private void checkRunOver(int i, int len, int startLoop) throws InvalidQueryException {
+ if (i >= len) {
+ parseIndex = startLoop;
+ throw getSyntaxError();
+ }
+ }
+
+ private void read() throws RepositoryException {
+ currentTokenQuoted = false;
+ if (expected != null) {
+ expected.clear();
+ }
+ int[] types = characterTypes;
+ int i = parseIndex;
+ int type = types[i];
+ while (type == 0) {
+ type = types[++i];
+ }
+ int start = i;
+ char[] chars = statementChars;
+ char c = chars[i++];
+ currentToken = "";
+ switch (type) {
+ case CHAR_NAME:
+ while (true) {
+ type = types[i];
+ if (type != CHAR_NAME && type != CHAR_VALUE) {
+ c = chars[i];
+ break;
+ }
+ i++;
+ }
+ currentToken = statement.substring(start, i);
+ if (currentToken.length() == 0) {
+ throw getSyntaxError();
+ }
+ currentTokenType = IDENTIFIER;
+ parseIndex = i;
+ return;
+ case CHAR_SPECIAL_2:
+ if (types[i] == CHAR_SPECIAL_2) {
+ i++;
+ }
+ // fall through
+ case CHAR_SPECIAL_1:
+ currentToken = statement.substring(start, i);
+ switch (c) {
+ case '$':
+ currentTokenType = PARAMETER;
+ break;
+ case '+':
+ currentTokenType = PLUS;
+ break;
+ case '-':
+ currentTokenType = MINUS;
+ break;
+ case '(':
+ currentTokenType = OPEN;
+ break;
+ case ')':
+ currentTokenType = CLOSE;
+ break;
+ default:
+ currentTokenType = KEYWORD;
+ }
+ parseIndex = i;
+ return;
+ case CHAR_VALUE:
+ long number = c - '0';
+ while (true) {
+ c = chars[i];
+ if (c < '0' || c > '9') {
+ if (c == '.') {
+ readDecimal(start, i);
+ break;
+ }
+ if (c == 'E' || c == 'e') {
+ readDecimal(start, i);
+ break;
+ }
+ checkLiterals(false);
+ currentValue = valueFactory.createValue(number);
+ currentTokenType = VALUE;
+ currentToken = "0";
+ parseIndex = i;
+ break;
+ }
+ number = number * 10 + (c - '0');
+ if (number > Integer.MAX_VALUE) {
+ readDecimal(start, i);
+ break;
+ }
+ i++;
+ }
+ return;
+ case CHAR_DECIMAL:
+ if (types[i] != CHAR_VALUE) {
+ currentTokenType = KEYWORD;
+ currentToken = ".";
+ parseIndex = i;
+ return;
+ }
+ readDecimal(i - 1, i);
+ return;
+ case CHAR_STRING:
+ readString(i, '\'');
+ return;
+ case CHAR_QUOTED:
+ readString(i, '\"');
+ return;
+ case CHAR_END:
+ currentToken = "";
+ currentTokenType = END;
+ parseIndex = i;
+ return;
+ default:
+ throw getSyntaxError();
+ }
+ }
+
+ private void readString(int i, char end) throws RepositoryException {
+ char[] chars = statementChars;
+ String result = null;
+ while (true) {
+ for (int begin = i;; i++) {
+ if (chars[i] == end) {
+ if (result == null) {
+ result = statement.substring(begin, i);
+ } else {
+ result += statement.substring(begin - 1, i);
+ }
+ break;
+ }
+ }
+ if (chars[++i] != end) {
+ break;
+ }
+ i++;
+ }
+ currentToken = "'";
+ checkLiterals(false);
+ currentValue = valueFactory.createValue(result);
+ parseIndex = i;
+ currentTokenType = VALUE;
+ }
+
+ private void checkLiterals(boolean text) throws InvalidQueryException {
+ if (text && !allowTextLiterals || (!text && !allowNumberLiterals)) {
+ throw getSyntaxError("bind variable (literals of this type not allowed)");
+ }
+ }
+
+ private void readDecimal(int start, int i) throws RepositoryException {
+ char[] chars = statementChars;
+ int[] types = characterTypes;
+ while (true) {
+ int t = types[i];
+ if (t != CHAR_DECIMAL && t != CHAR_VALUE) {
+ break;
+ }
+ i++;
+ }
+ if (chars[i] == 'E' || chars[i] == 'e') {
+ i++;
+ if (chars[i] == '+' || chars[i] == '-') {
+ i++;
+ }
+ if (types[i] != CHAR_VALUE) {
+ throw getSyntaxError();
+ }
+ while (types[++i] == CHAR_VALUE) {
+ // go until the first non-number
+ }
+ }
+ parseIndex = i;
+ String sub = statement.substring(start, i);
+ BigDecimal bd;
+ try {
+ bd = new BigDecimal(sub);
+ } catch (NumberFormatException e) {
+ throw ExceptionFactory.invalidQuery("Data conversion error converting " + sub + " to BigDecimal: " + e);
+ }
+ checkLiterals(false);
+
+ currentValue = valueFactory.createValue(bd);
+ currentTokenType = VALUE;
+ }
+
+ private InvalidQueryException getSyntaxError() {
+ if (expected == null || expected.size() == 0) {
+ return getSyntaxError(null);
+ } else {
+ StringBuilder buff = new StringBuilder();
+ for (String exp : expected) {
+ if (buff.length() > 0) {
+ buff.append(", ");
+ }
+ buff.append(exp);
+ }
+ return getSyntaxError(buff.toString());
+ }
+ }
+
+ private InvalidQueryException getSyntaxError(String expected) {
+ int index = Math.min(parseIndex, statement.length() - 1);
+ String query = statement.substring(0, index) + "(*)" + statement.substring(index).trim();
+ if (expected != null) {
+ query += "; expected: " + expected;
+ }
+ return new InvalidQueryException("Query:\n" + query);
+ }
+
+ /**
+ * Represents a column or a wildcard in a SQL expression.
+ * This class is temporarily used during parsing.
+ */
+ static class ColumnOrWildcard {
+ String selectorName;
+ String propertyName;
+ String columnName;
+ }
+
+ /**
+ * Get the selector name if only one selector exists in the query.
+ * If more than one selector exists, an exception is thrown.
+ *
+ * @return the selector name
+ */
+ private String getOnlySelectorName() throws RepositoryException {
+ if (selectors.size() > 1) {
+ throw getSyntaxError("Need to specify the selector name because the query contains more than one selector.");
+ }
+ return selectors.get(0).getSelectorName();
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserXPath.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserXPath.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserXPath.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserXPath.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,458 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.qom.BindVariableValue;
+import javax.jcr.query.qom.Column;
+import javax.jcr.query.qom.Constraint;
+import javax.jcr.query.qom.Ordering;
+import javax.jcr.query.qom.QueryObjectModel;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+import javax.jcr.query.qom.Selector;
+import javax.jcr.query.qom.Source;
+import org.apache.jackrabbit.query.ParserSQL2.ColumnOrWildcard;
+import org.apache.jackrabbit.query.qom.QueryObjectModelFactoryImpl;
+import org.apache.jackrabbit.query.val.ExceptionFactory;
+import org.apache.jackrabbit.query.val.ValueFactoryImpl;
+
+
+/**
+ * The XPath parser can convert a XPATH query to a QueryObjectModel.
+ */
+public class ParserXPath {
+
+ // Character types, used during the tokenizer phase
+ private static final int CHAR_END = -1, CHAR_VALUE = 2, CHAR_QUOTED = 3;
+ private static final int CHAR_NAME = 4, CHAR_SPECIAL_1 = 5, CHAR_SPECIAL_2 = 6;
+ private static final int CHAR_STRING = 7, CHAR_DECIMAL = 8;
+
+ // Token types
+ private static final int KEYWORD = 1, IDENTIFIER = 2, PARAMETER = 3, END = 4, VALUE = 5;
+ private static final int MINUS = 12, PLUS = 13, OPEN = 14, CLOSE = 15;
+
+ // The query as an array of characters and character types
+ private String statement;
+ private char[] statementChars;
+ private int[] characterTypes;
+
+ // The current state of the parser
+ private int parseIndex;
+ private int currentTokenType;
+ private String currentToken;
+ private boolean currentTokenQuoted;
+ private Value currentValue;
+ private ArrayList<String> expected;
+
+ // Code injection protection: if disabled, literals are not allowed
+ private boolean allowTextLiterals = true, allowNumberLiterals = true;
+
+ private QueryObjectModelFactory factory;
+ private ValueFactory valueFactory;
+
+ /**
+ * Create a new parser. A parser can be re-used, but it is not thread safe.
+ *
+ * @param factory the query object model factory
+ * @param valueFactory the value factory
+ */
+ public ParserXPath(QueryObjectModelFactory factory, ValueFactory valueFactory) {
+ this.factory = factory;
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Parse a JCR-SQL2 query and return the query object model
+ *
+ * @param query the query string
+ * @return the query object model
+ * @throws RepositoryException if parsing failed
+ */
+ public QueryObjectModel createQueryObjectModel(String query) throws RepositoryException {
+ initialize(query);
+ expected = new ArrayList<String>();
+ read();
+ if (readIf("//")) {
+ System.out.println("any child node");
+ } else if (readIf("/")) {
+ System.out.println("any node: " + readString());
+ }
+ if (currentToken.length() > 0) {
+ throw getSyntaxError("<end>");
+ }
+ return null;
+ // return factory.createQuery(source, constraint, orderings, columnArray);
+ }
+
+ private boolean readIf(String token) throws RepositoryException {
+ if (isToken(token)) {
+ read();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isToken(String token) {
+ boolean result = token.equalsIgnoreCase(currentToken) && !currentTokenQuoted;
+ if (result) {
+ return true;
+ }
+ addExpected(token);
+ return false;
+ }
+
+ private void read(String expected) throws RepositoryException {
+ if (!expected.equalsIgnoreCase(currentToken) || currentTokenQuoted) {
+ throw getSyntaxError(expected);
+ }
+ read();
+ }
+
+ private String readAny() throws RepositoryException {
+ if (currentTokenType == END) {
+ throw getSyntaxError("a token");
+ }
+ String s;
+ if (currentTokenType == VALUE) {
+ s = currentValue.getString();
+ } else {
+ s = currentToken;
+ }
+ read();
+ return s;
+ }
+
+ private Value readString() throws RepositoryException {
+ if (currentTokenType != VALUE) {
+ throw getSyntaxError("string value");
+ }
+ Value value = currentValue;
+ read();
+ return value;
+ }
+
+ private void addExpected(String token) {
+ if (expected != null) {
+ expected.add(token);
+ }
+ }
+
+ private void initialize(String query) throws InvalidQueryException {
+ if (query == null) {
+ query = "";
+ }
+ statement = query;
+ int len = query.length() + 1;
+ char[] command = new char[len];
+ int[] types = new int[len];
+ len--;
+ query.getChars(0, len, command, 0);
+ command[len] = ' ';
+ int startLoop = 0;
+ for (int i = 0; i < len; i++) {
+ char c = command[i];
+ int type = 0;
+ switch (c) {
+ case '/':
+ case '-':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '*':
+ case ',':
+ case ';':
+ case '+':
+ case '%':
+ case '?':
+ case '$':
+ case '[':
+ case ']':
+ type = CHAR_SPECIAL_1;
+ break;
+ case '!':
+ case '<':
+ case '>':
+ case '|':
+ case '=':
+ case ':':
+ type = CHAR_SPECIAL_2;
+ break;
+ case '.':
+ type = CHAR_DECIMAL;
+ break;
+ case '\'':
+ type = CHAR_STRING;
+ types[i] = CHAR_STRING;
+ startLoop = i;
+ while (command[++i] != '\'') {
+ checkRunOver(i, len, startLoop);
+ }
+ break;
+ case '\"':
+ type = CHAR_QUOTED;
+ types[i] = CHAR_QUOTED;
+ startLoop = i;
+ while (command[++i] != '\"') {
+ checkRunOver(i, len, startLoop);
+ }
+ break;
+ case '_':
+ type = CHAR_NAME;
+ break;
+ default:
+ if (c >= 'a' && c <= 'z') {
+ type = CHAR_NAME;
+ } else if (c >= 'A' && c <= 'Z') {
+ type = CHAR_NAME;
+ } else if (c >= '0' && c <= '9') {
+ type = CHAR_VALUE;
+ } else {
+ if (Character.isJavaIdentifierPart(c)) {
+ type = CHAR_NAME;
+ }
+ }
+ }
+ types[i] = (byte) type;
+ }
+ statementChars = command;
+ types[len] = CHAR_END;
+ characterTypes = types;
+ parseIndex = 0;
+ }
+
+ private void checkRunOver(int i, int len, int startLoop) throws InvalidQueryException {
+ if (i >= len) {
+ parseIndex = startLoop;
+ throw getSyntaxError();
+ }
+ }
+
+ private void read() throws RepositoryException {
+ currentTokenQuoted = false;
+ if (expected != null) {
+ expected.clear();
+ }
+ int[] types = characterTypes;
+ int i = parseIndex;
+ int type = types[i];
+ while (type == 0) {
+ type = types[++i];
+ }
+ int start = i;
+ char[] chars = statementChars;
+ char c = chars[i++];
+ currentToken = "";
+ switch (type) {
+ case CHAR_NAME:
+ while (true) {
+ type = types[i];
+ if (type != CHAR_NAME && type != CHAR_VALUE) {
+ c = chars[i];
+ break;
+ }
+ i++;
+ }
+ currentToken = statement.substring(start, i);
+ if (currentToken.length() == 0) {
+ throw getSyntaxError();
+ }
+ currentTokenType = IDENTIFIER;
+ parseIndex = i;
+ return;
+ case CHAR_SPECIAL_2:
+ if (types[i] == CHAR_SPECIAL_2) {
+ i++;
+ }
+ // fall through
+ case CHAR_SPECIAL_1:
+ currentToken = statement.substring(start, i);
+ switch (c) {
+ case '$':
+ currentTokenType = PARAMETER;
+ break;
+ case '+':
+ currentTokenType = PLUS;
+ break;
+ case '-':
+ currentTokenType = MINUS;
+ break;
+ case '(':
+ currentTokenType = OPEN;
+ break;
+ case ')':
+ currentTokenType = CLOSE;
+ break;
+ default:
+ currentTokenType = KEYWORD;
+ }
+ parseIndex = i;
+ return;
+ case CHAR_VALUE:
+ long number = c - '0';
+ while (true) {
+ c = chars[i];
+ if (c < '0' || c > '9') {
+ if (c == '.') {
+ readDecimal(start, i);
+ break;
+ }
+ if (c == 'E' || c == 'e') {
+ readDecimal(start, i);
+ break;
+ }
+ checkLiterals(false);
+ currentValue = valueFactory.createValue(number);
+ currentTokenType = VALUE;
+ currentToken = "0";
+ parseIndex = i;
+ break;
+ }
+ number = number * 10 + (c - '0');
+ if (number > Integer.MAX_VALUE) {
+ readDecimal(start, i);
+ break;
+ }
+ i++;
+ }
+ return;
+ case CHAR_DECIMAL:
+ if (types[i] != CHAR_VALUE) {
+ currentTokenType = KEYWORD;
+ currentToken = ".";
+ parseIndex = i;
+ return;
+ }
+ readDecimal(i - 1, i);
+ return;
+ case CHAR_STRING:
+ readString(i, '\'');
+ return;
+ case CHAR_QUOTED:
+ readString(i, '\"');
+ return;
+ case CHAR_END:
+ currentToken = "";
+ currentTokenType = END;
+ parseIndex = i;
+ return;
+ default:
+ throw getSyntaxError();
+ }
+ }
+
+ private void readString(int i, char end) throws RepositoryException {
+ char[] chars = statementChars;
+ String result = null;
+ while (true) {
+ for (int begin = i;; i++) {
+ if (chars[i] == end) {
+ if (result == null) {
+ result = statement.substring(begin, i);
+ } else {
+ result += statement.substring(begin - 1, i);
+ }
+ break;
+ }
+ }
+ if (chars[++i] != end) {
+ break;
+ }
+ i++;
+ }
+ currentToken = "'";
+ checkLiterals(false);
+ currentValue = valueFactory.createValue(result);
+ parseIndex = i;
+ currentTokenType = VALUE;
+ }
+
+ private void checkLiterals(boolean text) throws InvalidQueryException {
+ if (text && !allowTextLiterals || (!text && !allowNumberLiterals)) {
+ throw getSyntaxError("bind variable (literals of this type not allowed)");
+ }
+ }
+
+ private void readDecimal(int start, int i) throws RepositoryException {
+ char[] chars = statementChars;
+ int[] types = characterTypes;
+ while (true) {
+ int t = types[i];
+ if (t != CHAR_DECIMAL && t != CHAR_VALUE) {
+ break;
+ }
+ i++;
+ }
+ if (chars[i] == 'E' || chars[i] == 'e') {
+ i++;
+ if (chars[i] == '+' || chars[i] == '-') {
+ i++;
+ }
+ if (types[i] != CHAR_VALUE) {
+ throw getSyntaxError();
+ }
+ while (types[++i] == CHAR_VALUE) {
+ // go until the first non-number
+ }
+ }
+ parseIndex = i;
+ String sub = statement.substring(start, i);
+ BigDecimal bd;
+ try {
+ bd = new BigDecimal(sub);
+ } catch (NumberFormatException e) {
+ throw ExceptionFactory.invalidQuery("Data conversion error converting " + sub + " to BigDecimal: " + e);
+ }
+ checkLiterals(false);
+
+ currentValue = valueFactory.createValue(bd);
+ currentTokenType = VALUE;
+ }
+
+ private InvalidQueryException getSyntaxError() {
+ if (expected == null || expected.size() == 0) {
+ return getSyntaxError(null);
+ } else {
+ StringBuilder buff = new StringBuilder();
+ for (String exp : expected) {
+ if (buff.length() > 0) {
+ buff.append(", ");
+ }
+ buff.append(exp);
+ }
+ return getSyntaxError(buff.toString());
+ }
+ }
+
+ private InvalidQueryException getSyntaxError(String expected) {
+ int index = Math.min(parseIndex, statement.length() - 1);
+ String query = statement.substring(0, index) + "(*)" + statement.substring(index).trim();
+ if (expected != null) {
+ query += "; expected: " + expected;
+ }
+ return new InvalidQueryException("Query:\n" + query);
+ }
+
+
+}
+
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryImpl.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryImpl.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.qom.QueryObjectModel;
+import javax.jcr.version.VersionException;
+
+/**
+ * The implementation of the corresponding JCR interface.
+ */
+public class QueryImpl implements Query {
+
+ private final QueryObjectModel qom;
+
+ public QueryImpl(QueryObjectModel qom) {
+ this.qom = qom;
+ }
+
+ public void bindValue(String varName, Value value) throws IllegalArgumentException, RepositoryException {
+ qom.bindValue(varName, value);
+ }
+
+ public QueryResult execute() throws InvalidQueryException, RepositoryException {
+ return qom.execute();
+ }
+
+ public String[] getBindVariableNames() throws RepositoryException {
+ return qom.getBindVariableNames();
+ }
+
+ public String getLanguage() {
+ return qom.getLanguage();
+ }
+
+ public String getStatement() {
+ return qom.getStatement();
+ }
+
+ public String getStoredQueryPath() throws ItemNotFoundException, RepositoryException {
+ return qom.getStoredQueryPath();
+ }
+
+ public void setLimit(long limit) {
+ qom.setLimit(limit);
+ }
+
+ public void setOffset(long offset) {
+ qom.setOffset(offset);
+ }
+
+ public Node storeAsNode(String absPath) throws ItemExistsException, PathNotFoundException, VersionException,
+ ConstraintViolationException, LockException, UnsupportedRepositoryOperationException, RepositoryException {
+ return qom.storeAsNode(absPath);
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryManagerImpl.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryManagerImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryManagerImpl.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.qom.QueryObjectModel;
+import org.apache.jackrabbit.query.qom.QueryObjectModelFactoryImpl;
+import org.apache.jackrabbit.query.val.ValueFactoryImpl;
+/**
+ * The implementation of the corresponding JCR interface.
+ */
+public class QueryManagerImpl implements QueryManager {
+
+ private final QueryObjectModelFactoryImpl qomFactory;
+ private final ParserSQL2 parserSQL2;
+ private final ParserXPath parserXPath;
+
+ @SuppressWarnings("deprecation")
+ private static final String[] SUPPOERTED_QUERY_LANGUAGES = {
+ Query.JCR_JQOM,
+ Query.JCR_SQL2,
+ Query.SQL,
+ Query.XPATH
+ };
+
+ public QueryManagerImpl(QueryObjectModelFactoryImpl qomFactory, ValueFactoryImpl valueFactory) {
+ this.qomFactory = qomFactory;
+ parserSQL2 = new ParserSQL2(qomFactory, valueFactory);
+ parserXPath = new ParserXPath(qomFactory, valueFactory);
+ }
+
+ public Query createQuery(String statement, String language) throws InvalidQueryException, RepositoryException {
+ if (Query.JCR_SQL2.equals(language)) {
+ QueryObjectModel qom = parserSQL2.createQueryObjectModel(statement);
+ return new QueryImpl(qom);
+ } else if (Query.XPATH.equals(language)) {
+ QueryObjectModel qom = parserXPath.createQueryObjectModel(statement);
+ return new QueryImpl(qom);
+ }
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public QueryObjectModelFactoryImpl getQOMFactory() {
+ return qomFactory;
+ }
+
+ public Query getQuery(Node node) throws InvalidQueryException, RepositoryException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String[] getSupportedQueryLanguages() throws RepositoryException {
+ // TODO the list is mutable
+ return SUPPOERTED_QUERY_LANGUAGES;
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryResultImpl.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryResultImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/QueryResultImpl.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.RowIterator;
+
+/**
+ * The implementation of the corresponding JCR interface.
+ */
+public class QueryResultImpl implements QueryResult {
+
+ public String[] getColumnNames() throws RepositoryException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public NodeIterator getNodes() throws RepositoryException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public RowIterator getRows() throws RepositoryException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String[] getSelectorNames() throws RepositoryException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RangeIteratorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RangeIteratorImpl.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RangeIteratorImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RangeIteratorImpl.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import javax.jcr.RangeIterator;
+import javax.jcr.RepositoryException;
+
+/**
+ * The implementation of the corresponding JCR interface.
+ *
+ * @param <T> the type
+ */
+public abstract class RangeIteratorImpl<T> implements RangeIterator {
+
+ private final Iterator<T> iterator;
+ private T next;
+ private long size;
+ private long pos;
+
+ protected RangeIteratorImpl(Iterator<T> iterator, long size) {
+ this.iterator = iterator;
+ this.size = size;
+ fetchNext();
+ }
+
+ public boolean skip(T x) throws RepositoryException {
+ return false;
+ }
+
+ void fetchNext() {
+ try {
+ while (true) {
+ if (!iterator.hasNext()) {
+ next = null;
+ break;
+ }
+ next = iterator.next();
+ if (skip(next)) {
+ continue;
+ }
+ break;
+ }
+ } catch (RepositoryException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Object next() {
+ return getNext();
+ }
+
+ public T getNext() {
+ pos++;
+ T result = next;
+ if (result == null) {
+ throw new NoSuchElementException();
+ }
+ fetchNext();
+ return result;
+ }
+
+ public long getPosition() {
+ return pos;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void skip(long skipNum) {
+ for (int i = 0; i < skipNum; i++) {
+ getNext();
+ }
+ }
+
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowImpl.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowImpl.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.query.Row;
+
+/**
+ * The implementation of the corresponding JCR interface.
+ */
+public class RowImpl implements Row {
+
+ public Node getNode() throws RepositoryException {
+ // TODO
+ return null;
+ }
+
+ public Node getNode(String selectorName) throws RepositoryException {
+ // TODO
+ return null;
+ }
+
+ public String getPath() throws RepositoryException {
+ // TODO
+ return null;
+ }
+
+ public String getPath(String selectorName) throws RepositoryException {
+ // TODO
+ return null;
+ }
+
+ public double getScore() throws RepositoryException {
+ // TODO
+ return 0;
+ }
+
+ public double getScore(String selectorName) throws RepositoryException {
+ // TODO
+ return 0;
+ }
+
+ public Value getValue(String columnName) throws ItemNotFoundException, RepositoryException {
+ // TODO
+ return null;
+ }
+
+ public Value[] getValues() throws RepositoryException {
+ // TODO
+ return null;
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowIteratorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowIteratorImpl.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowIteratorImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/RowIteratorImpl.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.query;
+
+import java.util.Collection;
+import javax.jcr.query.Row;
+import javax.jcr.query.RowIterator;
+
+/**
+ * The implementation of the corresponding JCR interface.
+ */
+public class RowIteratorImpl extends RangeIteratorImpl<Row> implements RowIterator {
+
+ protected RowIteratorImpl(Collection<Row> coll, long size) {
+ super(coll.iterator(), size);
+ }
+
+ public Row nextRow() {
+ return getNext();
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/index/Index.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/index/Index.java?rev=1292828&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/index/Index.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/index/Index.java Thu Feb 23 15:34:27 2012
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jackrabbit.query.index;
+
+public class Index {
+
+ /**
+ * The path of what the index contains, or null if not set.
+ */
+ private String pathPrefix;
+
+ /**
+ * The value prefix, or null if not set.
+ */
+ private String valuePrefix;
+
+ /**
+ * The property name, or null if not set.
+ */
+ private String propertyName;
+
+ /**
+ * The node type, or null if not set.
+ */
+ // TODO: use a hash set?
+ private String nodeType;
+
+ public String getPathPrefix() {
+ return pathPrefix;
+ }
+
+ public void setPathPrefix(String pathPrefix) {
+ this.pathPrefix = pathPrefix;
+ }
+
+ public String getValuePrefix() {
+ return valuePrefix;
+ }
+
+ public void setValuePrefix(String valuePrefix) {
+ this.valuePrefix = valuePrefix;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
+ public String getNodeType() {
+ return nodeType;
+ }
+
+ public void setNodeType(String nodeType) {
+ this.nodeType = nodeType;
+ }
+
+ public String toString() {
+ StringBuilder buff = new StringBuilder("Index on ");
+ if (pathPrefix != null) {
+ buff.append("pathPrefix=").append(pathPrefix);
+ }
+ if (valuePrefix != null) {
+ buff.append("valuePrefix=").append(valuePrefix);
+ }
+ if (propertyName != null) {
+ buff.append("propertyName=").append(propertyName);
+ }
+ if (nodeType != null) {
+ buff.append("nodeType=").append(nodeType);
+ }
+ return buff.toString();
+ }
+
+}