001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2020 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.xpath;
021
022import com.puppycrawl.tools.checkstyle.api.DetailAST;
023import com.puppycrawl.tools.checkstyle.api.TokenTypes;
024import net.sf.saxon.Configuration;
025import net.sf.saxon.om.AxisInfo;
026import net.sf.saxon.om.GenericTreeInfo;
027import net.sf.saxon.om.NodeInfo;
028import net.sf.saxon.tree.iter.ArrayIterator;
029import net.sf.saxon.tree.iter.AxisIterator;
030import net.sf.saxon.tree.iter.EmptyIterator;
031import net.sf.saxon.tree.iter.SingleNodeIterator;
032import net.sf.saxon.tree.util.Navigator;
033import net.sf.saxon.type.Type;
034
035/**
036 * Represents root node of Xpath-tree.
037 *
038 */
039public class RootNode extends AbstractNode {
040
041    /** Name of the root element. */
042    private static final String ROOT_NAME = "ROOT";
043
044    /** Constant for optimization. */
045    private static final AbstractNode[] EMPTY_ABSTRACT_NODE_ARRAY = new AbstractNode[0];
046
047    /** The ast node. */
048    private final DetailAST detailAst;
049
050    /**
051     * Creates a new {@code RootNode} instance.
052     *
053     * @param detailAst reference to {@code DetailAST}
054     */
055    public RootNode(DetailAST detailAst) {
056        super(new GenericTreeInfo(Configuration.newConfiguration()));
057        this.detailAst = detailAst;
058
059        createChildren();
060    }
061
062    /**
063     * Compares current object with specified for order.
064     * Throws {@code UnsupportedOperationException} because functionality not required here.
065     * @param nodeInfo another {@code NodeInfo} object
066     * @return number representing order of current object to specified one
067     */
068    @Override
069    public int compareOrder(NodeInfo nodeInfo) {
070        throw throwUnsupportedOperationException();
071    }
072
073    /**
074     * Iterates siblings of the current node and
075     * recursively creates new Xpath-nodes.
076     */
077    private void createChildren() {
078        DetailAST currentChild = detailAst;
079        while (currentChild != null) {
080            final ElementNode child = new ElementNode(this, this, currentChild);
081            addChild(child);
082            currentChild = currentChild.getNextSibling();
083        }
084    }
085
086    /**
087     * Returns attribute value. Throws {@code UnsupportedOperationException} because root node
088     * has no attributes.
089     *
090     * @param namespace namespace
091     * @param localPart actual name of the attribute
092     * @return attribute value
093     */
094    @Override
095    public String getAttributeValue(String namespace, String localPart) {
096        throw throwUnsupportedOperationException();
097    }
098
099    /**
100     * Returns local part.
101     *
102     * @return local part
103     */
104    @Override
105    public String getLocalPart() {
106        return ROOT_NAME;
107    }
108
109    /**
110     * Returns type of the node.
111     *
112     * @return node kind
113     */
114    @Override
115    public int getNodeKind() {
116        return Type.DOCUMENT;
117    }
118
119    /**
120     * Returns parent.
121     *
122     * @return parent
123     */
124    @Override
125    public NodeInfo getParent() {
126        return null;
127    }
128
129    /**
130     * Returns root of the tree.
131     *
132     * @return root of the tree
133     */
134    @Override
135    public NodeInfo getRoot() {
136        return this;
137    }
138
139    /**
140     * Determines axis iteration algorithm. Throws {@code UnsupportedOperationException} in case,
141     * when there is no axis iterator for given axisNumber.
142     *
143     * @param axisNumber element from {@code AxisInfo}
144     * @return {@code AxisIterator} object
145     */
146    @Override
147    public AxisIterator iterateAxis(byte axisNumber) {
148        final AxisIterator result;
149        switch (axisNumber) {
150            case AxisInfo.ANCESTOR:
151            case AxisInfo.ATTRIBUTE:
152            case AxisInfo.PARENT:
153            case AxisInfo.FOLLOWING:
154            case AxisInfo.FOLLOWING_SIBLING:
155            case AxisInfo.PRECEDING:
156            case AxisInfo.PRECEDING_SIBLING:
157                result = EmptyIterator.OfNodes.THE_INSTANCE;
158                break;
159            case AxisInfo.ANCESTOR_OR_SELF:
160            case AxisInfo.SELF:
161                try (AxisIterator iterator = SingleNodeIterator.makeIterator(this)) {
162                    result = iterator;
163                }
164                break;
165            case AxisInfo.CHILD:
166                if (hasChildNodes()) {
167                    try (AxisIterator iterator = new ArrayIterator.OfNodes(
168                            getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY))) {
169                        result = iterator;
170                    }
171                }
172                else {
173                    result = EmptyIterator.OfNodes.THE_INSTANCE;
174                }
175                break;
176            case AxisInfo.DESCENDANT:
177                if (hasChildNodes()) {
178                    try (AxisIterator iterator =
179                                 new Navigator.DescendantEnumeration(this, false, true)) {
180                        result = iterator;
181                    }
182                }
183                else {
184                    result = EmptyIterator.OfNodes.THE_INSTANCE;
185                }
186                break;
187            case AxisInfo.DESCENDANT_OR_SELF:
188                try (AxisIterator iterator =
189                             new Navigator.DescendantEnumeration(this, true, true)) {
190                    result = iterator;
191                }
192                break;
193            default:
194                throw throwUnsupportedOperationException();
195        }
196        return result;
197    }
198
199    /**
200     * Returns line number.
201     *
202     * @return line number
203     */
204    @Override
205    public int getLineNumber() {
206        return detailAst.getLineNo();
207    }
208
209    /**
210     * Returns column number.
211     *
212     * @return column number
213     */
214    @Override
215    public int getColumnNumber() {
216        return detailAst.getColumnNo();
217    }
218
219    /**
220     * Getter method for token type.
221     *
222     * @return token type
223     */
224    @Override
225    public int getTokenType() {
226        return TokenTypes.EOF;
227    }
228
229    /**
230     * Returns underlying node.
231     *
232     * @return underlying node
233     */
234    @Override
235    public DetailAST getUnderlyingNode() {
236        return detailAst;
237    }
238
239    /**
240     * Returns UnsupportedOperationException exception.
241     *
242     * @return UnsupportedOperationException exception
243     */
244    private static UnsupportedOperationException throwUnsupportedOperationException() {
245        return new UnsupportedOperationException("Operation is not supported");
246    }
247
248}