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 createChildren(); 060 } 061 062 /** 063 * Iterates siblings of the current node and 064 * recursively creates new Xpath-nodes. 065 */ 066 private void createChildren() { 067 DetailAST currentChild = detailAst; 068 while (currentChild != null) { 069 final ElementNode child = new ElementNode(this, this, currentChild); 070 addChild(child); 071 currentChild = currentChild.getNextSibling(); 072 } 073 } 074 075 /** 076 * Returns attribute value. Throws {@code UnsupportedOperationException} because root node 077 * has no attributes. 078 * @param namespace namespace 079 * @param localPart actual name of the attribute 080 * @return attribute value 081 */ 082 @Override 083 public String getAttributeValue(String namespace, String localPart) { 084 throw throwUnsupportedOperationException(); 085 } 086 087 /** 088 * Returns local part. 089 * @return local part 090 */ 091 // -@cs[SimpleAccessorNameNotation] Overrides method from the base class. 092 // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166 093 @Override 094 public String getLocalPart() { 095 return ROOT_NAME; 096 } 097 098 /** 099 * 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 case AxisInfo.FOLLOWING: 150 case AxisInfo.FOLLOWING_SIBLING: 151 case AxisInfo.PRECEDING: 152 case AxisInfo.PRECEDING_SIBLING: 153 result = EmptyIterator.OfNodes.THE_INSTANCE; 154 break; 155 case AxisInfo.ANCESTOR_OR_SELF: 156 case AxisInfo.SELF: 157 try (AxisIterator iterator = SingleNodeIterator.makeIterator(this)) { 158 result = iterator; 159 } 160 break; 161 case AxisInfo.CHILD: 162 if (hasChildNodes()) { 163 try (AxisIterator iterator = new ArrayIterator.OfNodes( 164 getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY))) { 165 result = iterator; 166 } 167 } 168 else { 169 result = EmptyIterator.OfNodes.THE_INSTANCE; 170 } 171 break; 172 case AxisInfo.DESCENDANT: 173 if (hasChildNodes()) { 174 try (AxisIterator iterator = 175 new Navigator.DescendantEnumeration(this, false, true)) { 176 result = iterator; 177 } 178 } 179 else { 180 result = EmptyIterator.OfNodes.THE_INSTANCE; 181 } 182 break; 183 case AxisInfo.DESCENDANT_OR_SELF: 184 try (AxisIterator iterator = 185 new Navigator.DescendantEnumeration(this, true, true)) { 186 result = iterator; 187 } 188 break; 189 default: 190 throw throwUnsupportedOperationException(); 191 } 192 return result; 193 } 194 195 /** 196 * Returns line number. 197 * @return line number 198 */ 199 @Override 200 public int getLineNumber() { 201 return detailAst.getLineNo(); 202 } 203 204 /** 205 * Returns column number. 206 * @return column number 207 */ 208 @Override 209 public int getColumnNumber() { 210 return detailAst.getColumnNo(); 211 } 212 213 /** 214 * Getter method for token type. 215 * @return token type 216 */ 217 @Override 218 public int getTokenType() { 219 return TokenTypes.EOF; 220 } 221 222 /** 223 * Returns underlying node. 224 * @return underlying node 225 */ 226 // -@cs[SimpleAccessorNameNotation] Overrides method from the base class. 227 // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166 228 @Override 229 public DetailAST getUnderlyingNode() { 230 return detailAst; 231 } 232 233 /** 234 * Returns UnsupportedOperationException exception. 235 * @return UnsupportedOperationException exception 236 */ 237 private static UnsupportedOperationException throwUnsupportedOperationException() { 238 return new UnsupportedOperationException("Operation is not supported"); 239 } 240 241}