package sushi.event.collection; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EntityTransaction; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinTable; import javax.persistence.OneToMany; import javax.persistence.Query; import javax.persistence.Table; import sushi.persistence.Persistable; import sushi.persistence.Persistor; /** * @author micha * * @param <T> */ @Entity @Table(name = "SushiTree") public class SushiTree<T> extends Persistable implements Collection<T> { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="SushiTreeID") protected int ID; //essentiell, da sonst keine (leeren) SushiTrees gespeichert werden können @Column(name="Auxiliary") private String auxiliary = "Auxiliary"; @OneToMany(cascade = CascadeType.PERSIST) @JoinTable(name="SushiTree_SushiTreeElements") private List<SushiTreeElement<T>> treeElements = new ArrayList<SushiTreeElement<T>>(); @OneToMany(cascade = CascadeType.PERSIST) @JoinTable(name="SushiTree_SushiTreeRootElements") private List<SushiTreeElement<T>> treeRootElements = new ArrayList<SushiTreeElement<T>>(); public SushiTree() { this.ID = 0; } public SushiTree(T rootElementValue){ assert(rootElementValue != null); SushiTreeElement<T> element = new SushiTreeElement<T>(null, rootElementValue); treeElements = new ArrayList<SushiTreeElement<T>>(); treeRootElements = new ArrayList<SushiTreeElement<T>>(); treeElements.add(element); treeRootElements.add(element); } public T getParent(T treeElementValue){ for(SushiTreeElement<T> currentTreeElement : treeElements){ if(currentTreeElement.getValue() == treeElementValue){ return currentTreeElement.getParent().getValue(); } } return null; } /** * Returns all parents in the tree for the given element. * @param element * @return */ public Set<T> getIndirectParents(T element){ Set<T> parentValues = new HashSet<T>(); SushiTreeElement<T> currentTreeElement = findTreeElementByValue(element); if(currentTreeElement != null){ parentValues.addAll(getIndirectParents(currentTreeElement)); } return parentValues; } private Set<T> getIndirectParents(SushiTreeElement<T> currentTreeElement) { Set<T> parentValues = new HashSet<T>(); if(currentTreeElement.getParent() != null){ parentValues.add(currentTreeElement.getParent().getValue()); parentValues.addAll(getIndirectParents(currentTreeElement.getParent())); } return parentValues; } /** * Returns all elements from the tree, which contain exactly these children. * @param element * @return */ public Set<T> getIndirectParents(Collection<T> children){ Set<T> parentValues = new HashSet<T>(); Set<SushiTreeElement<T>> parents = new HashSet<SushiTreeElement<T>>(); for(SushiTreeElement<T> treeElement : treeElements){ if(treeElement.getChildValues().containsAll(children) && children.containsAll(treeElement.getChildValues())){ parents.add(treeElement); parentValues.add(treeElement.getValue()); } } for(SushiTreeElement<T> parent : parents){ parentValues.addAll(getIndirectParents(parent)); } return parentValues; } /** * Returns all descendants for the given element. * @param element * @return */ public Set<T> getIndirectChildren(T element){ Set<T> childrenValues = new HashSet<T>(); Set<SushiTreeElement<T>> children = new HashSet<SushiTreeElement<T>>(); SushiTreeElement<T> currentTreeElement = findTreeElementByValue(element); if(currentTreeElement != null){ children.addAll(getIndirectChildren(currentTreeElement)); } for(SushiTreeElement<T> child : children){ childrenValues.add(child.getValue()); } return childrenValues; } private Set<SushiTreeElement<T>> getIndirectChildren(SushiTreeElement<T> currentTreeElement) { Set<SushiTreeElement<T>> children = new HashSet<SushiTreeElement<T>>(); for(SushiTreeElement<T> childElement : currentTreeElement.getChildren()){ children.add(childElement); if(childElement.hasChildren()){ children.addAll(getIndirectChildren(childElement)); } } return children; } public List<T> getChildren(T element){ List<T> childrenValues = new ArrayList<T>(); SushiTreeElement<T> currentTreeElement = findTreeElementByValue(element); if(currentTreeElement != null){ for(SushiTreeElement<T> childElement : currentTreeElement.getChildren()){ childrenValues.add(childElement.getValue()); } } return childrenValues; } /** * Returns a list of BPMN elements, which are parents for the specified elements. * @param elements * @return */ public List<T> getParents(Collection<T> elements){ List<T> parentValues = new ArrayList<T>(); for(SushiTreeElement<T> treeElement : treeElements){ List<T> childrenOfElement = this.getChildren(treeElement.getValue()); if(childrenOfElement.containsAll(elements) && elements.containsAll(childrenOfElement)){ parentValues.add(treeElement.getValue()); } } return parentValues; } /** * Returns the values for all elements of the tree that are leaves * (elements that have no children). * @return */ public List<T> getValuesOfLeaves(){ List<T> leafValues = new ArrayList<T>(); for(SushiTreeElement<T> element : treeElements){ if(!element.hasChildren()){ leafValues.add(element.getValue()); } } return leafValues; } /** * Returns all leaf elements descending from the specified element. * @param element * @return */ public Set<T> getLeafs(T element){ Set<T> leaveValues = new HashSet<T>(); SushiTreeElement<T> currentTreeElement = findTreeElementByValue(element); if(currentTreeElement != null){ for(SushiTreeElement<T> treeElement : getIndirectChildren(currentTreeElement)){ if(!treeElement.hasChildren()){ leaveValues.add(treeElement.getValue()); } } } return leaveValues; } /** * Returns all elements of the tree, that have no children. * @return */ public Set<T> getLeafElements(){ Set<T> leaves = new HashSet<T>(); for(SushiTreeElement<T> element : getLeafs()){ leaves.add(element.getValue()); } return leaves; } /** * Returns all tree elements, that have no children. * @return */ private Set<SushiTreeElement<T>> getLeafs(){ Set<SushiTreeElement<T>> leaves = new HashSet<SushiTreeElement<T>>(); for(SushiTreeElement<T> element : treeElements){ if(!element.hasChildren()){ leaves.add(element); } } return leaves; } public boolean isInLeaves(T treeElement){ Set<SushiTreeElement<T>> leaves = getLeafs(); for(SushiTreeElement<T> element : leaves){ if(element.getValue().equals(treeElement)){ return true; } } return false; } public boolean hasChildren(T treeElement){ SushiTreeElement<T> currentTreeElement = findTreeElementByValue(treeElement); return currentTreeElement.hasChildren(); } /** * Adds a child to the specified parent. * @param parent * @param child */ public void addChild(T parent, T child) { SushiTreeElement<T> treeElement = findTreeElementByValue(parent); SushiTreeElement<T> childTreeElement = new SushiTreeElement<T>(treeElement, child); treeElements.add(childTreeElement); if(parent == null){ treeRootElements.add(childTreeElement); } } // public void addChild(T parent, T child, SushiAttributeTypeEnum type) { // // SushiTreeElement<T> treeElement = findTreeElementByValue(parent); // SushiAttribute<T> childTreeElement = new SushiAttribute<T>(treeElement, child, type); // treeElements.add(childTreeElement); // if(parent == null){ // treeRootElements.add(childTreeElement); // } // } /** * Returns true if the parent contains the specified child. * @param parent * @param child */ public boolean containsChild(T parent, T child){ return this.getChildren(parent).contains(child); } public boolean addRootElement(T rootElement){ SushiTreeElement<T> element = new SushiTreeElement<T>(rootElement); treeElements.add(element); return treeRootElements.add(element); } // // public boolean addRootElement(T rootElement, SushiAttributeTypeEnum type){ // SushiAttribute<T> element = new SushiAttribute<T>(null, rootElement, type); // treeElements.add(element); // return treeRootElements.add(element); // } /** * Removes all children from the specified tree element. * @param treeElement * @return */ public void removeChildren(T treeElement){ SushiTreeElement<T> currentTreeElement = findTreeElementByValue(treeElement); List<SushiTreeElement<T>> children = currentTreeElement.getChildren(); treeElements.removeAll(children); currentTreeElement.removeChildren(); } @Override public int size() { return treeElements.size(); } @Override public boolean isEmpty() { return treeElements.isEmpty(); } @Override public boolean contains(Object o) { try{ for(T element : this.getElements()){ if(element.equals(o)){ return true; } } return false; } catch(ClassCastException c){ return false; } } public List<SushiTreeElement<T>> getTreeElements() { return treeElements; } @Override public Iterator<T> iterator() { return getTreeElementValues(treeElements).iterator(); } @Override public Object[] toArray() { return treeElements.toArray(); } @Override public <T> T[] toArray(T[] a) { throw new RuntimeException("Was soll das denn zurückgeben!?"); } @Override public boolean add(T e) { return addRootElement(e); } @Override public boolean remove(Object removeElement) { //TODO: assert(removeElement instanceOf T); SushiTreeElement<T> removeTreeElement = findTreeElementByValue((T) removeElement); return remove(removeTreeElement); } public boolean remove(SushiTreeElement<T> removeTreeElement) { if(removeTreeElement != null){ if(removeTreeElement.hasChildren()){ List<SushiTreeElement<T>> children = new ArrayList<SushiTreeElement<T>>(removeTreeElement.getChildren()); for(SushiTreeElement<T> child : children){ remove(child); } } if (!(removeTreeElement.getParent() == null)){ removeTreeElement.getParent().getChildren().remove(removeTreeElement); } return (treeElements.remove(removeTreeElement) && treeRootElements.remove(removeTreeElement)); } return false; } /** * @author tsun * * @param parent Will be removed as well if it has no childs. * @param child */ public boolean removeChild(T parent, T child) { SushiTreeElement<T> parentElement; parentElement = findTreeRootElementByValue(parent); if(parentElement == null){ parentElement = findTreeElementByValue(parent); } if(parentElement != null){ if(parentElement.hasChildren()){ List<SushiTreeElement<T>> children = new ArrayList<SushiTreeElement<T>>(parentElement.getChildren()); for(SushiTreeElement<T> childTreeElement : children){ if(childTreeElement.getValue().equals(child)){ remove(childTreeElement); if(!parentElement.hasChildren()){ remove(parentElement); } return (treeElements.remove(childTreeElement) && treeElements.remove(parentElement) && treeRootElements.remove(parentElement)); } } } } return false; } /** * @author tsun * * @param parent Will not be removed in any case. * @param child */ public boolean removeChildOnly(T parent, T child) { SushiTreeElement<T> parentElement; parentElement = findTreeRootElementByValue(parent); if(parentElement == null){ parentElement = findTreeElementByValue(parent); } if(parentElement != null){ if(parentElement.hasChildren()){ List<SushiTreeElement<T>> children = new ArrayList<SushiTreeElement<T>>(parentElement.getChildren()); for(SushiTreeElement<T> childTreeElement : children){ if(childTreeElement.getValue().equals(child)){ remove(childTreeElement); return (treeElements.remove(childTreeElement) && treeElements.remove(parentElement) && treeRootElements.remove(parentElement)); } } } } return false; } @Override public boolean containsAll(Collection<?> c) { return getTreeElementValues(treeElements).containsAll(c); } @Override public boolean addAll(Collection<? extends T> collection) { boolean success = true; for(T element : collection){ success = success ? (this.addRootElement(element)) : false; } return success; } @Override public boolean removeAll(Collection<?> collection) { boolean removeSuccess = true; for(Object element : collection){ boolean elementRemoveSuccess = collection.remove(element); removeSuccess = removeSuccess ? elementRemoveSuccess : false; } return removeSuccess; } @Override public boolean retainAll(Collection<?> collection) { boolean retainSuccess = true; // TODO: assert(collection instanceof T); List<SushiTreeElement<T>> copyTreeList = new ArrayList<SushiTreeElement<T>>(treeElements); for(SushiTreeElement<T> element : copyTreeList){ if(!collection.contains(element.getValue())){ remove(element.getValue()); } } return retainSuccess; } @Override public void clear() { treeElements.clear(); treeRootElements.clear(); } private ArrayList<T> getTreeElementValues(List<SushiTreeElement<T>>treeElements) { ArrayList<T> valueElements = new ArrayList<T>(); for(SushiTreeElement<T> element : treeElements){ valueElements.add(element.getValue()); } return valueElements; } private SushiTreeElement<T> findTreeElementByValue(T treeElementValue){ if(treeElementValue == null){ return null; } for(SushiTreeElement<T> currentTreeElement : treeElements){ if(currentTreeElement.getValue().equals(treeElementValue)){ return currentTreeElement; } } return null; } private List<SushiTreeElement<T>> findTreeElementsByValue(T treeElementValue){ if(treeElementValue == null){ return null; } List<SushiTreeElement<T>> elements = new ArrayList<SushiTreeElement<T>>(); for(SushiTreeElement<T> currentTreeElement : treeElements){ if(currentTreeElement.getValue().equals(treeElementValue)){ elements.add(currentTreeElement); } } return elements; } public boolean isHierarchical() { return (! treeRootElements.containsAll(treeElements)); } private SushiTreeElement<T> findTreeRootElementByValue(T treeElementValue){ if(treeElementValue == null){ return null; } for(SushiTreeElement<T> currentTreeElement : treeRootElements){ if(currentTreeElement.getValue().equals(treeElementValue)){ return currentTreeElement; } } return null; } public List<T> getRootElements() { return getTreeElementValues(treeRootElements); } public T findElement(T value) { SushiTreeElement<T> element = findTreeElementByValue(value); if(element != null){ return findTreeElementByValue(value).getValue(); } else{ return null; } } public static List<SushiTree> findAll() { Query q = Persistor.getEntityManager().createQuery("select t from SushiTree t"); return q.getResultList(); } public static void removeAll() { try { EntityTransaction entr = Persistor.getEntityManager().getTransaction(); entr.begin(); Query query = Persistor.getEntityManager().createQuery("DELETE FROM SushiTree"); int deleteRecords = query.executeUpdate(); entr.commit(); System.out.println(deleteRecords + " records are deleted."); } catch (Exception ex) { System.out.println(ex.getMessage()); } } public ArrayList<T> getElements() { return getTreeElementValues(treeElements); } /** * Returns the depth of an element from the tree. If the element is not contained, -1 will be returned. * @param element * @return */ public int getElementDepth(T element){ int depth = 0; SushiTreeElement<T> treeElement = this.findTreeElementByValue(element); if(treeElement == null){ return -1; } SushiTreeElement<T> parent = treeElement.getParent(); while(parent != null){ parent = parent.getParent(); depth++; } return depth; } @Override public String toString(){ return printTreeLevel(treeRootElements, 0); } private String printTreeLevel(List<SushiTreeElement<T>> treeElements, int count) { String tree = ""; for(SushiTreeElement<T> element : treeElements){ for(int i = 0; i < count; i++){ tree += "\t"; } tree += element.getValue() + System.getProperty("line.separator"); if(element.hasChildren()){ tree += printTreeLevel(element.getChildren(), count + 1); } } return tree; } public Boolean retainAllLeafs(Collection<?> collection) { boolean retainSuccess = true; // TODO: assert(collection instanceof T); List<SushiTreeElement<T>> copyTreeList = new ArrayList<SushiTreeElement<T>>(getLeafs()); for(SushiTreeElement<T> element : copyTreeList){ if(!collection.contains(element.getValue())){ remove(element.getValue()); } } return retainSuccess; } public boolean containsRootElement(T eventTypeName) { for (SushiTreeElement<T> element : treeRootElements) { if (element.getValue().equals(eventTypeName)) { return true; } } return false; } /** * Checks if a node with the given value exists in the children of a parent node. * @param parent * @param child the node that shall be in the children of the parent * * @return true if the node with the given value exists in the children of the given parent node */ public boolean isInChildrenOfNode(T parent, T child) { if (parent != null) { for (T attribute : getElements()) { if (attribute.equals(parent)) { return getChildren(attribute).contains(child); } } return false; } else { return getRootElements().contains(child); } } @Override public int getID() { return ID; } }