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 * https://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; 018 019import java.util.Collections; 020import java.util.HashSet; 021import java.util.Set; 022 023/** 024 * <p> 025 * A base class for node combiner implementations. 026 * </p> 027 * <p> 028 * A <em>node combiner</em> is an object that knows how two hierarchical node structures can be combined into a single 029 * one. Of course, there are many possible ways of implementing such a combination, for example constructing a union, an 030 * intersection, or an "override" structure (were nodes in the first hierarchy take precedence over nodes in the second 031 * hierarchy). This abstract base class only provides some helper methods and defines the common interface for node 032 * combiners. Concrete sub classes will implement the diverse combination algorithms. 033 * </p> 034 * <p> 035 * For some concrete combiner implementations it is important to distinguish whether a node is a single node or whether 036 * it belongs to a list structure. Alone from the input structures, the combiner will not always be able to make this 037 * decision. So sometimes it may be necessary for the developer to configure the combiner and tell it, which nodes 038 * should be treated as list nodes. For this purpose the {@code addListNode()} method exists. It can be passed the name 039 * of a node, which should be considered a list node. 040 * </p> 041 * 042 * @since 1.3 043 */ 044public abstract class NodeCombiner { 045 046 /** 047 * A default handler object for immutable nodes. This object can be used by derived classes for dealing with nodes. 048 * However, it provides only limited functionality; it supports only operations on child nodes, but no references to 049 * parent nodes. 050 */ 051 protected static final NodeHandler<ImmutableNode> HANDLER = createNodeHandler(); 052 053 /** 054 * Creates a node handler object for immutable nodes which can be used by sub classes to perform advanced operations on 055 * nodes. 056 * 057 * @return the node handler implementation 058 */ 059 private static NodeHandler<ImmutableNode> createNodeHandler() { 060 return new AbstractImmutableNodeHandler() { 061 @Override 062 public ImmutableNode getParent(final ImmutableNode node) { 063 return null; 064 } 065 066 @Override 067 public ImmutableNode getRootNode() { 068 return null; 069 } 070 }; 071 } 072 073 /** Stores a list with node names that are known to be list nodes. */ 074 private final Set<String> listNodes; 075 076 /** 077 * Creates a new instance of {@code NodeCombiner}. 078 */ 079 public NodeCombiner() { 080 listNodes = new HashSet<>(); 081 } 082 083 /** 084 * Adds the name of a node to the list of known list nodes. This means that nodes with this name will never be combined. 085 * 086 * @param nodeName the name to be added 087 */ 088 public void addListNode(final String nodeName) { 089 listNodes.add(nodeName); 090 } 091 092 /** 093 * Combines the hierarchies represented by the given root nodes. This method must be defined in concrete sub classes 094 * with the implementation of a specific combination algorithm. 095 * 096 * @param node1 the first root node 097 * @param node2 the second root node 098 * @return the root node of the resulting combined node structure 099 */ 100 public abstract ImmutableNode combine(ImmutableNode node1, ImmutableNode node2); 101 102 /** 103 * Gets a set with the names of nodes that are known to be list nodes. 104 * 105 * @return a set with the names of list nodes 106 */ 107 public Set<String> getListNodes() { 108 return Collections.unmodifiableSet(listNodes); 109 } 110 111 /** 112 * Checks if a node is a list node. This implementation tests if the given node name is contained in the set of known 113 * list nodes. Derived classes which use different criteria may overload this method. 114 * 115 * @param node the node to be tested 116 * @return a flag whether this is a list node 117 */ 118 public boolean isListNode(final ImmutableNode node) { 119 return listNodes.contains(node.getNodeName()); 120 } 121}