    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.jxpath.ri.axes;
    019
    020import org.apache.commons.jxpath.Function;
    021import org.apache.commons.jxpath.JXPathContext;
    022import org.apache.commons.jxpath.NodeSet;
    023import org.apache.commons.jxpath.ri.EvalContext;
    024import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
    025import org.apache.commons.jxpath.ri.QName;
    026import org.apache.commons.jxpath.ri.model.NodePointer;
    027
    028/**
    029 * EvalContext that is used to hold the root node for the path traversal.
    030 */
    031public class RootContext extends EvalContext {
    032
    033    /**
    034     * Unknown value marker.
    035     */
    036    public static final Object UNKNOWN_VALUE = new Object();
    037
    038    private static final int MAX_REGISTER = 4;
    039    private final JXPathContextReferenceImpl jxpathContext;
    040    private final NodePointer pointer;
    041    private Object[] registers;
    042    private int availableRegister;
    043
    044    /**
    045     * Constructs a new RootContext.
    046     *
    047     * @param jxpathContext context
    048     * @param pointer       pointer
    049     */
    050    public RootContext(final JXPathContextReferenceImpl jxpathContext, final NodePointer pointer) {
    051        super(null);
    052        this.jxpathContext = jxpathContext;
    053        this.pointer = pointer;
    054        if (pointer != null) {
    055            pointer.setNamespaceResolver(jxpathContext.getNamespaceResolver());
    056        }
    057    }
    058
    059    /**
    060     * Gets absolute root context
    061     *
    062     * @return EvalContext
    063     */
    064    public EvalContext getAbsoluteRootContext() {
    065        return jxpathContext.getAbsoluteRootContext();
    066    }
    067
    068    /**
    069     * Gets a context that points to the specified object.
    070     *
    071     * @param constant object
    072     * @return EvalContext
    073     */
    074    public EvalContext getConstantContext(final Object constant) {
    075        if (constant instanceof NodeSet) {
    076            return new NodeSetContext(new RootContext(jxpathContext, null), (NodeSet) constant);
    077        }
    078        NodePointer pointer;
    079        if (constant instanceof NodePointer) {
    080            pointer = (NodePointer) constant;
    081        } else {
    082            pointer = NodePointer.newNodePointer(new QName(null, ""), constant, null);
    083        }
    084        return new InitialContext(new RootContext(jxpathContext, pointer));
    085    }
    086
    087    @Override
    088    public NodePointer getCurrentNodePointer() {
    089        return pointer;
    090    }
    091
    092    @Override
    093    public int getCurrentPosition() {
    094        throw new UnsupportedOperationException();
    095    }
    096
    097    /**
    098     * Gets the specified function from the context.
    099     *
    100     * @param functionName QName
    101     * @param parameters   Object[]
    102     * @return Function
    103     */
    104    public Function getFunction(final QName functionName, final Object[] parameters) {
    105        return jxpathContext.getFunction(functionName, parameters);
    106    }
    107
    108    @Override
    109    public JXPathContext getJXPathContext() {
    110        return jxpathContext;
    111    }
    112
    113    /**
    114     * Gets a registered value.
    115     *
    116     * @param id int
    117     * @return Object
    118     */
    119    public Object getRegisteredValue(final int id) {
    120        if (registers == null || id >= MAX_REGISTER || id == -1) {
    121            return UNKNOWN_VALUE;
    122        }
    123        return registers[id];
    124    }
    125
    126    @Override
    127    public RootContext getRootContext() {
    128        return this;
    129    }
    130
    131    @Override
    132    public Object getValue() {
    133        return pointer;
    134    }
    135
    136    /**
    137     * Gets variable context.
    138     *
    139     * @param variableName variable name
    140     * @return EvalContext
    141     */
    142    public EvalContext getVariableContext(final QName variableName) {
    143        return new InitialContext(new RootContext(jxpathContext, jxpathContext.getVariablePointer(variableName)));
    144    }
    145
    146    @Override
    147    public boolean nextNode() {
    148        throw new UnsupportedOperationException();
    149    }
    150
    151    @Override
    152    public boolean nextSet() {
    153        throw new UnsupportedOperationException();
    154    }
    155
    156    @Override
    157    public boolean setPosition(final int position) {
    158        throw new UnsupportedOperationException();
    159    }
    160
    161    /**
    162     * Sets the next registered value.
    163     *
    164     * @param value Object
    165     * @return the id that can reclaim value.
    166     */
    167    public int setRegisteredValue(final Object value) {
    168        if (registers == null) {
    169            registers = new Object[MAX_REGISTER];
    170            for (int i = 0; i < MAX_REGISTER; i++) {
    171                registers[i] = UNKNOWN_VALUE;
    172            }
    173        }
    174        if (availableRegister >= MAX_REGISTER) {
    175            return -1;
    176        }
    177        registers[availableRegister] = value;
    178        availableRegister++;
    179        return availableRegister - 1;
    180    }
    181
    182    @Override
    183    public String toString() {
    184        return super.toString() + ":" + pointer.asPath();
    185    }
    186}