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 19 import java.util.Locale; 20 21 import org.apache.commons.configuration2.tree.NodeHandler; 22 import org.apache.commons.jxpath.ri.QName; 23 import org.apache.commons.jxpath.ri.model.NodePointer; 24 import org.apache.commons.jxpath.ri.model.NodePointerFactory; 25 26 /** 27 * <p> 28 * Implements the {@code NodePointerFactory} interface for configuration nodes. 29 * </p> 30 * <p> 31 * This class is able to create {@code NodePointer}s for the nodes of hierarchical configurations. Because there is no 32 * common base class for configuration nodes (any specific configuration implementation can use its own node class) a 33 * trick is needed for activating this factory for a concrete JXPath query: The {@code wrapNode()} method has to be 34 * called with the node object and its corresponding {@code NodeHandler}. This creates a wrapper object containing all 35 * information required by the factory for processing a query. Then this wrapper object has to be passed to the query 36 * methods of the JXPath context. 37 * </p> 38 * 39 * @since 1.3 40 */ 41 public class ConfigurationNodePointerFactory implements NodePointerFactory { 42 /** 43 * An internally used wrapper class that holds all information for processing a query for a specific node. 44 * 45 * @param <T> the type of the nodes this class deals with 46 */ 47 static class NodeWrapper<T> { 48 /** Stores the node. */ 49 private final T node; 50 51 /** Stores the corresponding node handler. */ 52 private final NodeHandler<T> nodeHandler; 53 54 /** 55 * Creates a new instance of {@code NodeWrapper} and initializes it. 56 * 57 * @param nd the node 58 * @param handler the node handler 59 */ 60 public NodeWrapper(final T nd, final NodeHandler<T> handler) { 61 node = nd; 62 nodeHandler = handler; 63 } 64 65 /** 66 * Gets the wrapped node. 67 * 68 * @return the node 69 */ 70 public T getNode() { 71 return node; 72 } 73 74 /** 75 * Gets the node handler for the wrapped node. 76 * 77 * @return the node handler 78 */ 79 public NodeHandler<T> getNodeHandler() { 80 return nodeHandler; 81 } 82 } 83 84 /** Constant for the order of this factory. */ 85 public static final int CONFIGURATION_NODE_POINTER_FACTORY_ORDER = 200; 86 87 /** 88 * Creates a node wrapper for the specified node and its handler. This wrapper has to be passed to the JXPath context 89 * instead of the original node. 90 * 91 * @param <T> the type of the node 92 * @param node the node 93 * @param handler the corresponding node handler 94 * @return a wrapper for this node 95 */ 96 public static <T> Object wrapNode(final T node, final NodeHandler<T> handler) { 97 return new NodeWrapper<>(node, handler); 98 } 99 100 /** 101 * Creates a node pointer for the specified bean. If the bean is a configuration node, a corresponding pointer is 102 * returned. 103 * 104 * @param parent the parent node 105 * @param qName the name 106 * @param bean the bean 107 * @return a pointer for a configuration node if the bean is such a node 108 */ 109 @Override 110 @SuppressWarnings("unchecked") 111 /* 112 * Type casts are safe here, see above. Also, the hierarchy of node pointers is consistent, so a parent is compatible to 113 * a child. 114 */ 115 public NodePointer createNodePointer(final NodePointer parent, final QName qName, final Object bean) { 116 if (bean instanceof NodeWrapper) { 117 final NodeWrapper<Object> wrapper = (NodeWrapper<Object>) bean; 118 return new ConfigurationNodePointer<>((ConfigurationNodePointer<Object>) parent, wrapper.getNode(), wrapper.getNodeHandler()); 119 } 120 return null; 121 } 122 123 /** 124 * Creates a node pointer for the specified bean. If the bean is a configuration node (indicated by a wrapper object), a 125 * corresponding pointer is returned. 126 * 127 * @param qName the name of the node 128 * @param bean the bean 129 * @param locale the locale 130 * @return a pointer for a configuration node if the bean is such a node 131 */ 132 @Override 133 @SuppressWarnings("unchecked") 134 /* 135 * Type casts are safe here; because of the way the NodeWrapper was constructed the node handler must be compatible with 136 * the node. 137 */ 138 public NodePointer createNodePointer(final QName qName, final Object bean, final Locale locale) { 139 if (bean instanceof NodeWrapper) { 140 final NodeWrapper<Object> wrapper = (NodeWrapper<Object>) bean; 141 return new ConfigurationNodePointer<>(wrapper.getNode(), locale, wrapper.getNodeHandler()); 142 } 143 return null; 144 } 145 146 /** 147 * Gets the order of this factory between other factories. 148 * 149 * @return this order's factory 150 */ 151 @Override 152 public int getOrder() { 153 return CONFIGURATION_NODE_POINTER_FACTORY_ORDER; 154 } 155 }