ConfigurationNodePointerFactory.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 java.util.Locale;

  19. import org.apache.commons.configuration2.tree.NodeHandler;
  20. import org.apache.commons.jxpath.ri.QName;
  21. import org.apache.commons.jxpath.ri.model.NodePointer;
  22. import org.apache.commons.jxpath.ri.model.NodePointerFactory;

  23. /**
  24.  * <p>
  25.  * Implements the {@code NodePointerFactory} interface for configuration nodes.
  26.  * </p>
  27.  * <p>
  28.  * This class is able to create {@code NodePointer}s for the nodes of hierarchical configurations. Because there is no
  29.  * common base class for configuration nodes (any specific configuration implementation can use its own node class) a
  30.  * trick is needed for activating this factory for a concrete JXPath query: The {@code wrapNode()} method has to be
  31.  * called with the node object and its corresponding {@code NodeHandler}. This creates a wrapper object containing all
  32.  * information required by the factory for processing a query. Then this wrapper object has to be passed to the query
  33.  * methods of the JXPath context.
  34.  * </p>
  35.  *
  36.  * @since 1.3
  37.  */
  38. public class ConfigurationNodePointerFactory implements NodePointerFactory {
  39.     /**
  40.      * An internally used wrapper class that holds all information for processing a query for a specific node.
  41.      *
  42.      * @param <T> the type of the nodes this class deals with
  43.      */
  44.     static class NodeWrapper<T> {
  45.         /** Stores the node. */
  46.         private final T node;

  47.         /** Stores the corresponding node handler. */
  48.         private final NodeHandler<T> nodeHandler;

  49.         /**
  50.          * Creates a new instance of {@code NodeWrapper} and initializes it.
  51.          *
  52.          * @param nd the node
  53.          * @param handler the node handler
  54.          */
  55.         public NodeWrapper(final T nd, final NodeHandler<T> handler) {
  56.             node = nd;
  57.             nodeHandler = handler;
  58.         }

  59.         /**
  60.          * Gets the wrapped node.
  61.          *
  62.          * @return the node
  63.          */
  64.         public T getNode() {
  65.             return node;
  66.         }

  67.         /**
  68.          * Gets the node handler for the wrapped node.
  69.          *
  70.          * @return the node handler
  71.          */
  72.         public NodeHandler<T> getNodeHandler() {
  73.             return nodeHandler;
  74.         }
  75.     }

  76.     /** Constant for the order of this factory. */
  77.     public static final int CONFIGURATION_NODE_POINTER_FACTORY_ORDER = 200;

  78.     /**
  79.      * Creates a node wrapper for the specified node and its handler. This wrapper has to be passed to the JXPath context
  80.      * instead of the original node.
  81.      *
  82.      * @param <T> the type of the node
  83.      * @param node the node
  84.      * @param handler the corresponding node handler
  85.      * @return a wrapper for this node
  86.      */
  87.     public static <T> Object wrapNode(final T node, final NodeHandler<T> handler) {
  88.         return new NodeWrapper<>(node, handler);
  89.     }

  90.     /**
  91.      * Creates a node pointer for the specified bean. If the bean is a configuration node, a corresponding pointer is
  92.      * returned.
  93.      *
  94.      * @param parent the parent node
  95.      * @param qName the name
  96.      * @param bean the bean
  97.      * @return a pointer for a configuration node if the bean is such a node
  98.      */
  99.     @Override
  100.     @SuppressWarnings("unchecked")
  101.     /*
  102.      * Type casts are safe here, see above. Also, the hierarchy of node pointers is consistent, so a parent is compatible to
  103.      * a child.
  104.      */
  105.     public NodePointer createNodePointer(final NodePointer parent, final QName qName, final Object bean) {
  106.         if (bean instanceof NodeWrapper) {
  107.             final NodeWrapper<Object> wrapper = (NodeWrapper<Object>) bean;
  108.             return new ConfigurationNodePointer<>((ConfigurationNodePointer<Object>) parent, wrapper.getNode(), wrapper.getNodeHandler());
  109.         }
  110.         return null;
  111.     }

  112.     /**
  113.      * Creates a node pointer for the specified bean. If the bean is a configuration node (indicated by a wrapper object), a
  114.      * corresponding pointer is returned.
  115.      *
  116.      * @param qName the name of the node
  117.      * @param bean the bean
  118.      * @param locale the locale
  119.      * @return a pointer for a configuration node if the bean is such a node
  120.      */
  121.     @Override
  122.     @SuppressWarnings("unchecked")
  123.     /*
  124.      * Type casts are safe here; because of the way the NodeWrapper was constructed the node handler must be compatible with
  125.      * the node.
  126.      */
  127.     public NodePointer createNodePointer(final QName qName, final Object bean, final Locale locale) {
  128.         if (bean instanceof NodeWrapper) {
  129.             final NodeWrapper<Object> wrapper = (NodeWrapper<Object>) bean;
  130.             return new ConfigurationNodePointer<>(wrapper.getNode(), locale, wrapper.getNodeHandler());
  131.         }
  132.         return null;
  133.     }

  134.     /**
  135.      * Gets the order of this factory between other factories.
  136.      *
  137.      * @return this order's factory
  138.      */
  139.     @Override
  140.     public int getOrder() {
  141.         return CONFIGURATION_NODE_POINTER_FACTORY_ORDER;
  142.     }
  143. }