I am attempting to put together a DocsAndPositionsEnum that can hide terms
given the payload on the term.  The idea is that if a term has a particular
access control and the user does not I don't want it to be visible.  I have
based this off of

https://github.com/roshanp/lucure-core/blob/master/src/main/java/com/lucure/core/codec/AccessFilteredDocsAndPositionsEnum.java

with some modifications to try and preserve the position information that
is consumed as part of the hasAccess method.  The current iteration that I
am working with seems to be providing wrong positions to the
ExactPhraseScorer.phraseFreq() method in the ChunkState's that are
calculated.

Below is my current iteration on this, but I can't narrow down why exactly
the position information isn't what I expect.  Does anything jump out?

package com.lucure.core.codec;

import com.lucure.core.AuthorizationsHolder;
import com.lucure.core.security.Authorizations;
import com.lucure.core.security.FieldVisibility;
import com.lucure.core.security.VisibilityParseException;
import org.apache.lucene.index.DocsAndPositionsEnum;
import org.apache.lucene.util.AttributeSource;
import org.apache.lucene.util.BytesRef;

import java.io.IOException;
import java.util.Arrays;

import static com.lucure.core.codec.AccessFilteredDocsAndPositionsEnum
  .AllAuthorizationsHolder.ALLAUTHSHOLDER;

/**
 * Enum to read and restrict access to a document based on the payload which
 * is expected to store the visibility
 */
public class AccessFilteredDocsAndPositionsEnum extends
DocsAndPositionsEnum {

    /**
     * This placeholder allows for lucene specific operations such as
     * merge to read data with all authorizations enabled. This should never
     * be used outside of the Codec.
     */
    static class AllAuthorizationsHolder extends AuthorizationsHolder {

        static final AllAuthorizationsHolder ALLAUTHSHOLDER = new
AllAuthorizationsHolder();

        private AllAuthorizationsHolder() {
            super(Authorizations.EMPTY);
        }
    }

    static void enableMergeAuthorizations() {
        AuthorizationsHolder.threadAuthorizations.set(ALLAUTHSHOLDER);
    }

    static void disableMergeAuthorizations() {
        AuthorizationsHolder.threadAuthorizations.remove();
    }

    private final DocsAndPositionsEnum docsAndPositionsEnum;
    private final AuthorizationsHolder authorizationsHolder;

    public AccessFilteredDocsAndPositionsEnum(
      DocsAndPositionsEnum docsAndPositionsEnum) {
        this(docsAndPositionsEnum,
AuthorizationsHolder.threadAuthorizations.get());
    }

    public AccessFilteredDocsAndPositionsEnum(
      DocsAndPositionsEnum docsAndPositionsEnum,
      AuthorizationsHolder authorizationsHolder) {
        this.docsAndPositionsEnum = docsAndPositionsEnum;
        this.authorizationsHolder = authorizationsHolder;
    }

    long cost;
    int endOffset, startOffset, currentPosition, freq, docId;
    BytesRef payload;

    @Override
    public int nextPosition() throws IOException {

        while (!hasAccess()) {

        }

        return currentPosition + 1;
    }

    @Override
    public int startOffset() throws IOException {
        return startOffset;
    }

    @Override
    public int endOffset() throws IOException {
        return endOffset;
    }

    @Override
    public BytesRef getPayload() throws IOException {
        return payload;
    }

    @Override
    public int freq() throws IOException {
        return docsAndPositionsEnum.freq();
    }

    @Override
    public int docID() {
        return docsAndPositionsEnum.docID();
    }

    @Override
    public int nextDoc() throws IOException {

            while (docsAndPositionsEnum.nextDoc() != NO_MORE_DOCS) {

                if (hasAccess()) {
                    return docID();
                }
            }
            return NO_MORE_DOCS;

    }

    @Override
    public int advance(int target) throws IOException {
        int advance = docsAndPositionsEnum.advance(target);
        if (advance != NO_MORE_DOCS) {
                if (hasAccess()) {
                    return docID();
                } else {
                    //seek to next available
                    int doc;
                    while ((doc = nextDoc()) < target) {
                    }
                    return doc;
                }
        }
        return NO_MORE_DOCS;
    }

    @Override
    public long cost() {
        return docsAndPositionsEnum.cost();
    }

    protected boolean hasAccess() throws IOException {
        payload = docsAndPositionsEnum.getPayload();
        endOffset = docsAndPositionsEnum.endOffset();
        startOffset = docsAndPositionsEnum.startOffset();

        currentPosition = docsAndPositionsEnum.nextPosition() - 1;

        BytesRef payload = docsAndPositionsEnum.getPayload();
        try {
            if (payload == null ||
                    ALLAUTHSHOLDER.equals(authorizationsHolder) ||

this.authorizationsHolder.getVisibilityEvaluator().evaluate(
                            new
FieldVisibility(Arrays.copyOfRange(payload.bytes,
                                    payload.offset,
                                    payload.offset +
                                            payload.length)))) {
                return true;
            }
        } catch(VisibilityParseException e) {

        }
        return false;

    }

    @Override
    public AttributeSource attributes() {
        return super.attributes();
    }
}

Reply via email to