    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 */
    045public class ConfigurationNodePointerFactory implements NodePointerFactory
    046{
    047    /** Constant for the order of this factory. */
    048    public static final int CONFIGURATION_NODE_POINTER_FACTORY_ORDER = 200;
    049
    050    /**
    051     * Returns the order of this factory between other factories.
    052     *
    053     * @return this order's factory
    054     */
    055    @Override
    056    public int getOrder()
    057    {
    058        return CONFIGURATION_NODE_POINTER_FACTORY_ORDER;
    059    }
    060
    061    /**
    062     * Creates a node pointer for the specified bean. If the bean is a
    063     * configuration node (indicated by a wrapper object), a corresponding
    064     * pointer is returned.
    065     *
    066     * @param name the name of the node
    067     * @param bean the bean
    068     * @param locale the locale
    069     * @return a pointer for a configuration node if the bean is such a node
    070     */
    071    @Override
    072    @SuppressWarnings("unchecked")
    073    /* Type casts are safe here; because of the way the NodeWrapper was
    074       constructed the node handler must be compatible with the node.
    075     */
    076    public NodePointer createNodePointer(final QName name, final Object bean, final Locale locale)
    077    {
    078        if (bean instanceof NodeWrapper)
    079        {
    080            final NodeWrapper<?> wrapper = (NodeWrapper<?>) bean;
    081            return new ConfigurationNodePointer(wrapper.getNode(),
    082                    locale, wrapper.getNodeHandler());
    083        }
    084        return null;
    085    }
    086
    087    /**
    088     * Creates a node pointer for the specified bean. If the bean is a
    089     * configuration node, a corresponding pointer is returned.
    090     *
    091     * @param parent the parent node
    092     * @param name the name
    093     * @param bean the bean
    094     * @return a pointer for a configuration node if the bean is such a node
    095     */
    096    @Override
    097    @SuppressWarnings("unchecked")
    098    /* Type casts are safe here, see above. Also, the hierarchy of node
    099       pointers is consistent, so a parent is compatible to a child.
    100     */
    101    public NodePointer createNodePointer(final NodePointer parent, final QName name,
    102            final Object bean)
    103    {
    104        if (bean instanceof NodeWrapper)
    105        {
    106            final NodeWrapper<?> wrapper = (NodeWrapper<?>) bean;
    107            return new ConfigurationNodePointer((ConfigurationNodePointer) parent,
    108                    wrapper.getNode(), wrapper.getNodeHandler());
    109        }
    110        return null;
    111    }
    112
    113    /**
    114     * Creates a node wrapper for the specified node and its handler. This
    115     * wrapper has to be passed to the JXPath context instead of the original
    116     * node.
    117     *
    118     * @param <T> the type of the node
    119     * @param node the node
    120     * @param handler the corresponding node handler
    121     * @return a wrapper for this node
    122     */
    123    public static <T> Object wrapNode(final T node, final NodeHandler<T> handler)
    124    {
    125        return new NodeWrapper<>(node, handler);
    126    }
    127
    128    /**
    129     * An internally used wrapper class that holds all information for
    130     * processing a query for a specific node.
    131     *
    132     * @param <T> the type of the nodes this class deals with
    133     */
    134    static class NodeWrapper<T>
    135    {
    136        /** Stores the node. */
    137        private final T node;
    138
    139        /** Stores the corresponding node handler. */
    140        private final NodeHandler<T> nodeHandler;
    141
    142        /**
    143         * Creates a new instance of {@code NodeWrapper} and initializes it.
    144         *
    145         * @param nd the node
    146         * @param handler the node handler
    147         */
    148        public NodeWrapper(final T nd, final NodeHandler<T> handler)
    149        {
    150            node = nd;
    151            nodeHandler = handler;
    152        }
    153
    154        /**
    155         * Returns the wrapped node.
    156         *
    157         * @return the node
    158         */
    159        public T getNode()
    160        {
    161            return node;
    162        }
    163
    164        /**
    165         * Returns the node handler for the wrapped node.
    166         *
    167         * @return the node handler
    168         */
    169        public NodeHandler<T> getNodeHandler()
    170        {
    171            return nodeHandler;
    172        }
    173    }
    174}