/*
* The MIT License
*
* Copyright 2011 Sony Ericsson Mobile Communications. All rights reserved.
* Copyright 2012 Sony Mobile Communications AB. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.sonyericsson.hudson.plugins.metadata.model.values;
import com.sonyericsson.hudson.plugins.metadata.model.Metadata;
import com.sonyericsson.hudson.plugins.metadata.model.MetadataContainer;
import com.sonyericsson.hudson.plugins.metadata.model.MetadataParent;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
/**
* Utility methods for easier creation of tree structures of values.
*
* @author Robert Sandell <robert.sandell@sonyericsson.com>
*/
public abstract class TreeStructureUtil {
/**
* Private utility constructor.
*/
private TreeStructureUtil() {
}
/**
* Adds a {@link StringMetadataValue} to the root node with the specified path.
*
* @param root the root to add the tree to.
* @param value the string value of the leaf node.
* @param description the description of the leaf node.
* @param path the path to the leaf from the root.
* @return true if there was no merge conflicts.
*/
public static boolean addValue(MetadataParent root, String value, String description, String... path) {
return addValue(root, value, description, true, false, path);
}
/**
* Adds a {@link StringMetadataValue} to the root node with the specified path.
*
* @param root the root to add the tree to.
* @param value the string value of the leaf node.
* @param description the description of the leaf node.
* @param generated what the value's
* {@link com.sonyericsson.hudson.plugins.metadata.model.values.MetadataValue#isGenerated()}
* should be.
* @param exposedToEnvironment if this value should be exposed to the build as an
* environment variable.
* @param path the path to the leaf from the root.
* @return true if there was no merge conflicts.
*/
public static boolean addValue(MetadataParent root, String value, String description,
boolean generated, boolean exposedToEnvironment, String... path) {
StringMetadataValue sVal = new StringMetadataValue(path[path.length - 1], description, value,
exposedToEnvironment);
sVal.setGenerated(generated);
return addValue(root, sVal, generated, Arrays.copyOf(path, path.length - 1));
}
/**
* Adds a {@link DateMetadataValue} to the root node with the specified path.
*
* @param root the root to add the tree to.
* @param value the date value of the leaf node.
* @param description the description of the leaf node.
* @param timeDetailsEnabled true if the value has TimeDetails.
* @param exposedToEnvironment if this value should be exposed to the build as an
* environment variable.
* @param path the path to the leaf from the root.
* @return true if there was no merge conflicts.
*/
public static boolean addValue(MetadataParent root, Calendar value, String description, boolean timeDetailsEnabled,
boolean exposedToEnvironment, String... path) {
DateMetadataValue sVal = new DateMetadataValue(path[path.length - 1],
description, value, timeDetailsEnabled, exposedToEnvironment);
sVal.setGenerated(true);
return addValue(root, sVal, Arrays.copyOf(path, path.length - 1));
}
/**
* Adds a value with the specified path to the root.
*
* @param root the root to add the tree to.
* @param value the value of the leaf.
* @param parentPath the path of the parent of the leaf from the root.
* @return true if there was no merge conflicts.
*/
public static boolean addValue(MetadataParent root, AbstractMetadataValue value, String... parentPath) {
return addValue(root, value, true, parentPath);
}
/**
* Adds a value with the specified path to the root.
*
* @param root the root to add the tree to.
* @param value the value of the leaf.
* @param generated the parentPath should be marked as generated or not.
* @param parentPath the path of the parent of the leaf from the root.
* @return true if there was no merge conflicts.
*/
public static boolean addValue(MetadataParent root, AbstractMetadataValue value,
boolean generated, String... parentPath) {
if (parentPath == null || parentPath.length <= 0) {
return root.addChild(value) == null;
} else {
TreeNodeMetadataValue path = createPath(value, generated, parentPath);
return root.addChild(path) == null;
}
}
/**
* Creates a path where the last element is a string with the provided value and description.
*
* @param value the value
* @param description the description
* @param path the full path to the leaf.
* @return the tree.
*/
public static TreeNodeMetadataValue createPath(String value, String description, String... path) {
return createPath(value, description, true, false, path);
}
/**
* Creates a path where the last element is a string with the provided value and description.
*
* @param value the value
* @param description the description
* @param generated what the value's
* {@link com.sonyericsson.hudson.plugins.metadata.model.values.MetadataValue#isGenerated()}
* should be.
* @param exposedToEnvironment if this value should be exposed to the build as an
* environment variable.
* @param path the full path to the leaf.
* @return the tree.
*/
public static TreeNodeMetadataValue createPath(String value, String description, boolean generated,
boolean exposedToEnvironment, String... path) {
StringMetadataValue str = new StringMetadataValue(path[path.length - 1], description, value,
exposedToEnvironment);
str.setGenerated(generated);
return createPath(str, generated, Arrays.copyOf(path, path.length - 1));
}
/**
* Creates a path where the last element is a string with the provided value and description.
*
* @param value the value
* @param description the description
* @param timeDetailsEnabled true if TimeDetails should exist for the value.
* @param exposedToEnvironment if this value should be exposed to the build as an
* environment variable.
* @param path the full path to the leaf.
* @return the tree.
*/
public static TreeNodeMetadataValue createPath(Calendar value, String description, boolean timeDetailsEnabled,
boolean exposedToEnvironment, String... path) {
DateMetadataValue val = new DateMetadataValue(path[path.length - 1], description, value,
timeDetailsEnabled, exposedToEnvironment);
val.setGenerated(true);
return createPath(val, Arrays.copyOf(path, path.length - 1));
}
/**
* Creates a tree structured path with the provided leaf at the end. The value's {@link
* com.sonyericsson.hudson.plugins.metadata.model.values.MetadataValue#isGenerated()} will be true.
*
* @param leaf the leaf to put in the end.
* @param parentPath the path to the leaf.
* @return the root node of the path.
*/
public static TreeNodeMetadataValue createPath(AbstractMetadataValue leaf, String... parentPath) {
return createPath(leaf, true, parentPath);
}
/**
* Creates a tree structured path with the provided leaf at the end.
*
* @param leaf the leaf to put in the end.
* @param generated what the value's
* {@link com.sonyericsson.hudson.plugins.metadata.model.values.MetadataValue#isGenerated()}
* should be.
* @param parentPath the path to the leaf.
* @return the root node of the path.
*/
public static TreeNodeMetadataValue createPath(AbstractMetadataValue leaf, boolean generated, String... parentPath) {
if (parentPath == null || parentPath.length < 1) {
throw new IllegalArgumentException("The leaf must have at least one parent.");
}
TreeNodeMetadataValue root = null;
TreeNodeMetadataValue parent = null;
for (String name : parentPath) {
TreeNodeMetadataValue val = new TreeNodeMetadataValue(name);
val.setGenerated(generated);
if (parent != null) {
parent.addChild(val);
}
parent = val;
if (root == null) {
root = val;
}
}
parent.addChild(leaf);
return root;
}
/**
* Creates a straight tree-path. The method returns an array where index 0 is the root and index 1 is the leaf. The
* value's {@link com.sonyericsson.hudson.plugins.metadata.model.values.MetadataValue#isGenerated()} will be true.
*
* @param description the description of the root.
* @param path the path to create.
* @return the root and the leaf.
*/
public static TreeNodeMetadataValue[] createTreePath(String description, String... path) {
return createTreePath(description, true, path);
}
/**
* Creates a straight tree-path. The method returns an array where index 0 is the root and index 1 is the leaf.
*
* @param description the description of the root.
* @param generated what the value's
* {@link com.sonyericsson.hudson.plugins.metadata.model.values.MetadataValue#isGenerated()}
* should be.
* @param path the path to create.
* @return the root and the leaf.
*/
public static TreeNodeMetadataValue[] createTreePath(String description, boolean generated, String... path) {
TreeNodeMetadataValue[] arr = new TreeNodeMetadataValue[2];
arr[1] = new TreeNodeMetadataValue(path[path.length - 1], description);
arr[1].setGenerated(generated);
arr[0] = createPath(arr[1], generated, Arrays.copyOf(path, path.length - 1));
return arr;
}
/**
* Returns the node with the given path.
*
* @param root the root to start from when searching for the node with the given path.
* @param path the path for which a node should be returned.
* @param <T> The type of metadata.
* @return the value or null if it wasn't found.
*/
public static <T extends Metadata> T getPath(MetadataParent<T> root, String... path) {
if (path == null) {
return null;
}
MetadataParent<T> parent = root;
T currentValue = null;
for (int i = 0; i < path.length; i++) {
String name = path[i];
currentValue = parent.getChild(name);
if (currentValue == null) {
return null;
} else if (i == path.length - 1) {
return currentValue;
} else if (currentValue instanceof MetadataParent) {
parent = (MetadataParent)currentValue;
} else {
return null;
}
}
return null;
}
/**
* Returns the node with the given path.
*
* @param collection a collection of nodes to use as root nodes when searching for the node with the given path.
* @param path the path for which a node should be returned.
* @param <T> The type of metadata.
* @return the value or null if it wasn't found.
*/
public static <T extends Metadata> T getPath(Collection<T> collection, String... path) {
if (path == null || path.length == 0) {
return null;
}
String name = path[0];
for (T metadata : collection) {
if (metadata.getName().equalsIgnoreCase(name)) {
if (path.length == 1) {
return metadata;
}
if (metadata instanceof MetadataParent) {
String[] subPath = Arrays.copyOfRange(path, 1, path.length);
return getPath((MetadataParent<T>)metadata, subPath);
}
}
}
return null;
}
/**
* Returns the leaf with the given path.
*
* @param root the root to start from when searching for the leaf node with the given path.
* @param path the path for which a leaf node should be returned.
* @param <T> The type of metadata.
* @return the leaf or null if it wasn't found or if the path doesn't represent a leaf.
*/
public static <T extends Metadata> T getLeaf(MetadataParent<T> root, String... path) {
T value = getPath(root, path);
if (value == null) {
return null;
} else if (value instanceof MetadataParent) {
return null;
} else {
return value;
}
}
/**
* Returns the leaf with the given path.
*
* @param collection the collection to start from.
* @param path the path for which a leaf node should be returned.
* @param <T> The type of metadata.
* @return the leaf or null if it wasn't found or if the path doesn't represent a leaf.
*/
public static <T extends Metadata> T getLeaf(Collection<T> collection, String... path) {
T value = getPath(collection, path);
if (value == null || value instanceof MetadataParent) {
return null;
}
return value;
}
/**
* Adds all the leaves in the collection to the newCollection.
*
* @param collection the Collection to find the leaves in.
* @param newCollection the result.
* @param <T> the type of Metadata.
*/
public static <T extends Metadata> void findLeaves(Collection<T> collection, Collection<T> newCollection) {
if (collection == null || collection.isEmpty()) {
return;
}
for (Metadata def : collection) {
if (def instanceof MetadataParent) {
Collection children = ((MetadataParent)def).getChildren();
findLeaves(children, newCollection);
} else {
newCollection.add((T)def);
}
}
}
/**
* Prints the value and it's child if any into a structured string.
*
* @param value the value to print
* @param tabs the current level
* @return a pretty string.
*/
public static String prettyPrint(MetadataValue value, String tabs) {
StringBuffer str = new StringBuffer(tabs);
str.append(value.getName()).append("\n");
if (value instanceof MetadataParent) {
MetadataParent node = (MetadataParent)value;
prettyPrint(node.getChildren(), tabs + "\t");
}
return str.toString();
}
/**
* Prints the values and their children if any into a structured string.
*
* @param values the values to print
* @param tabs the current level.
* @return a pretty string.
*/
public static String prettyPrint(Collection<MetadataValue> values, String tabs) {
StringBuffer str = new StringBuffer();
for (MetadataValue subValue : values) {
str.append(prettyPrint(subValue, tabs));
}
return str.toString();
}
/**
* Find the first MetadataContainer that is an ancestor to the given Metadata.
*
* @param metadata the Metadata to find a MetadataContainer for.
* @return the first MetadataContainer ancestor.
*/
public static MetadataContainer getContainer(Metadata metadata) {
MetadataParent currentParent = metadata.getParent();
while (!(currentParent instanceof MetadataContainer)) {
if (currentParent instanceof Metadata) {
currentParent = ((Metadata)currentParent).getParent();
} else {
return null;
}
}
return (MetadataContainer)currentParent;
}
}