All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlbeans.impl.store.Path Maven / Gradle / Ivy

Go to download

The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.

The newest version!
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed 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.xmlbeans.impl.store;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.ref.WeakReference;
import java.math.BigDecimal;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.xmlbeans.impl.common.DefaultClassLoaderResourceLoader;
import org.apache.xmlbeans.impl.common.XPath;
import org.apache.xmlbeans.impl.common.XPath.XPathCompileException;
import org.apache.xmlbeans.impl.common.XPath.ExecutionContext;

import org.apache.xmlbeans.*;
import org.w3c.dom.Node;


// TODO - This class handled query *and* path ... rename it?

public abstract class Path
{
    public static final String PATH_DELEGATE_INTERFACE = "PATH_DELEGATE_INTERFACE";
    public static String _useDelegateForXpath = "use delegate for xpath";
    public static String _useXdkForXpath = "use xdk for xpath";
    public static String _useXqrlForXpath = "use xqrl for xpath";
    public static String _useXbeanForXpath = "use xbean for xpath";
    public static String _forceXqrl2002ForXpathXQuery = "use xqrl-2002 for xpath";

    private static final int USE_XBEAN    = 0x01;
    private static final int USE_XQRL     = 0x02;
    private static final int USE_DELEGATE = 0x04;
    private static final int USE_XQRL2002 = 0x08;
    private static final int USE_XDK      = 0x10;

    private static Map _xbeanPathCache = new WeakHashMap();
    private static Map _xdkPathCache = new WeakHashMap();
    private static Map _xqrlPathCache = new WeakHashMap();
    private static Map _xqrl2002PathCache = new WeakHashMap();

    private static Method _xdkCompilePath;
    private static Method _xqrlCompilePath;
    private static Method _xqrl2002CompilePath;

    private static boolean _xdkAvailable = true;
    private static boolean _xqrlAvailable = true;
    private static boolean _xqrl2002Available = true;

    private static final String _delIntfName;
    private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    static
    {
        String id = "META-INF/services/org.apache.xmlbeans.impl.store.PathDelegate.SelectPathInterface";
        InputStream in = new DefaultClassLoaderResourceLoader().getResourceAsStream(id);

        String name = null;
        if(in != null) {
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                name = br.readLine().trim();
                br.close();
            } catch (Exception e) {
                // set nothing
            }
        }

        _delIntfName = name;
    }

    protected final String _pathKey;

    Path(String key)
    {
        _pathKey = key;
    }


    interface PathEngine
    {
        void release();

        boolean next(Cur c);
    }

    abstract PathEngine execute(Cur c, XmlOptions options);

    //
    //
    //

    static String getCurrentNodeVar(XmlOptions options)
    {
        String currentNodeVar = "this";

        options = XmlOptions.maskNull(options);

        if (options.hasOption(XmlOptions.XQUERY_CURRENT_NODE_VAR)) {
            currentNodeVar = (String) options.get(XmlOptions.XQUERY_CURRENT_NODE_VAR);

            if (currentNodeVar.startsWith("$")) {
                throw new IllegalArgumentException("Omit the '$' prefix for the current node variable");
            }
        }

        return currentNodeVar;
    }

    public static Path getCompiledPath(String pathExpr, XmlOptions options)
    {
        options = XmlOptions.maskNull(options);

        int force =
                options.hasOption(_useDelegateForXpath) ? USE_DELEGATE
                : options.hasOption(_useXqrlForXpath) ? USE_XQRL
                : options.hasOption(_useXdkForXpath) ? USE_XDK
                : options.hasOption(_useXbeanForXpath) ? USE_XBEAN
                : options.hasOption(_forceXqrl2002ForXpathXQuery) ? USE_XQRL2002
                : USE_XBEAN|USE_XQRL|USE_XDK|USE_DELEGATE; //set all bits except XQRL2002
        String delIntfName = 
            options.hasOption(PATH_DELEGATE_INTERFACE) ? 
                (String)options.get(PATH_DELEGATE_INTERFACE) : _delIntfName;

        return getCompiledPath(pathExpr, force, getCurrentNodeVar(options), delIntfName);
    }

    static Path getCompiledPath(String pathExpr, int force,
        String currentVar, String delIntfName)
    {
        Path path = null;
        WeakReference pathWeakRef = null;
        Map namespaces = (force & USE_DELEGATE) != 0 ? new HashMap() : null;
        lock.readLock().lock();
        try {
        if ((force & USE_XBEAN) != 0)
            pathWeakRef = (WeakReference)_xbeanPathCache.get(pathExpr);
        if (pathWeakRef == null && (force & USE_XQRL) != 0)
            pathWeakRef = (WeakReference)_xqrlPathCache.get(pathExpr);
        if (pathWeakRef == null && (force & USE_XDK) != 0)
            pathWeakRef = (WeakReference)_xdkPathCache.get(pathExpr);
        if (pathWeakRef == null && (force & USE_XQRL2002) != 0)
            pathWeakRef = (WeakReference)_xqrl2002PathCache.get(pathExpr);

        if (pathWeakRef!=null)
            path = (Path)pathWeakRef.get();
        if (path != null)
            return path;
        } finally {
            lock.readLock().unlock();
        }
        lock.writeLock().lock();
        try {
        if ((force & USE_XBEAN) != 0) {
            pathWeakRef = (WeakReference)_xbeanPathCache.get(pathExpr);
            if (pathWeakRef != null)
                path = (Path)pathWeakRef.get();
            if (path==null)
            path = getCompiledPathXbean(pathExpr, currentVar, namespaces);
        }
        if (path == null && (force & USE_XQRL) != 0) {
            pathWeakRef = (WeakReference)_xqrlPathCache.get(pathExpr);
            if (pathWeakRef != null)
                path = (Path)pathWeakRef.get();
            if (path==null)
            path = getCompiledPathXqrl(pathExpr, currentVar);
        }
        if (path == null && (force & USE_XDK) != 0) {
            pathWeakRef = (WeakReference)_xdkPathCache.get(pathExpr);
            if (pathWeakRef != null)
                path = (Path)pathWeakRef.get();
            if (path==null)
            path = getCompiledPathXdk(pathExpr, currentVar);
        }
        if (path == null && (force & USE_DELEGATE) != 0) {
            path = getCompiledPathDelegate(pathExpr, currentVar, namespaces, delIntfName);
        }
        if (path == null && (force & USE_XQRL2002) != 0) {
            pathWeakRef = (WeakReference)_xqrl2002PathCache.get(pathExpr);
            if (pathWeakRef != null)
                path = (Path)pathWeakRef.get();
            if (path==null)
            path = getCompiledPathXqrl2002(pathExpr, currentVar);
        }
        if (path == null)
        {
            StringBuffer errMessage = new StringBuffer();
            if ((force & USE_XBEAN) != 0)
                errMessage.append(" Trying XBeans path engine...");
            if ((force & USE_XQRL) != 0)
                errMessage.append(" Trying XQRL...");
            if ((force & USE_XDK) != 0)
                errMessage.append(" Trying XDK...");
            if ((force & USE_DELEGATE) != 0)
                errMessage.append(" Trying delegated path engine...");
            if ((force & USE_XQRL2002) != 0)
                errMessage.append(" Trying XQRL2002...");

            throw new RuntimeException(errMessage.toString() + " FAILED on " + pathExpr);
        }
        } finally {
            lock.writeLock().unlock();
        }
        return path;
    }

    static private Path getCompiledPathXdk(String pathExpr, String currentVar)
    {
        Path path = createXdkCompiledPath(pathExpr, currentVar);
        if (path != null)
            _xdkPathCache.put(path._pathKey, new WeakReference(path));

        return path;
    }

    static private Path getCompiledPathXqrl(String pathExpr, String currentVar)
    {
        Path path = createXqrlCompiledPath(pathExpr, currentVar);
        if (path != null)
            _xqrlPathCache.put(path._pathKey, new WeakReference(path));

        return path;
    }

    static private Path getCompiledPathXqrl2002(String pathExpr, String currentVar)
    {
        Path path = createXqrl2002CompiledPath(pathExpr, currentVar);
        if (path != null)
            _xqrl2002PathCache.put(path._pathKey, new WeakReference(path));

        return path;
    }

    static private Path getCompiledPathXbean(String pathExpr,
        String currentVar, Map namespaces)
    {
        Path path = XbeanPath.create(pathExpr, currentVar, namespaces);
        if (path != null)
            _xbeanPathCache.put(path._pathKey, new WeakReference(path));

        return path;
    }

    static private Path getCompiledPathDelegate(String pathExpr, String currentVar, Map namespaces, String delIntfName)
    {
        Path path = null;
        if ( namespaces == null )
            namespaces = new HashMap();

        try
        {
            XPath.compileXPath(pathExpr, currentVar, namespaces);
        }
        catch (XPath.XPathCompileException e)
        {
            //do nothing, this function is only called to populate the namespaces map
        }

        int offset =
            namespaces.get(XPath._NS_BOUNDARY) == null ?
            0 :
            ((Integer) namespaces.get(XPath._NS_BOUNDARY)).intValue();
        namespaces.remove(XPath._NS_BOUNDARY);
        path = DelegatePathImpl.create(delIntfName,
            pathExpr.substring(offset),
            currentVar,
            namespaces);

        return path;
    }


    public static String compilePath(String pathExpr, XmlOptions options)
    {
        return getCompiledPath(pathExpr, options)._pathKey;
    }

    //
    // Xbean store specific implementation of compiled path
    //

    private static final class XbeanPath extends Path
    {
        static Path create(String pathExpr, String currentVar, Map namespaces)
        {
            try
            {
                return new XbeanPath(pathExpr, currentVar,
                                XPath.compileXPath(pathExpr, currentVar, namespaces));
            }
            catch (XPathCompileException e) {
                return null;
            }
        }

        private XbeanPath(String pathExpr, String currentVar, XPath xpath)
        {
            super(pathExpr);

            _currentVar = currentVar;
            _compiledPath = xpath;
        }

        PathEngine execute(Cur c, XmlOptions options)
        {
            options = XmlOptions.maskNull(options);
            String delIntfName = 
                options.hasOption(PATH_DELEGATE_INTERFACE) ? 
                    (String)options.get(PATH_DELEGATE_INTERFACE) : _delIntfName;

            // The builtin XPath engine works only on containers.  Delegate to
            // xqrl otherwise.  Also, if the path had a //. at the end, the
            // simple xpath engine can't do the generate case, it only handles
            // attrs and elements.

            if (!c.isContainer() || _compiledPath.sawDeepDot())
            {
                int force = USE_DELEGATE | USE_XQRL | USE_XDK;
                return getCompiledPath(_pathKey, force, _currentVar, delIntfName).execute(c, options);
            }
            return new XbeanPathEngine(_compiledPath, c);
        }

        private final String _currentVar;
        private final XPath _compiledPath;
        public Map namespaces;
    }

    private static Path createXdkCompiledPath(String pathExpr, String currentVar)
    {
        if (!_xdkAvailable)
            return null;

        if (_xdkCompilePath == null)
        {
            try
            {
                Class xdkImpl = Class.forName("org.apache.xmlbeans.impl.store.OXQXBXqrlImpl");

                _xdkCompilePath =
                    xdkImpl.getDeclaredMethod("compilePath",
                        new Class[]{String.class, String.class, Boolean.class});
            }
            catch (ClassNotFoundException e)
            {
                _xdkAvailable = false;
                return null;
            }
            catch (Exception e)
            {
                _xdkAvailable = false;
                throw new RuntimeException(e.getMessage(), e);
            }
        }

        Object[] args = new Object[]{pathExpr, currentVar, new Boolean(true)};

        try {
            return (Path) _xdkCompilePath.invoke(null, args);
        }
        catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            throw new RuntimeException(t.getMessage(), t);
        }
        catch (IllegalAccessException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    private static Path createXqrlCompiledPath(String pathExpr, String currentVar)
    {
        if (!_xqrlAvailable)
            return null;

        if (_xqrlCompilePath == null)
        {
            try
            {
                Class xqrlImpl = Class.forName("org.apache.xmlbeans.impl.store.XqrlImpl");

                _xqrlCompilePath =
                        xqrlImpl.getDeclaredMethod("compilePath",
                                new Class[]{String.class, String.class, Boolean.class});
            }
            catch (ClassNotFoundException e)
            {
                _xqrlAvailable = false;
                return null;
            }
            catch (Exception e)
            {
                _xqrlAvailable = false;
                throw new RuntimeException(e.getMessage(), e);
            }
        }

        Object[] args = new Object[]{pathExpr, currentVar, new Boolean(true)};

        try {
            return (Path) _xqrlCompilePath.invoke(null, args);
        }
        catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            throw new RuntimeException(t.getMessage(), t);
        }
        catch (IllegalAccessException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    private static Path createXqrl2002CompiledPath(String pathExpr, String currentVar)
    {
        if (!_xqrl2002Available)
            return null;

        if (_xqrl2002CompilePath == null)
        {
            try
            {
                Class xqrlImpl = Class.forName("org.apache.xmlbeans.impl.store.Xqrl2002Impl");

                _xqrl2002CompilePath =
                    xqrlImpl.getDeclaredMethod("compilePath",
                        new Class[]{String.class, String.class, Boolean.class});
            }
            catch (ClassNotFoundException e)
            {
                _xqrl2002Available = false;
                return null;
            }
            catch (Exception e)
            {
                _xqrl2002Available = false;
                throw new RuntimeException(e.getMessage(), e);
            }
        }

        Object[] args = new Object[]{pathExpr, currentVar, new Boolean(true)};

        try
        {
            return (Path) _xqrl2002CompilePath.invoke(null, args);
        }
        catch (InvocationTargetException e)
        {
            Throwable t = e.getCause();
            throw new RuntimeException(t.getMessage(), t);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    private static final class XbeanPathEngine
        extends ExecutionContext
        implements PathEngine
    {
        XbeanPathEngine(XPath xpath, Cur c)
        {
            assert c.isContainer();

            _version = c._locale.version();
            _cur = c.weakCur(this);

            _cur.push();

            init(xpath);

            int ret = start();

            if ((ret & HIT) != 0)
                c.addToSelection();

            doAttrs(ret, c);

            if ((ret & DESCEND) == 0 || !Locale.toFirstChildElement(_cur))
                release();
        }

        private void advance(Cur c)
        {
            assert _cur != null;

            if (_cur.isFinish())
            {
                if (_cur.isAtEndOfLastPush())
                    release();
                else {
                    end();
                    _cur.next();
                }
            }
            else if (_cur.isElem())
            {
                int ret = element(_cur.getName());

                if ((ret & HIT) != 0)
                    c.addToSelection(_cur);

                doAttrs(ret, c);

                if ((ret & DESCEND) == 0 || !Locale.toFirstChildElement(_cur))
                {
                    end();
                    _cur.skip();
                }
            }
            else
            {
                do
                {
                    _cur.next();
                }
                while(!_cur.isContainerOrFinish());
            }
        }

        private void doAttrs(int ret, Cur c)
        {
            assert _cur.isContainer();

            if ((ret & ATTRS) != 0) {
                if (_cur.toFirstAttr()) {
                    do {
                        if (attr(_cur.getName()))
                            c.addToSelection(_cur);
                    }
                    while (_cur.toNextAttr());

                    _cur.toParent();
                }
            }
        }

        public boolean next(Cur c)
        {
            if (_cur != null && _version != _cur._locale.version())
                throw new ConcurrentModificationException("Document changed during select");

            int startCount = c.selectionCount();

            while (_cur != null) {
                advance(c);

                if (startCount != c.selectionCount())
                    return true;
            }

            return false;
        }

        public void release()
        {
            if (_cur != null) {
                _cur.release();
                _cur = null;
            }
        }

        private final long _version;
        private Cur _cur;
    }

    private static final class DelegatePathImpl
        extends Path
    {
        private PathDelegate.SelectPathInterface _xpathImpl;

        static Path create(String implClassName, String pathExpr, String currentNodeVar, Map namespaceMap)
        {
            assert !currentNodeVar.startsWith("$"); // cezar review with ericvas

            PathDelegate.SelectPathInterface impl =
                    PathDelegate.createInstance(implClassName, pathExpr, currentNodeVar, namespaceMap);
            if (impl == null)
                return null;

            return new DelegatePathImpl(impl, pathExpr);
        }


        private DelegatePathImpl(PathDelegate.SelectPathInterface xpathImpl,
                              String pathExpr)
        {
            super(pathExpr);
            _xpathImpl = xpathImpl;
        }

        protected PathEngine execute(Cur c, XmlOptions options)
        {
            return new DelegatePathEngine(_xpathImpl, c);
        }

        private static class DelegatePathEngine
                extends XPath.ExecutionContext
                implements PathEngine
        {
            // full datetime format: yyyy-MM-dd'T'HH:mm:ss'Z'
            private final DateFormat xmlDateFormat = new SimpleDateFormat("yyyy-MM-dd");

            DelegatePathEngine(PathDelegate.SelectPathInterface xpathImpl,
                               Cur c)
            {
                _engine = xpathImpl;
                _version = c._locale.version();
                _cur = c.weakCur(this);
            }

            public boolean next(Cur c)
            {
                if (!_firstCall)
                    return false;

                _firstCall = false;

                if (_cur != null && _version != _cur._locale.version())
                    throw new ConcurrentModificationException("Document changed during select");

                List resultsList;
                Object context_node;

                context_node = _cur.getDom();
                resultsList = _engine.selectPath(context_node);

                int i;
                for (i = 0; i < resultsList.size(); i++) {
                    //simple type function results
                    Object node = resultsList.get(i);
                    Cur pos = null;
                    if (!(node instanceof Node)) {
                        Object obj = resultsList.get(i);
                        String value;
                        if (obj instanceof Date) {
                            value = xmlDateFormat.format((Date) obj);
                        } else if (obj instanceof BigDecimal) {
                            value = ((BigDecimal)obj).toPlainString();
                        } else {
                            value = obj.toString();
                        }

                        //we cannot leave the cursor's locale, as
                        //everything is done in the selections of this cursor

                        Locale l = c._locale;
                        try {
                            pos = l.load("").tempCur();
                            pos.setValue(value);     
                            SchemaType type = getType(node);
                            Locale.autoTypeDocument(pos, type, null);
                            //move the cur to the actual text
                            pos.next();
                        }
                        catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                    else {
                        assert (node instanceof DomImpl.Dom):
                                "New object created in XPATH!";
                        pos = ((DomImpl.Dom) node).tempCur();

                    }
                    c.addToSelection(pos);
                    pos.release();
                }
                release();
                _engine = null;
                return true;
            }

            private SchemaType getType(Object node)
            {
                SchemaType type;
                if (node instanceof Integer)
                    type = XmlInteger.type;
                else if (node instanceof Double)
                    type = XmlDouble.type;
                else if (node instanceof Long)
                    type = XmlLong.type;
                else if (node instanceof Float)
                    type = XmlFloat.type;
                else if (node instanceof BigDecimal)
                    type = XmlDecimal.type;
                else if (node instanceof Boolean)
                    type = XmlBoolean.type;
                else if (node instanceof String)
                    type = XmlString.type;
                else if (node instanceof Date)
                    type = XmlDate.type;
                else
                    type = XmlAnySimpleType.type;
                return type;
            }

            public void release()
            {
                if (_cur != null) {
                    _cur.release();
                    _cur = null;
                }
            }

            private Cur _cur;
            private PathDelegate.SelectPathInterface _engine;
            private boolean _firstCall = true;
            private long _version;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy