1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.xpath;
21  
22  import com.puppycrawl.tools.checkstyle.api.DetailAST;
23  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24  import net.sf.saxon.Configuration;
25  import net.sf.saxon.om.AxisInfo;
26  import net.sf.saxon.om.GenericTreeInfo;
27  import net.sf.saxon.om.NodeInfo;
28  import net.sf.saxon.tree.iter.ArrayIterator;
29  import net.sf.saxon.tree.iter.AxisIterator;
30  import net.sf.saxon.tree.iter.EmptyIterator;
31  import net.sf.saxon.tree.iter.SingleNodeIterator;
32  import net.sf.saxon.tree.util.Navigator;
33  import net.sf.saxon.type.Type;
34  
35  /**
36   * Represents root node of Xpath-tree.
37   *
38   */
39  public class RootNode extends AbstractNode {
40  
41      /** Name of the root element. */
42      private static final String ROOT_NAME = "ROOT";
43  
44      /** Constant for optimization. */
45      private static final AbstractNode[] EMPTY_ABSTRACT_NODE_ARRAY = new AbstractNode[0];
46  
47      /** The ast node. */
48      private final DetailAST detailAst;
49  
50      /**
51       * Creates a new {@code RootNode} instance.
52       *
53       * @param detailAst reference to {@code DetailAST}
54       */
55      public RootNode(DetailAST detailAst) {
56          super(new GenericTreeInfo(Configuration.newConfiguration()));
57          this.detailAst = detailAst;
58  
59          createChildren();
60      }
61  
62      /**
63       * Iterates siblings of the current node and
64       * recursively creates new Xpath-nodes.
65       */
66      private void createChildren() {
67          DetailAST currentChild = detailAst;
68          while (currentChild != null) {
69              final ElementNode child = new ElementNode(this, this, currentChild);
70              addChild(child);
71              currentChild = currentChild.getNextSibling();
72          }
73      }
74  
75      /**
76       * Returns attribute value. Throws {@code UnsupportedOperationException} because root node
77       * has no attributes.
78       * @param namespace namespace
79       * @param localPart actual name of the attribute
80       * @return attribute value
81       */
82      @Override
83      public String getAttributeValue(String namespace, String localPart) {
84          throw throwUnsupportedOperationException();
85      }
86  
87      /**
88       * Returns local part.
89       * @return local part
90       */
91      // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
92      // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
93      @Override
94      public String getLocalPart() {
95          return ROOT_NAME;
96      }
97  
98      /**
99       * Returns type of the node.
100      * @return node kind
101      */
102     @Override
103     public int getNodeKind() {
104         return Type.DOCUMENT;
105     }
106 
107     /**
108      * Returns parent.
109      * @return parent
110      */
111     @Override
112     public NodeInfo getParent() {
113         return null;
114     }
115 
116     /**
117      * Returns root of the tree.
118      * @return root of the tree
119      */
120     @Override
121     public NodeInfo getRoot() {
122         return this;
123     }
124 
125     /**
126      * Returns string value.
127      * @return string value
128      */
129     // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
130     // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
131     @Override
132     public String getStringValue() {
133         return ROOT_NAME;
134     }
135 
136     /**
137      * Determines axis iteration algorithm. Throws {@code UnsupportedOperationException} in case,
138      * when there is no axis iterator for given axisNumber.
139      * @param axisNumber element from {@code AxisInfo}
140      * @return {@code AxisIterator} object
141      */
142     @Override
143     public AxisIterator iterateAxis(byte axisNumber) {
144         final AxisIterator result;
145         switch (axisNumber) {
146             case AxisInfo.ANCESTOR:
147             case AxisInfo.ATTRIBUTE:
148             case AxisInfo.PARENT:
149                 result = EmptyIterator.OfNodes.THE_INSTANCE;
150                 break;
151             case AxisInfo.ANCESTOR_OR_SELF:
152             case AxisInfo.SELF:
153                 try (AxisIterator iterator = SingleNodeIterator.makeIterator(this)) {
154                     result = iterator;
155                 }
156                 break;
157             case AxisInfo.CHILD:
158                 if (hasChildNodes()) {
159                     try (AxisIterator iterator = new ArrayIterator.OfNodes(
160                             getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY))) {
161                         result = iterator;
162                     }
163                 }
164                 else {
165                     result = EmptyIterator.OfNodes.THE_INSTANCE;
166                 }
167                 break;
168             case AxisInfo.DESCENDANT:
169                 if (hasChildNodes()) {
170                     try (AxisIterator iterator =
171                                  new Navigator.DescendantEnumeration(this, false, true)) {
172                         result = iterator;
173                     }
174                 }
175                 else {
176                     result = EmptyIterator.OfNodes.THE_INSTANCE;
177                 }
178                 break;
179             case AxisInfo.DESCENDANT_OR_SELF:
180                 try (AxisIterator iterator =
181                              new Navigator.DescendantEnumeration(this, true, true)) {
182                     result = iterator;
183                 }
184                 break;
185             default:
186                 throw throwUnsupportedOperationException();
187         }
188         return result;
189     }
190 
191     /**
192      * Returns line number.
193      * @return line number
194      */
195     @Override
196     public int getLineNumber() {
197         return detailAst.getLineNo();
198     }
199 
200     /**
201      * Returns column number.
202      * @return column number
203      */
204     @Override
205     public int getColumnNumber() {
206         return detailAst.getColumnNo();
207     }
208 
209     /**
210      * Getter method for token type.
211      * @return token type
212      */
213     @Override
214     public int getTokenType() {
215         return TokenTypes.EOF;
216     }
217 
218     /**
219      * Returns underlying node.
220      * @return underlying node
221      */
222     // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
223     // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
224     @Override
225     public DetailAST getUnderlyingNode() {
226         return detailAst;
227     }
228 
229     /**
230      * Returns UnsupportedOperationException exception.
231      * @return UnsupportedOperationException exception
232      */
233     private static UnsupportedOperationException throwUnsupportedOperationException() {
234         return new UnsupportedOperationException("Operation is not supported");
235     }
236 
237 }