    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.configuration2.tree.xpath;
    018
    019import java.util.Locale;
    020
    021import org.apache.commons.configuration2.tree.NodeHandler;
    022import org.apache.commons.jxpath.ri.QName;
    023import org.apache.commons.jxpath.ri.model.NodePointer;
    024import org.apache.commons.jxpath.ri.model.NodePointerFactory;
    025
    026/**
    027 * <p>
    028 * Implementation of the {@code NodePointerFactory} interface for configuration
    029 * nodes.
    030 * </p>
    031 * <p>
    032 * This class is able to create {@code NodePointer}s for the nodes of
    033 * hierarchical configurations. Because there is no common base class for
    034 * configuration nodes (any specific configuration implementation can use its
    035 * own node class) a trick is needed for activating this factory for a concrete
    036 * JXPath query: The {@code wrapNode()} method has to be called with the node
    037 * object and its corresponding {@code NodeHandler}. This creates a wrapper
    038 * object containing all information required by the factory for processing a
    039 * query. Then this wrapper object has to be passed to the query methods of the
    040 * JXPath context.
    041 * </p>
    042 *
    043 * @since 1.3
    044 * @version $Id: ConfigurationNodePointerFactory.java 1842194 2018-09-27 22:24:23Z ggregory $
    045 */
    046public class ConfigurationNodePointerFactory implements NodePointerFactory
    047{
    048    /** Constant for the order of this factory. */
    049    public static final int CONFIGURATION_NODE_POINTER_FACTORY_ORDER = 200;
    050
    051    /**
    052     * Returns the order of this factory between other factories.
    053     *
    054     * @return this order's factory
    055     */
    056    @Override
    057    public int getOrder()
    058    {
    059        return CONFIGURATION_NODE_POINTER_FACTORY_ORDER;
    060    }
    061
    062    /**
    063     * Creates a node pointer for the specified bean. If the bean is a
    064     * configuration node (indicated by a wrapper object), a corresponding
    065     * pointer is returned.
    066     *
    067     * @param name the name of the node
    068     * @param bean the bean
    069     * @param locale the locale
    070     * @return a pointer for a configuration node if the bean is such a node
    071     */
    072    @Override
    073    @SuppressWarnings("unchecked")
    074    /* Type casts are safe here; because of the way the NodeWrapper was
    075       constructed the node handler must be compatible with the node.
    076     */
    077    public NodePointer createNodePointer(final QName name, final Object bean, final Locale locale)
    078    {
    079        if (bean instanceof NodeWrapper)
    080        {
    081            final NodeWrapper<?> wrapper = (NodeWrapper<?>) bean;
    082            return new ConfigurationNodePointer(wrapper.getNode(),
    083                    locale, wrapper.getNodeHandler());
    084        }
    085        return null;
    086    }
    087
    088    /**
    089     * Creates a node pointer for the specified bean. If the bean is a
    090     * configuration node, a corresponding pointer is returned.
    091     *
    092     * @param parent the parent node
    093     * @param name the name
    094     * @param bean the bean
    095     * @return a pointer for a configuration node if the bean is such a node
    096     */
    097    @Override
    098    @SuppressWarnings("unchecked")
    099    /* Type casts are safe here, see above. Also, the hierarchy of node
    100       pointers is consistent, so a parent is compatible to a child.
    101     */
    102    public NodePointer createNodePointer(final NodePointer parent, final QName name,
    103            final Object bean)
    104    {
    105        if (bean instanceof NodeWrapper)
    106        {
    107            final NodeWrapper<?> wrapper = (NodeWrapper<?>) bean;
    108            return new ConfigurationNodePointer((ConfigurationNodePointer) parent,
    109                    wrapper.getNode(), wrapper.getNodeHandler());
    110        }
    111        return null;
    112    }
    113
    114    /**
    115     * Creates a node wrapper for the specified node and its handler. This
    116     * wrapper has to be passed to the JXPath context instead of the original
    117     * node.
    118     *
    119     * @param <T> the type of the node
    120     * @param node the node
    121     * @param handler the corresponding node handler
    122     * @return a wrapper for this node
    123     */
    124    public static <T> Object wrapNode(final T node, final NodeHandler<T> handler)
    125    {
    126        return new NodeWrapper<>(node, handler);
    127    }
    128
    129    /**
    130     * An internally used wrapper class that holds all information for
    131     * processing a query for a specific node.
    132     *
    133     * @param <T> the type of the nodes this class deals with
    134     */
    135    static class NodeWrapper<T>
    136    {
    137        /** Stores the node. */
    138        private final T node;
    139
    140        /** Stores the corresponding node handler. */
    141        private final NodeHandler<T> nodeHandler;
    142
    143        /**
    144         * Creates a new instance of {@code NodeWrapper} and initializes it.
    145         *
    146         * @param nd the node
    147         * @param handler the node handler
    148         */
    149        public NodeWrapper(final T nd, final NodeHandler<T> handler)
    150        {
    151            node = nd;
    152            nodeHandler = handler;
    153        }
    154
    155        /**
    156         * Returns the wrapped node.
    157         *
    158         * @return the node
    159         */
    160        public T getNode()
    161        {
    162            return node;
    163        }
    164
    165        /**
    166         * Returns the node handler for the wrapped node.
    167         *
    168         * @return the node handler
    169         */
    170        public NodeHandler<T> getNodeHandler()
    171        {
    172            return nodeHandler;
    173        }
    174    }
    175}