jackrabbit-oak-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Angela Schreiber <anch...@adobe.com>
Subject Re: svn commit: r1373392 - in /jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user: ./ query/
Date Fri, 17 Aug 2012 09:01:07 GMT
hi alex

for backward compatibility the form jr-user-query implementation
and the authorizable-query-utility present in jackrabbit-jcr-commons
is required to work as is as nobody will have time to fix all
usages of that in our products.

we may - just in case we have time left - add a additional 
implementation of michael's user-query API and start deprecating
the old one in a subsequent release of oak. do you volunteer
to take care of that? that would be perfect.

kind regards
angela

On 8/17/12 10:43 AM, Alex Parvulescu wrote:
> Hi,
>
> I'd like to raise a concern here about the XPath query builder that made
> its way into oak-jcr with this commit.
>
> There is no native XPath support in Oak. Currently the XPath queries are
> beaing translated into (more or less) equivalent SQL2 queries. See
> also OAK-225.
> So under these circumstances it doesn't make sense to build a query
> programatically as XPath just to have it translated into SQL2 at a later
> stage.
>
> thoughts?
>
> thanks,
> alex
>
>
> On Wed, Aug 15, 2012 at 3:24 PM,<angela@apache.org>  wrote:
>
>> Author: angela
>> Date: Wed Aug 15 13:24:21 2012
>> New Revision: 1373392
>>
>> URL: http://svn.apache.org/viewvc?rev=1373392&view=rev
>> Log:
>> OAK-50 : Implement User Management (WIP)
>>
>> Added:
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/Condition.java
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ConditionVisitor.java
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/RelationOp.java
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ResultIterator.java
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryBuilder.java
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryEvaluator.java
>> Modified:
>>
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java
>>
>> Modified:
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java
>> URL:
>> http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java?rev=1373392&r1=1373391&r2=1373392&view=diff
>>
>> ==============================================================================
>> ---
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java
>> (original)
>> +++
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java
>> Wed Aug 15 13:24:21 2012
>> @@ -41,6 +41,8 @@ import org.apache.jackrabbit.oak.api.Pro
>>   import org.apache.jackrabbit.oak.api.Root;
>>   import org.apache.jackrabbit.oak.api.Tree;
>>   import org.apache.jackrabbit.oak.jcr.SessionDelegate;
>> +import
>> org.apache.jackrabbit.oak.jcr.security.user.query.XPathQueryBuilder;
>> +import
>> org.apache.jackrabbit.oak.jcr.security.user.query.XPathQueryEvaluator;
>>   import org.apache.jackrabbit.oak.jcr.value.ValueConverter;
>>   import org.apache.jackrabbit.oak.security.user.UserProviderImpl;
>>   import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
>> @@ -142,8 +144,9 @@ public class UserManagerImpl implements
>>
>>       @Override
>>       public Iterator<Authorizable>  findAuthorizables(Query query) throws
>> RepositoryException {
>> -        // TODO : execute the specified query
>> -        throw new UnsupportedOperationException("Not Implemented");
>> +        XPathQueryBuilder builder = new XPathQueryBuilder();
>> +        query.build(builder);
>> +        return new XPathQueryEvaluator(builder, this,
>> sessionDelegate.getQueryManager(),
>> sessionDelegate.getNamePathMapper()).eval();
>>       }
>>
>>       @Override
>>
>> Added:
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/Condition.java
>> URL:
>> http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/Condition.java?rev=1373392&view=auto
>>
>> ==============================================================================
>> ---
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/Condition.java
>> (added)
>> +++
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/Condition.java
>> Wed Aug 15 13:24:21 2012
>> @@ -0,0 +1,190 @@
>> +/*
>> + * 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.oak.jcr.security.user.query;
>> +
>> +import java.util.ArrayList;
>> +import java.util.Iterator;
>> +import java.util.List;
>> +import javax.jcr.RepositoryException;
>> +import javax.jcr.Value;
>> +
>> +
>> +interface Condition {
>> +
>> +    void accept(ConditionVisitor visitor) throws RepositoryException;
>> +
>> +    //------------------------------------------<  Condition
>> implementations>---
>> +
>> +    static class Node implements Condition {
>> +        private final String pattern;
>> +
>> +        public Node(String pattern) {
>> +            this.pattern = pattern;
>> +        }
>> +
>> +        public String getPattern() {
>> +            return pattern;
>> +        }
>> +
>> +        public void accept(ConditionVisitor visitor) throws
>> RepositoryException {
>> +            visitor.visit(this);
>> +        }
>> +    }
>> +
>> +    static class Property implements Condition {
>> +        private final String relPath;
>> +        private final RelationOp op;
>> +        private final Value value;
>> +        private final String pattern;
>> +
>> +        public Property(String relPath, RelationOp op, Value value) {
>> +            this.relPath = relPath;
>> +            this.op = op;
>> +            this.value = value;
>> +            pattern = null;
>> +        }
>> +
>> +        public Property(String relPath, RelationOp op, String pattern) {
>> +            this.relPath = relPath;
>> +            this.op = op;
>> +            value = null;
>> +            this.pattern = pattern;
>> +        }
>> +
>> +        public Property(String relPath, RelationOp op) {
>> +            this.relPath = relPath;
>> +            this.op = op;
>> +            value = null;
>> +            pattern = null;
>> +        }
>> +
>> +        public String getRelPath() {
>> +            return relPath;
>> +        }
>> +
>> +        public RelationOp getOp() {
>> +            return op;
>> +        }
>> +
>> +        public Value getValue() {
>> +            return value;
>> +        }
>> +
>> +        public String getPattern() {
>> +            return pattern;
>> +        }
>> +
>> +        public void accept(ConditionVisitor visitor) throws
>> RepositoryException {
>> +            visitor.visit(this);
>> +        }
>> +    }
>> +
>> +    static class Contains implements Condition {
>> +        private final String relPath;
>> +        private final String searchExpr;
>> +
>> +        public Contains(String relPath, String searchExpr) {
>> +            this.relPath = relPath;
>> +            this.searchExpr = searchExpr;
>> +        }
>> +
>> +        public String getRelPath() {
>> +            return relPath;
>> +        }
>> +
>> +        public String getSearchExpr() {
>> +            return searchExpr;
>> +        }
>> +
>> +        public void accept(ConditionVisitor visitor) {
>> +            visitor.visit(this);
>> +        }
>> +    }
>> +
>> +    static class Impersonation implements Condition {
>> +        private final String name;
>> +
>> +        public Impersonation(String name) {
>> +            this.name = name;
>> +        }
>> +
>> +        public String getName() {
>> +            return name;
>> +        }
>> +
>> +        public void accept(ConditionVisitor visitor) {
>> +            visitor.visit(this);
>> +        }
>> +    }
>> +
>> +    static class Not implements Condition {
>> +        private final Condition condition;
>> +
>> +        public Not(Condition condition) {
>> +            this.condition = condition;
>> +        }
>> +
>> +        public Condition getCondition() {
>> +            return condition;
>> +        }
>> +
>> +        public void accept(ConditionVisitor visitor) throws
>> RepositoryException {
>> +            visitor.visit(this);
>> +        }
>> +    }
>> +
>> +    abstract static class Compound implements Condition,
>> Iterable<Condition>  {
>> +        private final List<Condition>  conditions = new
>> ArrayList<Condition>();
>> +
>> +        public Compound() {
>> +            super();
>> +        }
>> +
>> +        public Compound(Condition condition1, Condition condition2) {
>> +            conditions.add(condition1);
>> +            conditions.add(condition2);
>> +        }
>> +
>> +        public void addCondition(Condition condition) {
>> +            conditions.add(condition);
>> +        }
>> +
>> +        public Iterator<Condition>  iterator() {
>> +            return conditions.iterator();
>> +        }
>> +    }
>> +
>> +    static class And extends Compound {
>> +        public And(Condition condition1, Condition condition2) {
>> +            super(condition1, condition2);
>> +        }
>> +
>> +        public void accept(ConditionVisitor visitor) throws
>> RepositoryException {
>> +            visitor.visit(this);
>> +        }
>> +    }
>> +
>> +    static class Or extends Compound {
>> +        public Or(Condition condition1, Condition condition2) {
>> +            super(condition1, condition2);
>> +        }
>> +
>> +        public void accept(ConditionVisitor visitor) throws
>> RepositoryException {
>> +            visitor.visit(this);
>> +        }
>> +    }
>> +}
>> \ No newline at end of file
>>
>> Added:
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ConditionVisitor.java
>> URL:
>> http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ConditionVisitor.java?rev=1373392&view=auto
>>
>> ==============================================================================
>> ---
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ConditionVisitor.java
>> (added)
>> +++
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ConditionVisitor.java
>> Wed Aug 15 13:24:21 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.oak.jcr.security.user.query;
>> +
>> +import javax.jcr.RepositoryException;
>> +
>> +interface ConditionVisitor {
>> +
>> +    void visit(Condition.Node node) throws RepositoryException;
>> +
>> +    void visit(Condition.Property condition) throws RepositoryException;
>> +
>> +    void visit(Condition.Contains condition);
>> +
>> +    void visit(Condition.Impersonation condition);
>> +
>> +    void visit(Condition.Not condition) throws RepositoryException;
>> +
>> +    void visit(Condition.And condition) throws RepositoryException;
>> +
>> +    void visit(Condition.Or condition) throws RepositoryException;
>> +}
>> \ No newline at end of file
>>
>> Added:
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/RelationOp.java
>> URL:
>> http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/RelationOp.java?rev=1373392&view=auto
>>
>> ==============================================================================
>> ---
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/RelationOp.java
>> (added)
>> +++
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/RelationOp.java
>> Wed Aug 15 13:24:21 2012
>> @@ -0,0 +1,28 @@
>> +package org.apache.jackrabbit.oak.jcr.security.user.query;
>> +
>> +/**
>> + * Relational operators for comparing a property to a value. Correspond
>> + * to the general comparison operators as define in JSR-170.
>> + * The {@link #EX} tests for existence of a property.
>> + */
>> +enum RelationOp {
>> +
>> +    NE("!="),
>> +    EQ("="),
>> +    LT("<"),
>> +    LE("<="),
>> +    GT(">"),
>> +    GE("=>"),
>> +    EX(""),
>> +    LIKE("like");
>> +
>> +    private final String op;
>> +
>> +    RelationOp(String op) {
>> +        this.op = op;
>> +    }
>> +
>> +    String getOp() {
>> +        return op;
>> +    }
>> +}
>>
>> Added:
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ResultIterator.java
>> URL:
>> http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ResultIterator.java?rev=1373392&view=auto
>>
>> ==============================================================================
>> ---
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ResultIterator.java
>> (added)
>> +++
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/ResultIterator.java
>> Wed Aug 15 13:24:21 2012
>> @@ -0,0 +1,120 @@
>> +/*
>> + * 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.oak.jcr.security.user.query;
>> +
>> +import java.util.Iterator;
>> +import java.util.NoSuchElementException;
>> +
>> +/**
>> + * Implements a query result iterator which only returns a maximum number
>> of
>> + * element from an underlying iterator starting at a given offset.
>> + *
>> + * @param<T>  element type of the query results
>> + *
>> + * TODO move to query-commons ?
>> + */
>> +public class ResultIterator<T>  implements Iterator<T>  {
>> +
>> +    public final static int OFFSET_NONE = 0;
>> +    public final static int MAX_ALL = -1;
>> +
>> +    private final Iterator<T>  iterator;
>> +    private final long offset;
>> +    private final long max;
>> +    private int pos;
>> +    private T next;
>> +
>> +    /**
>> +     * Create a new {@code ResultIterator} with a given offset and maximum
>> +     *
>> +     * @param offset Offset to start iteration at. Must be non negative
>> +     * @param max Maximum elements this iterator should return.
>> +     * Set to {@link #MAX_ALL} for all results.
>> +     * @param iterator the underlying iterator
>> +     * @throws IllegalArgumentException if offset is negative
>> +     */
>> +    private ResultIterator(long offset, long max, Iterator<T>  iterator) {
>> +        if (offset<  OFFSET_NONE) {
>> +            throw new IllegalArgumentException("Offset must not be
>> negative");
>> +        }
>> +        this.iterator = iterator;
>> +        this.offset = offset;
>> +        this.max = max;
>> +    }
>> +
>> +    /**
>> +     * Returns an iterator respecting the specified {@code offset} and
>> {@code max}.
>> +     *
>> +     * @param offset   offset to start iteration at. Must be non negative
>> +     * @param max      maximum elements this iterator should return. Set
>> to
>> +     * {@link #MAX_ALL} for all
>> +     * @param iterator the underlying iterator
>> +     * @param<T>       element type
>> +     * @return an iterator which only returns the elements in the given
>> bounds
>> +     */
>> +    public static<T>  Iterator<T>  create(long offset, long max,
>> Iterator<T>  iterator) {
>> +        if (offset == OFFSET_NONE&&  max == MAX_ALL) {
>> +            // no constraints on offset nor max ->  return the original
>> iterator.
>> +            return iterator;
>> +        } else {
>> +            return new ResultIterator<T>(offset, max, iterator);
>> +        }
>> +    }
>> +
>> +    //-----------------------------------------------------------<
>> Iterator>---
>> +    @Override
>> +    public boolean hasNext() {
>> +        if (next == null) {
>> +            fetchNext();
>> +        }
>> +        return next != null;
>> +    }
>> +
>> +    @Override
>> +    public T next() {
>> +        if (!hasNext()) {
>> +            throw new NoSuchElementException();
>> +        }
>> +        return consumeNext();
>> +    }
>> +
>> +    @Override
>> +    public void remove() {
>> +        throw new UnsupportedOperationException();
>> +    }
>> +
>> +    //------------------------------------------------------------<
>> private>---
>> +
>> +    private void fetchNext() {
>> +        for (; pos<  offset&&  iterator.hasNext(); pos++) {
>> +            next = iterator.next();
>> +        }
>> +
>> +        if (pos<  offset || !iterator.hasNext() || max>= 0&&  pos
-
>> offset + 1>  max) {
>> +            next = null;
>> +        } else {
>> +            next = iterator.next();
>> +            pos++;
>> +        }
>> +    }
>> +
>> +    private T consumeNext() {
>> +        T element = next;
>> +        next = null;
>> +        return element;
>> +    }
>> +}
>> \ No newline at end of file
>>
>> Added:
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryBuilder.java
>> URL:
>> http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryBuilder.java?rev=1373392&view=auto
>>
>> ==============================================================================
>> ---
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryBuilder.java
>> (added)
>> +++
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryBuilder.java
>> Wed Aug 15 13:24:21 2012
>> @@ -0,0 +1,195 @@
>> +/*
>> + * 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.oak.jcr.security.user.query;
>> +
>> +import javax.jcr.Value;
>> +
>> +import org.apache.jackrabbit.api.security.user.Authorizable;
>> +import org.apache.jackrabbit.api.security.user.QueryBuilder;
>> +
>> +public class XPathQueryBuilder implements QueryBuilder<Condition>  {
>> +
>> +    private Class<? extends Authorizable>  selector = Authorizable.class;
>> +    private String groupName;
>> +    private boolean declaredMembersOnly;
>> +    private Condition condition;
>> +    private String sortProperty;
>> +    private Direction sortDirection = Direction.ASCENDING;
>> +    private boolean sortIgnoreCase;
>> +    private Value bound;
>> +    private long offset;
>> +    private long maxCount = -1;
>> +
>> +    //-------------------------------------------------------<
>> QueryBuilder>---
>> +    @Override
>> +    public void setSelector(Class<? extends Authorizable>  selector) {
>> +        this.selector = selector;
>> +    }
>> +
>> +    @Override
>> +    public void setScope(String groupName, boolean declaredOnly) {
>> +        this.groupName = groupName;
>> +        declaredMembersOnly = declaredOnly;
>> +    }
>> +
>> +    @Override
>> +    public void setCondition(Condition condition) {
>> +        this.condition = condition;
>> +    }
>> +
>> +    @Override
>> +    public void setSortOrder(String propertyName, Direction direction,
>> boolean ignoreCase) {
>> +        sortProperty = propertyName;
>> +        sortDirection = direction;
>> +        sortIgnoreCase = ignoreCase;
>> +    }
>> +
>> +    @Override
>> +    public void setSortOrder(String propertyName, Direction direction) {
>> +        setSortOrder(propertyName, direction, false);
>> +    }
>> +
>> +    @Override
>> +    public void setLimit(Value bound, long maxCount) {
>> +        offset = 0;   // Unset any previously set offset
>> +        this.bound = bound;
>> +        this.maxCount = maxCount;
>> +    }
>> +
>> +    @Override
>> +    public void setLimit(long offset, long maxCount) {
>> +        bound = null; // Unset any previously set bound
>> +        this.offset = offset;
>> +        this.maxCount = maxCount;
>> +    }
>> +
>> +    @Override
>> +    public Condition nameMatches(String pattern) {
>> +        return new Condition.Node(pattern);
>> +    }
>> +
>> +    @Override
>> +    public Condition neq(String relPath, Value value) {
>> +        return new Condition.Property(relPath, RelationOp.NE, value);
>> +    }
>> +
>> +    @Override
>> +    public Condition eq(String relPath, Value value) {
>> +        return new Condition.Property(relPath, RelationOp.EQ, value);
>> +    }
>> +
>> +    @Override
>> +    public Condition lt(String relPath, Value value) {
>> +        return new Condition.Property(relPath, RelationOp.LT, value);
>> +    }
>> +
>> +    @Override
>> +    public Condition le(String relPath, Value value) {
>> +        return new Condition.Property(relPath, RelationOp.LE, value);
>> +    }
>> +
>> +    @Override
>> +    public Condition gt(String relPath, Value value) {
>> +        return new Condition.Property(relPath, RelationOp.GT, value);
>> +    }
>> +
>> +    @Override
>> +    public Condition ge(String relPath, Value value) {
>> +        return new Condition.Property(relPath, RelationOp.GE, value);
>> +    }
>> +
>> +    @Override
>> +    public Condition exists(String relPath) {
>> +        return new Condition.Property(relPath, RelationOp.EX);
>> +    }
>> +
>> +    @Override
>> +    public Condition like(String relPath, String pattern) {
>> +        return new Condition.Property(relPath, RelationOp.LIKE, pattern);
>> +    }
>> +
>> +    @Override
>> +    public Condition contains(String relPath, String searchExpr) {
>> +        return new Condition.Contains(relPath, searchExpr);
>> +    }
>> +
>> +    @Override
>> +    public Condition impersonates(String name) {
>> +        return new Condition.Impersonation(name);
>> +    }
>> +
>> +    @Override
>> +    public Condition not(Condition condition) {
>> +        return new Condition.Not(condition);
>> +    }
>> +
>> +    @Override
>> +    public Condition and(Condition condition1, Condition condition2) {
>> +        return new Condition.And(condition1, condition2);
>> +    }
>> +
>> +    @Override
>> +    public Condition or(Condition condition1, Condition condition2) {
>> +        return new Condition.Or(condition1, condition2);
>> +    }
>> +
>> +    //-----------------------------------------------------------<
>> internal>---
>> +
>> +    Condition property(String relPath, RelationOp op, Value value) {
>> +        return new Condition.Property(relPath, op, value);
>> +    }
>> +
>> +    Class<? extends Authorizable>  getSelector() {
>> +        return selector;
>> +    }
>> +
>> +    String getGroupName() {
>> +        return groupName;
>> +    }
>> +
>> +    boolean isDeclaredMembersOnly() {
>> +        return declaredMembersOnly;
>> +    }
>> +
>> +    Condition getCondition() {
>> +        return condition;
>> +    }
>> +
>> +    String getSortProperty() {
>> +        return sortProperty;
>> +    }
>> +
>> +    Direction getSortDirection() {
>> +        return sortDirection;
>> +    }
>> +
>> +    boolean getSortIgnoreCase() {
>> +        return sortIgnoreCase;
>> +    }
>> +
>> +    Value getBound() {
>> +        return bound;
>> +    }
>> +
>> +    long getOffset() {
>> +        return offset;
>> +    }
>> +
>> +    long getMaxCount() {
>> +        return maxCount;
>> +    }
>> +}
>> \ No newline at end of file
>>
>> Added:
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryEvaluator.java
>> URL:
>> http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryEvaluator.java?rev=1373392&view=auto
>>
>> ==============================================================================
>> ---
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryEvaluator.java
>> (added)
>> +++
>> jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/query/XPathQueryEvaluator.java
>> Wed Aug 15 13:24:21 2012
>> @@ -0,0 +1,340 @@
>> +/*
>> + * 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.oak.jcr.security.user.query;
>> +
>> +import java.util.Iterator;
>> +import javax.annotation.Nonnull;
>> +import javax.jcr.Node;
>> +import javax.jcr.PropertyType;
>> +import javax.jcr.RepositoryException;
>> +import javax.jcr.Value;
>> +import javax.jcr.query.Query;
>> +import javax.jcr.query.QueryManager;
>> +
>> +import com.google.common.base.Function;
>> +import com.google.common.base.Predicate;
>> +import com.google.common.base.Predicates;
>> +import com.google.common.collect.Iterators;
>> +import org.apache.jackrabbit.api.security.user.Authorizable;
>> +import org.apache.jackrabbit.api.security.user.Group;
>> +import org.apache.jackrabbit.api.security.user.QueryBuilder;
>> +import org.apache.jackrabbit.api.security.user.User;
>> +import org.apache.jackrabbit.api.security.user.UserManager;
>> +import org.apache.jackrabbit.oak.jcr.security.user.UserManagerImpl;
>> +import org.apache.jackrabbit.oak.namepath.NamePathMapper;
>> +import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
>> +import org.apache.jackrabbit.util.Text;
>> +import org.slf4j.Logger;
>> +import org.slf4j.LoggerFactory;
>> +
>> +/**
>> + * This evaluator for {@link
>> org.apache.jackrabbit.api.security.user.Query}s use XPath
>> + * and some minimal client side filtering.
>> + */
>> +public class XPathQueryEvaluator implements ConditionVisitor {
>> +    static final Logger log =
>> LoggerFactory.getLogger(XPathQueryEvaluator.class);
>> +
>> +    private final XPathQueryBuilder builder;
>> +    private final UserManager userManager;
>> +    private final QueryManager queryManager;
>> +    private final NamePathMapper namePathMapper;
>> +
>> +    private final StringBuilder xPath = new StringBuilder();
>> +
>> +    public XPathQueryEvaluator(XPathQueryBuilder builder, UserManagerImpl
>> userManager,
>> +                               QueryManager queryManager, NamePathMapper
>> namePathMapper) {
>> +        this.builder = builder;
>> +        this.userManager = userManager;
>> +        this.queryManager = queryManager;
>> +        this.namePathMapper = namePathMapper;
>> +    }
>> +
>> +    public Iterator<Authorizable>  eval() throws RepositoryException {
>> +        xPath.append("//element(*,")
>> +                .append(getNtName(builder.getSelector()))
>> +                .append(')');
>> +
>> +        Value bound = builder.getBound();
>> +        long offset = builder.getOffset();
>> +        if (bound != null&&  offset>  0) {
>> +            log.warn("Found bound {} and offset {} in limit. Discarding
>> offset.", bound, offset);
>> +            offset = 0;
>> +        }
>> +
>> +        Condition condition = builder.getCondition();
>> +        String sortCol = builder.getSortProperty();
>> +        QueryBuilder.Direction sortDir = builder.getSortDirection();
>> +        if (bound != null) {
>> +            if (sortCol == null) {
>> +                log.warn("Ignoring bound {} since no sort order is
>> specified");
>> +            } else {
>> +                Condition boundCondition = builder.property(sortCol,
>> getCollation(sortDir), bound);
>> +                condition = condition == null
>> +                        ? boundCondition
>> +                        : builder.and(condition, boundCondition);
>> +            }
>> +        }
>> +
>> +        if (condition != null) {
>> +            xPath.append('[');
>> +            condition.accept(this);
>> +            xPath.append(']');
>> +        }
>> +
>> +        if (sortCol != null) {
>> +            boolean ignoreCase = builder.getSortIgnoreCase();
>> +            xPath.append(" order by ")
>> +                    .append(ignoreCase ? "" : "fn:lower-case(")
>> +                    .append(sortCol)
>> +                    .append(ignoreCase ? " " : ") ")
>> +                    .append(sortDir.getDirection());
>> +        }
>> +
>> +        Query query = queryManager.createQuery(xPath.toString(),
>> Query.XPATH);
>> +        long maxCount = builder.getMaxCount();
>> +        if (maxCount == 0) {
>> +            return Iterators.emptyIterator();
>> +        }
>> +
>> +        // If we are scoped to a group and have a limit, we have to apply
>> the limit
>> +        // here (inefficient!) otherwise we can apply the limit in the
>> query
>> +        if (builder.getGroupName() == null) {
>> +            if (offset>  0) {
>> +                query.setOffset(offset);
>> +            }
>> +            if (maxCount>  0) {
>> +                query.setLimit(maxCount);
>> +            }
>> +            return toAuthorizables(execute(query));
>> +        } else {
>> +            Iterator<Authorizable>  result =
>> toAuthorizables(execute(query));
>> +            Iterator<Authorizable>  filtered = filter(result,
>> builder.getGroupName(), builder.isDeclaredMembersOnly());
>> +            return ResultIterator.create(offset, maxCount, filtered);
>> +        }
>> +    }
>> +
>> +    //---------------------------------------------------<
>> ConditionVisitor>---
>> +    @Override
>> +    public void visit(Condition.Node condition) throws
>> RepositoryException {
>> +        xPath.append('(')
>> +                .append("jcr:like(")
>> +
>>   .append(namePathMapper.getJcrName(UserConstants.REP_PRINCIPAL_NAME))
>> +                .append(",'")
>> +                .append(condition.getPattern())
>> +                .append("')")
>> +                .append(" or ")
>> +                .append("jcr:like(fn:name(.),'")
>> +                .append(escape(condition.getPattern()))
>> +                .append("')")
>> +                .append(')');
>> +    }
>> +
>> +    @Override
>> +    public void visit(Condition.Property condition) throws
>> RepositoryException {
>> +        RelationOp relOp = condition.getOp();
>> +        if (relOp == RelationOp.EX) {
>> +            xPath.append(condition.getRelPath());
>> +        } else if (relOp == RelationOp.LIKE) {
>> +            xPath.append("jcr:like(")
>> +                    .append(condition.getRelPath())
>> +                    .append(",'")
>> +                    .append(condition.getPattern())
>> +                    .append("')");
>> +        } else {
>> +            xPath.append(condition.getRelPath())
>> +                    .append(condition.getOp().getOp())
>> +                    .append(format(condition.getValue()));
>> +        }
>> +    }
>> +
>> +    @Override
>> +    public void visit(Condition.Contains condition) {
>> +        xPath.append("jcr:contains(")
>> +                .append(condition.getRelPath())
>> +                .append(",'")
>> +                .append(condition.getSearchExpr())
>> +                .append("')");
>> +    }
>> +
>> +    @Override
>> +    public void visit(Condition.Impersonation condition) {
>> +        xPath.append("@rep:impersonators='")
>> +                .append(condition.getName())
>> +                .append('\'');
>> +    }
>> +
>> +    @Override
>> +    public void visit(Condition.Not condition) throws RepositoryException
>> {
>> +        xPath.append("not(");
>> +        condition.getCondition().accept(this);
>> +        xPath.append(')');
>> +    }
>> +
>> +    @Override
>> +    public void visit(Condition.And condition) throws RepositoryException
>> {
>> +        int count = 0;
>> +        for (Condition c : condition) {
>> +            xPath.append(count++>  0 ? " and " : "");
>> +            c.accept(this);
>> +        }
>> +    }
>> +
>> +    @Override
>> +    public void visit(Condition.Or condition) throws RepositoryException {
>> +        int pos = xPath.length();
>> +
>> +        int count = 0;
>> +        for (Condition c : condition) {
>> +            xPath.append(count++>  0 ? " or " : "");
>> +            c.accept(this);
>> +        }
>> +
>> +        // Surround or clause with parentheses if it contains more than
>> one term
>> +        if (count>  1) {
>> +            xPath.insert(pos, '(');
>> +            xPath.append(')');
>> +        }
>> +    }
>> +
>> +    //------------------------------------------------------------<
>> private>---
>> +    /**
>> +     * Escape {@code string} for matching in jcr escaped node names
>> +     *
>> +     * @param string string to escape
>> +     * @return escaped string
>> +     */
>> +    @Nonnull
>> +    public static String escape(String string) {
>> +        StringBuilder result = new StringBuilder();
>> +
>> +        int k = 0;
>> +        int j;
>> +        do {
>> +            j = string.indexOf('%', k); // split on %
>> +            if (j<  0) {
>> +                // jcr escape trail
>> +
>>   result.append(Text.escapeIllegalJcrChars(string.substring(k)));
>> +            } else if (j>  0&&  string.charAt(j - 1) == '\\') {
>> +                // literal occurrence of % ->  jcr escape
>> +
>>   result.append(Text.escapeIllegalJcrChars(string.substring(k, j) + '%'));
>> +            } else {
>> +                // wildcard occurrence of % ->  jcr escape all but %
>> +
>>   result.append(Text.escapeIllegalJcrChars(string.substring(k,
>> j))).append('%');
>> +            }
>> +
>> +            k = j + 1;
>> +        } while (j>= 0);
>> +
>> +        return result.toString();
>> +    }
>> +
>> +    @Nonnull
>> +    private String getNtName(Class<? extends Authorizable>  selector) {
>> +        String ntName;
>> +        if (User.class.isAssignableFrom(selector)) {
>> +            ntName = namePathMapper.getJcrName(UserConstants.NT_REP_USER);
>> +        } else if (Group.class.isAssignableFrom(selector)) {
>> +            ntName =
>> namePathMapper.getJcrName(UserConstants.NT_REP_GROUP);
>> +        } else {
>> +            ntName =
>> namePathMapper.getJcrName(UserConstants.NT_REP_AUTHORIZABLE);
>> +        }
>> +        if (ntName == null) {
>> +            log.warn("Failed to retrieve JCR name for authorizable node
>> type.");
>> +            ntName = UserConstants.NT_REP_AUTHORIZABLE;
>> +        }
>> +        return ntName;
>> +    }
>> +
>> +    @Nonnull
>> +    private static String format(Value value) throws RepositoryException {
>> +        switch (value.getType()) {
>> +            case PropertyType.STRING:
>> +            case PropertyType.BOOLEAN:
>> +                return '\'' + value.getString() + '\'';
>> +
>> +            case PropertyType.LONG:
>> +            case PropertyType.DOUBLE:
>> +                return value.getString();
>> +
>> +            case PropertyType.DATE:
>> +                return "xs:dateTime('" + value.getString() + "')";
>> +
>> +            default:
>> +                throw new RepositoryException("Property of type " +
>> PropertyType.nameFromValue(value.getType()) +
>> +                        " not supported");
>> +        }
>> +    }
>> +
>> +    @Nonnull
>> +    private static RelationOp getCollation(QueryBuilder.Direction
>> direction) throws RepositoryException {
>> +        switch (direction) {
>> +            case ASCENDING:
>> +                return RelationOp.GT;
>> +            case DESCENDING:
>> +                return RelationOp.LT;
>> +            default:
>> +                throw new RepositoryException("Unknown sort order " +
>> direction);
>> +        }
>> +    }
>> +
>> +    @Nonnull
>> +    @SuppressWarnings("unchecked")
>> +    private static Iterator<Node>  execute(Query query) throws
>> RepositoryException {
>> +        return query.execute().getNodes();
>> +    }
>> +
>> +    @Nonnull
>> +    private Iterator<Authorizable>  toAuthorizables(Iterator<Node> 
nodes) {
>> +        Function<Node, Authorizable>  transformer = new Function<Node,
>> Authorizable>() {
>> +            public Authorizable apply(Node node) {
>> +                try {
>> +                    return
>> userManager.getAuthorizableByPath(node.getPath());
>> +                } catch (RepositoryException e) {
>> +                    log.warn("Cannot create authorizable from node {}",
>> node);
>> +                    log.debug(e.getMessage(), e);
>> +                    return null;
>> +                }
>> +            }
>> +        };
>> +
>> +        return Iterators.transform(nodes, transformer);
>> +    }
>> +
>> +    @Nonnull
>> +    private Iterator<Authorizable>  filter(Iterator<Authorizable>
>> authorizables,
>> +                                          String groupName,
>> +                                          final boolean
>> declaredMembersOnly) throws RepositoryException {
>> +        Predicate<Authorizable>  predicate;
>> +        Authorizable authorizable =
>> userManager.getAuthorizable(groupName);
>> +        if (authorizable == null || !authorizable.isGroup()) {
>> +            predicate = Predicates.alwaysFalse();
>> +        } else {
>> +            final Group group = (Group) authorizable;
>> +            predicate = new Predicate<Authorizable>() {
>> +                public boolean apply(Authorizable authorizable) {
>> +                    try {
>> +                        return (declaredMembersOnly) ?
>> group.isDeclaredMember(authorizable) : group.isMember(authorizable);
>> +                    } catch (RepositoryException e) {
>> +                        log.debug("Cannot determine group membership for
>> {}", authorizable, e.getMessage());
>> +                        return false;
>> +                    }
>> +                }
>> +            };
>> +        }
>> +        return Iterators.filter(authorizables, predicate);
>> +    }
>> +}
>> \ No newline at end of file
>>
>>
>>

Mime
View raw message