/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * LabelNodeImpl.java * Copyright (C) 2009-2010 Aristotle University of Thessaloniki, Thessaloniki, Greece */ package mulan.data; import java.io.Serializable; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import mulan.core.ArgumentNullException; /** * Implementation of {@link LabelNode}, representing a label attribute and its connection * within a hierarchy of labels. * * @author Jozef Vilcek */ @XmlRootElement(name = "label", namespace = LabelsBuilder.LABELS_SCHEMA_NAMESPACE) @XmlAccessorType(XmlAccessType.NONE) @XmlType(name = "labelType", propOrder = {"childrenNodes"}) public class LabelNodeImpl implements LabelNode, Serializable { private static final long serialVersionUID = -7974176487751728557L; @XmlAttribute(required = true) private final String name; @XmlElement(type = LabelNodeImpl.class, name = "label", namespace = LabelsBuilder.LABELS_SCHEMA_NAMESPACE) private final Set<LabelNode> childrenNodes; private LabelNode parentNode; /** * Creates a new instance of {@link LabelNodeImpl}. * @param name the name of the label attribute this node represents */ public LabelNodeImpl(String name) { if (name == null) { throw new ArgumentNullException("name"); } this.name = name; parentNode = null; childrenNodes = new HashSet<LabelNode>(); } /** * Empty constructor needs to be defined because of JAXB. * Not intended for use. */ @SuppressWarnings("unused") private LabelNodeImpl() { name = ""; childrenNodes = new HashSet<LabelNode>(); } /** * Adds the specified {@link LabelNode} to the set of child nodes. * The parent of added node is set to reference this {@link LabelNode} instance. * This indicates that there is a hierarchy between these two {@link LabelNode} nodes. * * @param node the {@link LabelNode} to be removed * @return true if node was actually removed; false node was not in child nodes set * @throws ArgumentNullException if specified {@link LabelNode} parameter is null * @throws IllegalArgumentException if {@link LabelNode} being added has same name as this {@link LabelNode} instance (parent) */ public boolean addChildNode(LabelNode node) { if (node == null) { throw new ArgumentNullException("node"); } if (node.getName().equals(name)) { throw new IllegalArgumentException("The child label node can not have same name as parent."); } if (!childrenNodes.contains(node)) { ((LabelNodeImpl) node).setParent(this); } return childrenNodes.add(node); } /** * Removes the specified {@link LabelNode} from the set of child nodes. * The connection between removed {@link LabelNode} and its {@link LabelNode#getParent()} * * @param node the {@link LabelNode} to be removed * @return true if node was actually removed; false node was not in child nodes set * @throws ArgumentNullException if specified {@link LabelNode} parameter is null */ public boolean removeChildNode(LabelNode node) { if (node == null) { throw new ArgumentNullException("node"); } if (childrenNodes.contains(node)) { for (LabelNode item : childrenNodes) { if (item.equals(node)) { ((LabelNodeImpl) item).setParent(null); break; } } } return childrenNodes.remove(node); } /** * Gets the children of a label * * @return a Set of labels */ public Set<String> getChildrenLabels() { Set<String> labels = new HashSet<String>(); for (LabelNode child : childrenNodes) { labels.add(child.getName()); } return labels; } public Set<String> getDescendantLabels() { Set<String> labels = new HashSet<String>(); if (hasChildren()) { for (LabelNode child : childrenNodes) { labels.addAll(getDescendantLabelsRec(child)); } } return labels; } private Set<String> getDescendantLabelsRec(LabelNode node) { Set<String> labels = new HashSet<String>(); labels.add(node.getName()); if (node.hasChildren()) { for (LabelNode child : node.getChildren()) { labels.addAll(getDescendantLabelsRec(child)); } } return labels; } public Set<LabelNode> getChildren() { return Collections.unmodifiableSet(childrenNodes); } public String getName() { return name; } public LabelNode getParent() { return parentNode; } /** * Sets a node as the parent of this node * * @param node a node to be set as parent */ protected void setParent(LabelNode node) { parentNode = node; } public boolean hasChildren() { return !childrenNodes.isEmpty(); } public boolean hasParent() { return (parentNode == null) ? false : true; } /** * The hash code is computed based on label name attribute, which defines the * identity of the {@link LabelNodeImpl} node. */ @Override public int hashCode() { int hash = 1; hash = hash * 31 + name.hashCode(); return hash; } /** * The two {@link LabelNodeImpl} nodes are equal if the are the same * (points to the same object) of if they returns same {@link #getName()} value. * The name of the labels gives the identity to the {@link LabelNodeImpl}. */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if ((obj == null) || (obj.getClass() != this.getClass())) { return false; } LabelNodeImpl labelNode = (LabelNodeImpl) obj; return name.equals(labelNode.getName()); } }