package sushi.transformation.collection; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EntityTransaction; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Query; import javax.persistence.Table; import sushi.event.collection.SushiTreeElement; import sushi.persistence.Persistable; import sushi.persistence.Persistor; import sushi.transformation.TransformationRule; import sushi.transformation.element.EventTypeElement; import sushi.transformation.element.FilterExpressionConnectorElement; import sushi.transformation.element.FilterExpressionElement; import sushi.transformation.element.PatternOperatorElement; /** * Container object for the pattern elements of a transformation rule. * One pattern tree per transformation rule. */ @Entity @Table(name = "SushiPatternTree") public class SushiPatternTree extends Persistable { private static final long serialVersionUID = 4641263893746532464L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="SushiPatternTreeID") protected int ID; @Column(name="Auxiliary") private String auxiliary = "Auxiliary"; @OneToOne(fetch = FetchType.LAZY, mappedBy = "patternTree") private TransformationRule transformationRule; // @OneToMany(cascade = CascadeType.PERSIST) // @JoinTable(name="SushiTreeElementTree_SushiTreeElements") // private List<SushiTreeElement<Serializable>> elements = new ArrayList<SushiTreeElement<Serializable>>(); @OneToMany(cascade = CascadeType.ALL) @JoinColumn(name="patternTreeID", referencedColumnName="SushiPatternTreeID") private List<SushiTreeElement<Serializable>> elements = new ArrayList<SushiTreeElement<Serializable>>(); public SushiPatternTree() { this.ID = 0; } public SushiPatternTree(SushiTreeElement<Serializable> element) { this(); assert(element != null); this.elements.add(element); } public SushiPatternTree(List<SushiTreeElement<Serializable>> elements) { this(); assert(elements != null); assert(!elements.isEmpty()); this.elements.addAll(elements); } public boolean isEmpty() { return elements.isEmpty(); } @Override public int getID() { return ID; } /** * Method to retrieve all elements of the pattern tree. * @return list of elements */ public List<SushiTreeElement<Serializable>> getElements() { return elements; } /** * Method to retrieve all elements without parents. * @return list of root elements in an adequate order */ public List<SushiTreeElement<Serializable>> getRoots() { List<SushiTreeElement<Serializable>> rootElements = new ArrayList<SushiTreeElement<Serializable>>(); for (SushiTreeElement<Serializable> currentElement : elements) { if (!currentElement.hasParent()) { rootElements.add(currentElement); } } return rootElements; } /** * Method to retrieve all elements without children. * @return list of root elements in an adequate order */ public List<SushiTreeElement<Serializable>> getLeafs() { List<SushiTreeElement<Serializable>> leafElements = new ArrayList<SushiTreeElement<Serializable>>(); for (SushiTreeElement<Serializable> currentElement : elements) { if (!currentElement.hasChildren()) { leafElements.add(currentElement); } } return leafElements; } /** * Method to retrieve all pattern operator elements of the pattern tree. * @return list of pattern operator elements */ public List<PatternOperatorElement> getPatternOperatorElements() { List<PatternOperatorElement> patternOperatorElements = new ArrayList<PatternOperatorElement>(); for (SushiTreeElement<Serializable> element : elements) { if (element instanceof PatternOperatorElement) { patternOperatorElements.add((PatternOperatorElement) element); } } return patternOperatorElements; } /** * Method to retrieve all event type elements of the pattern tree. * @return list of event type elements */ public List<EventTypeElement> getEventTypeElements() { List<EventTypeElement> eventTypeElements = new ArrayList<EventTypeElement>(); for (SushiTreeElement<Serializable> element : elements) { if (element instanceof EventTypeElement) { eventTypeElements.add((EventTypeElement) element); } } return eventTypeElements; } /** * Method to retrieve all filter expression elements of the pattern tree. * @return list of filter expression elements */ public List<FilterExpressionElement> getFilterExpressionElements() { List<FilterExpressionElement> filterExpressionElements = new ArrayList<FilterExpressionElement>(); for (SushiTreeElement<Serializable> element : elements) { if (element instanceof FilterExpressionElement) { filterExpressionElements.add((FilterExpressionElement) element); } } return filterExpressionElements; } public boolean addElement(SushiTreeElement<Serializable> element) { return elements.add(element); } public boolean addElements(List<SushiTreeElement<Serializable>> elements) { return elements.addAll(elements); } /** * Removes the given element from the tree. * If an element has parent and child elements, the child elements will be connected to the parent elements. * * @param element the element to be removed * @return true if removal was successful */ public boolean removeElement(SushiTreeElement<Serializable> element) { if (element instanceof FilterExpressionElement) { SushiTreeElement<Serializable> parentElement = element.getParent(); parentElement.removeChild(element); } else if (element instanceof EventTypeElement) { List<SushiTreeElement<Serializable>> allChildrenOfElement = getAllChildrenFromElement(element); for (SushiTreeElement<Serializable> child : allChildrenOfElement) { child.removeElement(); elements.remove(child); } List<SushiTreeElement<Serializable>> allParentsOfElement = getAllParentsFromElement(element); for (SushiTreeElement<Serializable> parent : allParentsOfElement) { parent.removeElement(); elements.remove(parent); } element.removeElement(); } else if (element instanceof PatternOperatorElement || element instanceof FilterExpressionConnectorElement) { for (SushiTreeElement<Serializable> childElement : element.getChildren()) { if (element.hasParent()) { SushiTreeElement<Serializable> parentElement = element.getParent(); childElement.setParent(parentElement); parentElement.removeChild(element); } else { childElement.setParent(null); } } } return elements.remove(element); } /** * Method to retrieve all elements from lower levels that are referenced directly or indirectly by the given element. * * @param element the element from which all lower level elements shall be found * @return list of elements from lower levels that are referenced directly or indirectly by the given element */ private List<SushiTreeElement<Serializable>> getAllChildrenFromElement(SushiTreeElement<Serializable> element) { List<SushiTreeElement<Serializable>> allChildren = new ArrayList<SushiTreeElement<Serializable>>(); for (SushiTreeElement<Serializable> child : element.getChildren()) { allChildren.add(child); if (child.hasChildren()) { for (SushiTreeElement<Serializable> childOfChild : child.getChildren()) { getAllChildrenFromChild(allChildren, childOfChild); } } } return allChildren; } private void getAllChildrenFromChild(List<SushiTreeElement<Serializable>> allChildren, SushiTreeElement<Serializable> element) { allChildren.add(element); if (element.hasChildren()) { for (SushiTreeElement<Serializable> child : element.getChildren()) { getAllChildrenFromChild(allChildren, child); } } } /** * Method to retrieve all elements from higher levels that are referenced directly or indirectly by the given element. * * @param element the element from which all higher shall be found * @return list of elements from higher levels that are referenced directly or indirectly by the given element */ private List<SushiTreeElement<Serializable>> getAllParentsFromElement(SushiTreeElement<Serializable> element) { List<SushiTreeElement<Serializable>> allParents = new ArrayList<SushiTreeElement<Serializable>>(); if (element.hasParent()) { SushiTreeElement<Serializable> parent = element.getParent(); allParents.add(parent); if (parent.hasParent()) { getAllParentsFromParent(allParents, parent.getParent()); } } return allParents; } private void getAllParentsFromParent(List<SushiTreeElement<Serializable>> allParents, SushiTreeElement<Serializable> element) { allParents.add(element); if (element.hasParent()) { getAllChildrenFromChild(allParents, element.getParent()); } } public static List<SushiPatternTree> findAll() { Query q = Persistor.getEntityManager().createQuery("SELECT t FROM SushiPatternTree t"); return q.getResultList(); } public static void removeAll() { try { EntityTransaction entr = Persistor.getEntityManager().getTransaction(); entr.begin(); Query query = Persistor.getEntityManager().createQuery("DELETE FROM SushiPatternTree"); int deleteRecords = query.executeUpdate(); entr.commit(); System.out.println(deleteRecords + " records are deleted."); } catch (Exception ex) { System.out.println(ex.getMessage()); } } @Override public SushiPatternTree clone() { return deepClone(); } private SushiPatternTree deepClone() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (SushiPatternTree) ois.readObject(); } catch (IOException e) { return null; } catch (ClassNotFoundException e) { return null; } } @Override public String toString() { return printTreeLevel(getRoots(), 0); } private String printTreeLevel(List<SushiTreeElement<Serializable>> elements, int count) { String tree = ""; for (SushiTreeElement<Serializable> element : elements) { for (int i = 0; i < count; i++) { tree += "\t"; } tree += element + System.getProperty("line.separator"); if (element.hasChildren()) { tree += printTreeLevel(element.getChildren(), count + 1); } } return tree; } }