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