All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.javabuilders.Node Maven / Gradle / Ivy

The newest version!
package org.javabuilders;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Represents a node being currently processed
 * @author Jacek Furmankiewicz
 */
public class Node  {

	private Object mainObject = null;
	private Node parent = null;
	private String key = null;

	private Map> childValues = new HashMap>();
	private Set childNodes = new LinkedHashSet();
	
	private Map properties = new HashMap();
	private Set consumedKeys = new HashSet();
	
	private boolean usePreInstantiatedRoot = false;
	private Map customProperties = new HashMap();

	/**
	 * Constructor (for use by Builder only)
	 * @param mainObject Main object being processed
	 * @param properties The list of properties for this object
	 */
	Node(Node parent, String key) {
		this(parent,key,null);
	}
	
	/**
	 * Constructor
	 * @param mainObject Main object being processed
	 * @param properties The list of properties for this object
	 */
	public Node(String key, Map properties) {
		this(null,key, properties);
	}
	
	/**
	 * Constructor
	 * @param parent	Parent node (null is accepted if root)
	 * @param mainObject Main object being processed
	 */
	public Node(Node parent, String key, Map properties) {
		this(parent,key, properties, null);
	}
	
	/**
	 * Constructor
	 * @param parent	Parent node (null is accepted if root)
	 * @param mainObject Main object being processed
	 */
	public Node(Node parent, String key, Map properties, Object mainObject) {
		if (key == null) {
			throw new NullPointerException("key cannot be null");
		}
		this.key = key;
		
		if (properties != null) {
			this.properties = properties;
		}
		
		//automatically add to parent if there is one
		if (parent != null) {
			parent.addChildNode(this);
			this.parent = parent;
		}
		
		if (mainObject != null) {
			this.setMainObject(mainObject);
		}
	}

	
	/**
	 * Returns the optional main object that was created by this node
	 * @return Main object
	 */
	public Object getMainObject() {
		return mainObject;
	}
	
	/**
	 * Sets the optional main object that was created by this node
	 */
	public void setMainObject(Object object) {
		mainObject = object;
	}
	
	/**
	 * @return The parent node (null if root)
	 */
	public Node getParent() {
		return parent;
	}
	
	/**
	 * Returns the list of all the children nodes belonging to this parent
	 * @return
	 */
	public Map> getChildValues() {
		return childValues;
	}
	
	/**
	 * Returns the list of all the children for a specific key
	 * @return
	 */
	public List getChildValues(String key) {
		return childValues.get(key);
	}
	
	/**
	 * Returns the first child value for a specific key
	 * @return
	 */
	public Object getFirstChildValue(String key) {
		return childValues.get(key).get(0);
	}
	
	/**
	 * Registers the child with this parent, grouped under a common key
	 */
	public void addChildValue(String key,Object value) {
		List list = childValues.get(key);
		if (list == null) {
			list = new ArrayList();
			childValues.put(key, list);
		}
		list.add(value);
	}
	
	/**
	 * Returns all child nodes
	 * @return All child nodes
	 */
	public Set getChildNodes() {
		return childNodes;
	}
	
	/**
	 * Returns all child nodes, filtered by class type that was created
	 * @param classFilter Class filter
	 * @return All child nodes
	 */
	public Set getChildNodes(Class classFilter) {
		Set nodes = new LinkedHashSet();
		
		for(Node child : getChildNodes()) {
			if (classFilter.isAssignableFrom(child.getMainObject().getClass())) {
				nodes.add(child);
			}
		}
		
		return nodes;
	}

	
	/**
	 * Helper method to quickly get helper node
	 * @return 
	 */
	public Node getContentNode() {
		return getChildNode(Builder.CONTENT);
	}
	
	/**
	 * Helper method to quickly get children in the content node of a particular
	 * type
	 * @param classFilter Class type to filter on
	 * @return List of relevant child nodes
	 */
	public Set getContentNodes(Class classFilter) {
		Node content = getContentNode();
		if (content != null) {
			return content.getChildNodes(classFilter);
		} else {
			return new HashSet();
		}
	}
	
	/**
	 * Returns the child node identified by a particular key
	 * @param key Key
	 * @return Child node (or null if none found)
	 */
	public Node getChildNode(String key) {
		for(Node node: childNodes) {
			if (node.getKey().equals(key)) {
				return node;
			}
		}
		return null;
	}
	
	/**
	 * Adds a child node
	 * @param node Node
	 */
	public void addChildNode(Node node) {
		childNodes.add(node);
	}

	/**
	 * @return The properties
	 */
	public Map getProperties() {
		return properties;
	}
	
	/**
	 * Shortcut to getProperties().containsKey() for simpler API
	 * @param key 
	 * @return True if contains property, false if not
	 */
	public boolean containsProperty(String key) {
		return getProperties().containsKey(key);
	}
	
	/**
	 * Shortcut to quickly get a string representation of a property value
	 * @param property A list of property aliases
	 * @throws Thrown if the same aliased property is defined multiple times
	 * @return String property value (null if not found)
	 */
	public String getStringProperty(String...propertyAliases) throws BuildException {
		String value = null;
		for(String alias : propertyAliases) {
			if (getProperties().containsKey(alias)) {
				//if the same property's aliases are defined multiple times, we need to throw exception
				if (value == null) {
					Object temp = getProperties().get(alias);
					value = (temp instanceof String) ? (String)temp : String.valueOf(temp);
				} else {
					throw new BuildException("Found multiple alias values for the same property: " + propertyAliases);
				}
			}
		}
		
		return value;
	}
	
	/**
	 * Shortcut to quickly get a Long representation of a property value
	 * @param property A list of property aliases
	 * @throws Thrown if the same aliased property is defined multiple times
	 * @return String property value (null if not found)
	 */
	public Long getLongProperty(String...propertyAliases) throws BuildException {
		Long value = null;
		for(String alias : propertyAliases) {
			if (getProperties().containsKey(alias)) {
				//if the same property's aliases are defined multiple times, we need to throw exception
				if (value == null) {
					value = (Long)getProperties().get(alias);
				} else {
					throw new BuildException("Found multiple alias values for the same property: " + propertyAliases);
				}
			}
		}
		return value;
	}
	
	/**
	 * Shortcut to quickly get an Object representation of a property value
	 * @param property A list of property aliases
	 * @throws Thrown if the same aliased property is defined multiple times
	 * @return String property value (null if not found)
	 */
	public Object getProperty(String...propertyAliases) throws BuildException {
		Object value = null;
		for(String alias : propertyAliases) {
			if (getProperties().containsKey(alias)) {
				//if the same property's aliases are defined multiple times, we need to throw exception
				if (value == null) {
					value = getProperties().get(alias);
				} else {
					throw new BuildException("Found multiple alias values for the same property: " + propertyAliases);
				}
			}
		}
		return value;
	}
	
	/**
	 * Returns if the list of created objects has at least one instance of the
	 * requested class (or its subclasses)
	 * @param type Class type
	 * @return true if found, false if not
	 */
	public boolean containsType(Class type) {
		boolean contains = false;
		for(Node child : getChildNodes()) {
			if (child.getMainObject() != null &&
					type.isAssignableFrom(child.getMainObject().getClass())) {
				contains = true;
				break;
			}
		}
		return contains;
	}
	
	/**
	 * Return the key that this node corresponds to
	 * @return Key
	 */
	public String getKey() {
		return key;
	}

	/**
	 * @return The list of keys/properties of the node that have been consumed by the various property handlers up till now
	 */
	public Set getConsumedKeys() {
		return consumedKeys;
	}
	
	/**
	 * For internal Builder use (when processing collection nodes)
	 * @param consumedKeys
	 */
	void setConsumedKeys(Set consumedKeys) {
		this.consumedKeys = consumedKeys;
	}

	/**
	 * If true, the node should use the preinstantiated root object instead
	 * of creating a new instance
	 * @return the usePreInstantiatedRoot
	 */
	public boolean isUsePreInstantiatedRoot() {
		return usePreInstantiatedRoot;
	}

	/**
	 * Sets a flag telling the node to use the preinstantiated root from
	 * the BuildResult instead of creating a new instance
	 * @param usePreInstantiatedRoot the usePreInstantiatedRoot to set
	 */
	public void setUsePreInstantiatedRoot(boolean usePreInstantiatedRoot) {
		this.usePreInstantiatedRoot = usePreInstantiatedRoot;
	}

	/**
	 * @return Domain-specific custom properties that can be set on a node
	 */
	public Map getCustomProperties() {
		return customProperties;
	}
	
	/**
	 * @param key Key
	 * @return Custom property value
	 */
	public Object getCustomProperty(String key) {
		return customProperties.get(key);
	}

	
	/**
	 * Checks if a custom property is equal to a particular value
	 * @param key Key
	 * @param value Value to compare
	 * @return True if equal, false if not
	 */
	public boolean isCustomPropertyEqualTo(String key,Object value) {
		Object pValue =customProperties.get(key);
		if (pValue == null) {
			return false;
		} else {
			return pValue.equals(value);
		}
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return MessageFormat.format("{0} node: {1}",getKey(), properties); 
	}
}