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}