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    /** 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                result = SingleNodeIterator.makeIterator(this);
156                break;
157            case AxisInfo.CHILD:
158                if (hasChildNodes()) {
159                    result = new ArrayIterator.OfNodes(
160                            getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY));
161                }
162                else {
163                    result = EmptyIterator.OfNodes.THE_INSTANCE;
164                }
165                break;
166            case AxisInfo.DESCENDANT:
167                if (hasChildNodes()) {
168                    result = new Navigator.DescendantEnumeration(this, false, true);
169                }
170                else {
171                    result = EmptyIterator.OfNodes.THE_INSTANCE;
172                }
173                break;
174            case AxisInfo.DESCENDANT_OR_SELF:
175                result = new Navigator.DescendantEnumeration(this, true, true);
176                break;
177            default:
178                throw throwUnsupportedOperationException();
179        }
180        return result;
181    }
182
183    /**
184     * Returns line number.
185     * @return line number
186     */
187    @Override
188    public int getLineNumber() {
189        return detailAst.getLineNo();
190    }
191
192    /**
193     * Returns column number.
194     * @return column number
195     */
196    @Override
197    public int getColumnNumber() {
198        return detailAst.getColumnNo();
199    }
200
201    /**
202     * Getter method for token type.
203     * @return token type
204     */
205    @Override
206    public int getTokenType() {
207        return TokenTypes.EOF;
208    }
209
210    /**
211     * Returns underlying node.
212     * @return underlying node
213     */
214    // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
215    // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
216    @Override
217    public DetailAST getUnderlyingNode() {
218        return detailAst;
219    }
220
221    /**
222     * Returns UnsupportedOperationException exception.
223     * @return UnsupportedOperationException exception
224     */
225    private static UnsupportedOperationException throwUnsupportedOperationException() {
226        return new UnsupportedOperationException("Operation is not supported");
227    }
228
229}