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