/* $Id: ConfigurationNode.java 988245 2010-08-23 18:39:35Z kwright $ */ /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.manifoldcf.core.interfaces; import java.io.*; import java.util.*; /** This class represents a node in a configuration structure. */ public class ConfigurationNode implements IHierarchyParent { public static final String _rcsid = "@(#)$Id: ConfigurationNode.java 988245 2010-08-23 18:39:35Z kwright $"; // Member variables protected List<ConfigurationNode> children = null; protected Map<String,String> attributes = null; protected String type = null; protected String value = null; // Readonly flag protected boolean readOnly = false; /** Constructor. */ public ConfigurationNode(String type) { this.type = type; } /** Duplication constructor. */ public ConfigurationNode(ConfigurationNode source) { this.type = source.type; this.value = source.value; this.readOnly = source.readOnly; if (source.attributes != null) { Iterator<String> iter = source.attributes.keySet().iterator(); while (iter.hasNext()) { String attribute = iter.next(); String attrValue = source.attributes.get(attribute); if (this.attributes == null) this.attributes = new HashMap<String,String>(); this.attributes.put(attribute,attrValue); } } int i = 0; while (i < source.getChildCount()) { ConfigurationNode child = source.findChild(i++); this.addChild(this.getChildCount(),createNewNode(child)); } } /** Make a new blank node identical in type and class to the current node. *@return the new node. */ protected ConfigurationNode createNewNode() { return new ConfigurationNode(type); } /** Make a new node that is a copy of the specified node. */ protected ConfigurationNode createNewNode(ConfigurationNode source) { return new ConfigurationNode(source); } /** Make this node (and its children) read-only */ public void makeReadOnly() { if (readOnly) return; if (children != null) { int i = 0; while (i < children.size()) { ConfigurationNode child = (ConfigurationNode)children.get(i++); child.makeReadOnly(); } } readOnly = true; } /** Create a duplicate of the current node. *@return the duplicate */ protected ConfigurationNode createDuplicate(boolean readOnly) { if (readOnly && this.readOnly) return this; ConfigurationNode rval = createNewNode(); rval.value = value; if (attributes != null) rval.attributes = cloneAttributes(attributes); if (children != null) { rval.children = new ArrayList<ConfigurationNode>(); int i = 0; while (i < children.size()) { ConfigurationNode node = children.get(i++); rval.children.add(node.createDuplicate(readOnly)); } } rval.readOnly = readOnly; return rval; } /** Get type. *@return the node type. */ public String getType() { return type; } /** Set value. *@param value is the value to set. */ public void setValue(String value) { if (readOnly) throw new IllegalStateException("Attempt to change read-only object"); this.value = value; } /** Get value. *@return the value. */ public String getValue() { return value; } /** Get child count. *@return the count. */ public int getChildCount() { if (children == null) return 0; return children.size(); } /** Get child n. *@param index is the child number. *@return the child node. */ public ConfigurationNode findChild(int index) { return children.get(index); } /** Remove child n. *@param index is the child to remove. */ public void removeChild(int index) { if (readOnly) throw new IllegalStateException("Attempt to change read-only object"); if (children != null) { children.remove(index); if (children.size() == 0) children = null; } } /** Add child at specified position. *@param index is the position to add the child. *@param child is the child to add. */ public void addChild(int index, ConfigurationNode child) { if (readOnly) throw new IllegalStateException("Attempt to change read-only object"); if (children == null) children = new ArrayList<ConfigurationNode>(); children.add(index,child); } /** Clear children. */ public void clearChildren() { if (readOnly) throw new IllegalStateException("Attempt to change read-only object"); children.clear(); } /** Set an attribute. *@param attribute is the name of the attribute. *@param value is the value of the attribute (null to remove it). */ public void setAttribute(String attribute, String value) { if (readOnly) throw new IllegalStateException("Attempt to change read-only object"); if (value == null) { if (attributes != null) { attributes.remove(attribute); if (attributes.size() == 0) attributes = null; } } else { if (attributes == null) attributes = new HashMap(); attributes.put(attribute,value); } } /** Get the attribute count. *@return the attribute count. */ public int getAttributeCount() { if (attributes == null) return 0; else return attributes.size(); } /** Iterate over attributes. *@return the attribute iterator. */ public Iterator<String> getAttributes() { if (attributes == null) return new HashMap<String,String>().keySet().iterator(); return attributes.keySet().iterator(); } /** Get an attribute value. *@param attribute is the name of the attribute. *@return the value. */ public String getAttributeValue(String attribute) { if (attributes == null) return null; return attributes.get(attribute); } /** Calculate a hashcode */ public int hashCode() { int rval = type.hashCode(); if (value != null) rval += value.hashCode(); if (attributes != null) { Iterator<String> iter = attributes.keySet().iterator(); // Make sure this is not sensitive to order! while (iter.hasNext()) { String key = iter.next(); String attrValue = attributes.get(key); rval += key.hashCode() + attrValue.hashCode(); } } if (children != null) { // Do children int i = 0; while (i < children.size()) { rval += children.get(i++).hashCode(); } } return rval; } /** Check if equals */ public boolean equals(Object o) { if (!(o instanceof ConfigurationNode)) return false; ConfigurationNode n = (ConfigurationNode)o; if (((attributes==null)?0:attributes.size()) != ((n.attributes==null)?0:n.attributes.size())) return false; if (((children==null)?0:children.size()) != ((n.children==null)?0:n.children.size())) return false; if (!type.equals(n.type)) return false; if (value == null || n.value == null) { if (value != n.value) return false; } else { if (!value.equals(n.value)) return false; } if (attributes != null && n.attributes != null) { Iterator<String> iter = attributes.keySet().iterator(); while (iter.hasNext()) { String key = iter.next(); String attrValue = attributes.get(key); String nAttrValue = n.attributes.get(key); if (nAttrValue == null || !attrValue.equals(nAttrValue)) return false; } } if (children != null && n.children != null) { int i = 0; while (i < children.size()) { ConfigurationNode child = children.get(i); ConfigurationNode nChild = n.children.get(i); if (!child.equals(nChild)) return false; i++; } } return true; } /** Construct a human-readable string */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("("); sb.append(type); if (value != null) sb.append(":").append(value); if (attributes != null) { Iterator<String> iter = attributes.keySet().iterator(); while (iter.hasNext()) { sb.append(" "); String key = iter.next(); String attrValue = attributes.get(key); sb.append(key).append("='").append(attrValue).append("'"); } } sb.append(" ["); if (children != null) { int i = 0; while (i < children.size()) { if (i > 0) sb.append(", "); ConfigurationNode cn = children.get(i++); sb.append(cn.toString()); } } sb.append("])"); return sb.toString(); } protected static Map<String,String> cloneAttributes(Map<String,String> attributes) { Map<String,String> rval = new HashMap<String,String>(); Iterator<Map.Entry<String,String>> iter = attributes.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String,String> entry = iter.next(); rval.put(entry.getKey(),entry.getValue()); } return rval; } }