001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2019 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        if (detailAst != null) {
060            createChildren();
061        }
062    }
063
064    /**
065     * Iterates siblings of the current node and
066     * recursively creates new Xpath-nodes.
067     */
068    private void createChildren() {
069        DetailAST currentChild = detailAst;
070        while (currentChild != null) {
071            final ElementNode child = new ElementNode(this, this, currentChild);
072            addChild(child);
073            currentChild = currentChild.getNextSibling();
074        }
075    }
076
077    /**
078     * Returns attribute value. Throws {@code UnsupportedOperationException} because root node
079     * has no attributes.
080     * @param namespace namespace
081     * @param localPart actual name of the attribute
082     * @return attribute value
083     */
084    @Override
085    public String getAttributeValue(String namespace, String localPart) {
086        throw throwUnsupportedOperationException();
087    }
088
089    /**
090     * Returns local part.
091     * @return local part
092     */
093    // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
094    // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
095    @Override
096    public String getLocalPart() {
097        return ROOT_NAME;
098    }
099
100    /**
101     * Returns type of the node.
102     * @return node kind
103     */
104    @Override
105    public int getNodeKind() {
106        return Type.DOCUMENT;
107    }
108
109    /**
110     * Returns parent.
111     * @return parent
112     */
113    @Override
114    public NodeInfo getParent() {
115        return null;
116    }
117
118    /**
119     * Returns root of the tree.
120     * @return root of the tree
121     */
122    @Override
123    public NodeInfo getRoot() {
124        return this;
125    }
126
127    /**
128     * Returns string value.
129     * @return string value
130     */
131    // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
132    // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
133    @Override
134    public String getStringValue() {
135        return ROOT_NAME;
136    }
137
138    /**
139     * Determines axis iteration algorithm. Throws {@code UnsupportedOperationException} in case,
140     * when there is no axis iterator for given axisNumber.
141     * @param axisNumber element from {@code AxisInfo}
142     * @return {@code AxisIterator} object
143     */
144    @Override
145    public AxisIterator iterateAxis(byte axisNumber) {
146        final AxisIterator result;
147        switch (axisNumber) {
148            case AxisInfo.ANCESTOR:
149            case AxisInfo.ATTRIBUTE:
150            case AxisInfo.PARENT:
151                result = EmptyIterator.OfNodes.THE_INSTANCE;
152                break;
153            case AxisInfo.ANCESTOR_OR_SELF:
154            case AxisInfo.SELF:
155                try (AxisIterator iterator = SingleNodeIterator.makeIterator(this)) {
156                    result = iterator;
157                }
158                break;
159            case AxisInfo.CHILD:
160                if (hasChildNodes()) {
161                    try (AxisIterator iterator = new ArrayIterator.OfNodes(
162                            getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY))) {
163                        result = iterator;
164                    }
165                }
166                else {
167                    result = EmptyIterator.OfNodes.THE_INSTANCE;
168                }
169                break;
170            case AxisInfo.DESCENDANT:
171                if (hasChildNodes()) {
172                    try (AxisIterator iterator =
173                                 new Navigator.DescendantEnumeration(this, false, true)) {
174                        result = iterator;
175                    }
176                }
177                else {
178                    result = EmptyIterator.OfNodes.THE_INSTANCE;
179                }
180                break;
181            case AxisInfo.DESCENDANT_OR_SELF:
182                try (AxisIterator iterator =
183                             new Navigator.DescendantEnumeration(this, true, true)) {
184                    result = iterator;
185                }
186                break;
187            default:
188                throw throwUnsupportedOperationException();
189        }
190        return result;
191    }
192
193    /**
194     * Returns line number.
195     * @return line number
196     */
197    @Override
198    public int getLineNumber() {
199        return detailAst.getLineNo();
200    }
201
202    /**
203     * Returns column number.
204     * @return column number
205     */
206    @Override
207    public int getColumnNumber() {
208        return detailAst.getColumnNo();
209    }
210
211    /**
212     * Getter method for token type.
213     * @return token type
214     */
215    @Override
216    public int getTokenType() {
217        return TokenTypes.EOF;
218    }
219
220    /**
221     * Returns underlying node.
222     * @return underlying node
223     */
224    // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
225    // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
226    @Override
227    public DetailAST getUnderlyingNode() {
228        return detailAst;
229    }
230
231    /**
232     * Returns UnsupportedOperationException exception.
233     * @return UnsupportedOperationException exception
234     */
235    private static UnsupportedOperationException throwUnsupportedOperationException() {
236        return new UnsupportedOperationException("Operation is not supported");
237    }
238
239}