Package org.exist.xquery.functions.fn

Source Code of org.exist.xquery.functions.fn.ExtCollection

/*
* eXist Open Source Native XML Database
* Copyright (C) 2004-2009 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*  $Id$
*/
package org.exist.xquery.functions.fn;

import org.apache.log4j.Logger;

import org.exist.collections.Collection;
import org.exist.dom.DefaultDocumentSet;
import org.exist.dom.DocumentImpl;
import org.exist.dom.DocumentSet;
import org.exist.dom.MutableDocumentSet;
import org.exist.dom.NewArrayNodeSet;
import org.exist.dom.NodeProxy;
import org.exist.dom.NodeSet;
import org.exist.dom.QName;
import org.exist.dom.StoredNode;
import org.exist.numbering.NodeId;
import org.exist.storage.UpdateListener;
import org.exist.storage.lock.Lock;
import org.exist.util.LockException;
import org.exist.xmldb.XmldbURI;
import org.exist.xquery.Cardinality;
import org.exist.xquery.Dependency;
import org.exist.xquery.Function;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.Profiler;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.functions.xmldb.XMLDBModule;
import org.exist.xquery.value.AnyURIValue;
import org.exist.xquery.value.FunctionReturnSequenceType;
import org.exist.xquery.value.FunctionParameterSequenceType;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.Type;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.exist.security.PermissionDeniedException;

/**
* @author wolf
*/
public class ExtCollection extends Function {

    protected static final Logger logger = Logger.getLogger(ExtCollection.class);

    public final static FunctionSignature signature =
        new FunctionSignature(
            new QName("collection", Function.BUILTIN_FUNCTION_NS),
            "Returns the documents contained in the collections specified in " +
            "the input sequence. " + XMLDBModule.COLLECTION_URI +
            " Documents contained in subcollections are also included. If no value is supplied, the statically know documents are used, for the REST Server this could be the addressed collection.",
            new SequenceType[] {
                //Different from the offical specs
                new FunctionParameterSequenceType("collection-uris", Type.STRING,
                    Cardinality.ZERO_OR_MORE, "The collection-URIs for which to include the documents")},
                new FunctionReturnSequenceType(Type.NODE, Cardinality.ZERO_OR_MORE,
                    "The document nodes contained in or under the given collections"),
            true);

    private boolean includeSubCollections = false;
    private UpdateListener listener = null;

    /**
     * @param context
     */
    public ExtCollection(XQueryContext context) {
        this(context, signature, true);
    }

  public ExtCollection(XQueryContext context, FunctionSignature signature, boolean inclusive) {
    super(context, signature);
    includeSubCollections = inclusive;
  }
 
  /* (non-Javadoc)
   * @see org.exist.xquery.Expression#eval(org.exist.dom.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
   */
  public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
        if (context.getProfiler().isEnabled()) {
            context.getProfiler().start(this);      
            context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
            if (contextSequence != null)
                {context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);}
            if (contextItem != null)
                {context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());}
        }
        final List<String> args = getParameterValues(contextSequence, contextItem);
        // TODO: disabled cache for now as it may cause concurrency issues
        // better use compile-time inspection and maybe a pragma to mark those
        // sections in the query that can be safely cached
        // boolean cacheIsValid = false;
        // if (cachedArgs != null)
        //    cacheIsValid = compareArguments(cachedArgs, args);
        // if (cacheIsValid) {
             //If the expression occurs in a nested context, we might have cached the
             //document set
             //if (context.getProfiler().isEnabled())
                 //context.getProfiler().end(this, "fn:collection: loading documents", cached);
             //return cached;
        // }
        //Build the document set
        DocumentSet docs = null;
        try {
            if (args.size() == 0) {
                //TODO : add default collection to the context
                //If the value of the default collection is undefined an error is raised [err:FODC0002].
                docs = context.getStaticallyKnownDocuments();
            } else {
                MutableDocumentSet ndocs = new DefaultDocumentSet();
                for (final String next : args) {
                    final XmldbURI uri = new AnyURIValue(next).toXmldbURI();
                    final Collection coll = context.getBroker().getCollection(uri);
                    if (coll == null) {
                        if (context.isRaiseErrorOnFailedRetrieval()) {
                            throw new XPathException("FODC0002: can not access collection '" + uri + "'");
                        }
                    } else {
                        if (context.inProtectedMode())
                            {context.getProtectedDocs().getDocsByCollection(coll, includeSubCollections, ndocs);}
                        else
                            {coll.allDocs(context.getBroker(), ndocs,
                                includeSubCollections, context.getProtectedDocs());}
                    }
                }
                docs = ndocs;
            }
        } catch (final XPathException e) { //From AnyURIValue constructor
            e.setLocation(line, column);
            throw new XPathException("FODC0002: " + e.getMessage());
        } catch(final PermissionDeniedException pde) {
            throw new XPathException("FODC0002: can not access collection '" + pde.getMessage() + "'");
           
        }
        // iterate through all docs and create the node set
        final NodeSet result = new NewArrayNodeSet(docs.getDocumentCount(), 1);
        Lock dlock;
        DocumentImpl doc;
        for (final Iterator<DocumentImpl> i = docs.getDocumentIterator(); i.hasNext();) {
            doc = i.next();
            dlock = doc.getUpdateLock();
            boolean lockAcquired = false;
            try {
                if (!context.inProtectedMode() && !dlock.hasLock()) {
                    dlock.acquire(Lock.READ_LOCK);
                    lockAcquired = true;
                }
                result.add(new NodeProxy(doc)); // , -1, Node.DOCUMENT_NODE));
            } catch (final LockException e) {
                throw new XPathException(e.getMessage());
            } finally {
                if (lockAcquired)
                    {dlock.release(Lock.READ_LOCK);}
            }
        }
        registerUpdateListener();
        if (context.getProfiler().isEnabled())
               {context.getProfiler().end(this, "", result);}
        return result;
    }

    /**
     * @param contextSequence
     * @param contextItem
     * @throws XPathException
     */
    private List<String> getParameterValues(Sequence contextSequence,
            Item contextItem) throws XPathException {
        final List<String> args = new ArrayList<String>(getArgumentCount() + 10);
        for (int i = 0; i < getArgumentCount(); i++) {
            final Sequence seq = getArgument(i).eval(contextSequence, contextItem);
            for (final SequenceIterator j = seq.iterate(); j.hasNext();) {
                final Item next = j.nextItem();
                args.add(next.getStringValue());
            }
        }
        return args;
    }

    protected void registerUpdateListener() {
        if (listener == null) {
            listener = new UpdateListener() {

                public void documentUpdated(DocumentImpl document, int event) {
                    //Nothing to do (previously was cache management)
                }

                public void unsubscribe() {
                    ExtCollection.this.listener = null;
                }

                public void nodeMoved(NodeId oldNodeId, StoredNode newNode) {
                    // not relevant
                }

                public void debug() {
                    LOG.debug("UpdateListener: Line: " + getLine() + ": " +
                        ExtCollection.this.toString());
                }
            };
            context.registerUpdateListener(listener);
        }
    }

    /* (non-Javadoc)
     * @see org.exist.xquery.PathExpr#resetState()
     */
    public void resetState(boolean postOptimization) {
        super.resetState(postOptimization);
        //Nothing more to do (previously was cache management)
    }
}
TOP

Related Classes of org.exist.xquery.functions.fn.ExtCollection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.