AbstractConfigurationNodeIterator.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.configuration2.tree.xpath;

  18. import org.apache.commons.configuration2.tree.NodeHandler;
  19. import org.apache.commons.jxpath.ri.QName;
  20. import org.apache.commons.jxpath.ri.model.NodeIterator;
  21. import org.apache.commons.jxpath.ri.model.NodePointer;
  22. import org.apache.commons.lang3.StringUtils;

  23. /**
  24.  * <p>
  25.  * A base class for implementing iterators over configuration nodes.
  26.  * </p>
  27.  * <p>
  28.  * This class already provides common functionality for implementing the iteration process. Derived classes will
  29.  * implement specific behavior based on the concrete node type (child node or attribute node).
  30.  * </p>
  31.  *
  32.  * @param <T> the type of the nodes this iterator deals with
  33.  * @since 1.3
  34.  */
  35. abstract class AbstractConfigurationNodeIterator<T> implements NodeIterator {
  36.     /** Constant for the prefix separator. */
  37.     private static final String PREFIX_SEPARATOR = ":";

  38.     /** A format for constructing a node name with a namespace prefix. */
  39.     private static final String FMT_NAMESPACE = "%s" + PREFIX_SEPARATOR + "%s";

  40.     /**
  41.      * Generates a qualified name with a namespace prefix.
  42.      *
  43.      * @param prefix the prefix
  44.      * @param name the name (may be <strong>null</strong>)
  45.      * @return the qualified name
  46.      */
  47.     protected static String prefixName(final String prefix, final String name) {
  48.         return String.format(FMT_NAMESPACE, prefix, StringUtils.defaultString(name));
  49.     }

  50.     /**
  51.      * Returns the qualified name from the given {@code QName}. If the name has no namespace, result is the simple name.
  52.      * Otherwise, the namespace prefix is added.
  53.      *
  54.      * @param qName the {@code QName}
  55.      * @return the qualified name
  56.      */
  57.     protected static String qualifiedName(final QName qName) {
  58.         return qName.getPrefix() == null ? qName.getName() : prefixName(qName.getPrefix(), qName.getName());
  59.     }

  60.     /** Stores the parent node pointer. */
  61.     private final ConfigurationNodePointer<T> parent;

  62.     /** Stores the current position. */
  63.     private int position;

  64.     /** Stores the start offset of the iterator. */
  65.     private int startOffset;

  66.     /** Stores the reverse flag. */
  67.     private final boolean reverse;

  68.     /**
  69.      * Creates a new instance of {@code ConfigurationNodeIteratorBase} and initializes it.
  70.      *
  71.      * @param parent the parent pointer
  72.      * @param reverse the reverse flag
  73.      */
  74.     protected AbstractConfigurationNodeIterator(final ConfigurationNodePointer<T> parent, final boolean reverse) {
  75.         this.parent = parent;
  76.         this.reverse = reverse;
  77.     }

  78.     /**
  79.      * Creates the configuration node pointer for the current position. This method is called by {@code getNodePointer()}.
  80.      * Derived classes must create the correct pointer object.
  81.      *
  82.      * @param position the current position in the iteration
  83.      * @return the node pointer
  84.      */
  85.     protected abstract NodePointer createNodePointer(int position);

  86.     /**
  87.      * Gets the maximum position for this iterator.
  88.      *
  89.      * @return the maximum allowed position
  90.      */
  91.     protected int getMaxPosition() {
  92.         return reverse ? getStartOffset() + 1 : size() - getStartOffset();
  93.     }

  94.     /**
  95.      * Gets the node handler for the managed nodes. This is a convenience method.
  96.      *
  97.      * @return the node handler
  98.      */
  99.     protected NodeHandler<T> getNodeHandler() {
  100.         return getParent().getNodeHandler();
  101.     }

  102.     /**
  103.      * Gets the current node pointer.
  104.      *
  105.      * @return the current pointer in this iteration
  106.      */
  107.     @Override
  108.     public NodePointer getNodePointer() {
  109.         if (getPosition() < 1 && !setPosition(1)) {
  110.             return null;
  111.         }

  112.         return createNodePointer(positionToIndex(getPosition()));
  113.     }

  114.     /**
  115.      * Gets the parent node pointer.
  116.      *
  117.      * @return the parent node pointer
  118.      */
  119.     protected ConfigurationNodePointer<T> getParent() {
  120.         return parent;
  121.     }

  122.     /**
  123.      * Gets the position of the iteration.
  124.      *
  125.      * @return the position
  126.      */
  127.     @Override
  128.     public int getPosition() {
  129.         return position;
  130.     }

  131.     /**
  132.      * Gets the start offset of the iteration.
  133.      *
  134.      * @return the start offset
  135.      */
  136.     protected int getStartOffset() {
  137.         return startOffset;
  138.     }

  139.     /**
  140.      * Returns the index in the data list for the given position. This method also checks the reverse flag.
  141.      *
  142.      * @param pos the position (1-based)
  143.      * @return the corresponding list index
  144.      */
  145.     protected int positionToIndex(final int pos) {
  146.         return (reverse ? 1 - pos : pos - 1) + getStartOffset();
  147.     }

  148.     /**
  149.      * Sets the position of the iteration.
  150.      *
  151.      * @param pos the new position
  152.      * @return a flag if this is a valid position
  153.      */
  154.     @Override
  155.     public boolean setPosition(final int pos) {
  156.         position = pos;
  157.         return pos >= 1 && pos <= getMaxPosition();
  158.     }

  159.     /**
  160.      * Sets the start offset of the iteration. This is used when a start element was set.
  161.      *
  162.      * @param startOffset the start offset
  163.      */
  164.     protected void setStartOffset(final int startOffset) {
  165.         this.startOffset = startOffset;
  166.         if (reverse) {
  167.             this.startOffset--;
  168.         } else {
  169.             this.startOffset++;
  170.         }
  171.     }

  172.     /**
  173.      * Returns the number of elements in this iteration.
  174.      *
  175.      * @return the number of elements
  176.      */
  177.     protected abstract int size();
  178. }