package sushi.event; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Query; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonIgnore; import sushi.bpmn.monitoringpoint.MonitoringPoint; import sushi.correlation.CorrelationRule; import sushi.event.attribute.SushiAttribute; import sushi.event.attribute.SushiAttributeTree; import sushi.persistence.Persistable; import sushi.persistence.Persistor; import sushi.process.SushiProcess; import sushi.transformation.TransformationRule; import sushi.visualisation.SushiEventView; import sushi.visualisation.SushiChartConfiguration; /** * Representation of an event type */ @Entity @Table(name = "EventType") public class SushiEventType extends Persistable { private static final long serialVersionUID = 1L; @Id @Column(name="ID") @GeneratedValue(strategy = GenerationType.IDENTITY) private int ID; @Column(name = "TypeName", unique = true) private String typeName; // hold the structure definition of the attributes + types in a tree @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="Attributes") private SushiAttributeTree attributes; //must be an attribute expression @Column(name = "TimestampName") private String timestampName; @Column(name = "XMLEvent") private boolean isXMLEvent = false; @Column(name = "SchemaName") private String schemaName; private SushiEventType() { this.typeName = ""; this.attributes = new SushiAttributeTree(); this.timestampName = null; } /** * Constructor. * * @param typeName * @throws RuntimeException */ public SushiEventType(String typeName) throws RuntimeException { this(); /* * remove leading and trailing whitespace * and replace each sequence of whitespace with an underscore */ String strippedTypeName = typeName.trim().replaceAll(" +", "_"); if (!isValidName(strippedTypeName)) { throw new RuntimeException("Event type name is not valid. Only characters [a-z], [A-Z], [0-9], - and _ are allowed!"); } this.typeName = strippedTypeName; } /** * Constructor. * * @param typeName * @param attributeTree * @throws RuntimeException */ public SushiEventType(String typeName, SushiAttributeTree attributeTree) throws RuntimeException { this(typeName); this.attributes = attributeTree; } /** * Constructor. * * @param typeName * @param attributeTree * @param timestampName must be an attribute expression * (e.g. 'timestamp' for a timestamp that is in root level, * 'someroot.time' for a timestamp that is in the second level etc. * @throws RuntimeException */ public SushiEventType(String typeName, SushiAttributeTree attributeTree, String timestampName) throws RuntimeException { this(typeName, attributeTree); /* * remove leading and trailing whitespace * and replace each sequence of whitespace with an underscore */ if (timestampName != null) { String strippedTimestampName = timestampName.trim().replaceAll(" +", "_"); if (!isValidName(strippedTimestampName)) { throw new RuntimeException("Timestamp name is not valid. Only characters [a-z], [A-Z], [0-9], - and _ are allowed!"); } this.timestampName = strippedTimestampName; } } /** * Constructor. * * @param typeName * @param attributeTree * @param timestampName must be an attribute expression * (e.g. 'timestamp' for a timestamp that is in root level, * 'someroot.time' for a timestamp that is in the second level etc. * @param schemaName * @throws RuntimeException */ public SushiEventType(String typeName, SushiAttributeTree attributeTree, String timestampName, String schemaName) throws RuntimeException { this(typeName, attributeTree, timestampName); this.isXMLEvent = true; this.schemaName = schemaName; } /** * Constructor. * * @param typeName * @param attributes list of root level attributes * @throws RuntimeException */ public SushiEventType(String typeName, List<SushiAttribute> attributes) throws RuntimeException { this(typeName); for (SushiAttribute attribute : attributes) { this.attributes.addRoot(attribute); } } /** * Constructor. * * @param typeName * @param attributes list of root level attributes * @param timestampName must be an attribute expression * (e.g. 'timestamp' for a timestamp that is in root level, * 'someroot.time' for a timestamp that is in the second level etc. * @throws RuntimeException */ public SushiEventType(String typeName, List<SushiAttribute> attributes, String timestampName) throws RuntimeException { this(typeName, attributes); /* * remove leading and trailing whitespace * and replace each sequence of whitespace with an underscore */ if (timestampName != null) { String strippedTimestampName = timestampName.trim().replaceAll(" +", "_"); if (!isValidName(strippedTimestampName)) { throw new RuntimeException("Timestamp name is not valid. Only characters [a-z], [A-Z], [0-9], - and _ are allowed!"); } this.timestampName = strippedTimestampName; } } /** * add attribute/type pair to the root attributes */ public void addValueType(SushiAttribute attribute) { attributes.addRoot(attribute); } /** * add attribute/type pairs to the root attributes */ public void addValueTypes(List<SushiAttribute> rootAttributes) { for (SushiAttribute root: rootAttributes) { attributes.addRoot(root); } } /** * checks if SushiEventtyp contains all given attribute names */ public boolean containsValues(List<String> attributeNames) { for (String name: attributeNames) { if (!containsValue(name)) return false; } return true; } /** * checks if SushiEventtyp contains the given attribute name */ public boolean containsValue(String attributeName) { return attributes.contains(attributeName); } /** * @param attributeExpression * @return true if the first found attribute has children */ public boolean hasChildren(String attributeExpression) { return attributes.hasChildren(attributeExpression); } /** * checks if the Eventtyp is hierarchical */ public boolean isHierarchical(){ return attributes.isHierarchical(); } public boolean isValidName(String string) { return string != null && string.matches("^[-a-zA-Z0-9._]+"); // a-z A-Z 0-9 _ - sind erlaubt } /** * @return list of root attribute names from the value type tree plus the timestamp name */ public ArrayList<String> getRootAttributeNames() { ArrayList<String> attributeNames = new ArrayList<String>(); List<SushiAttribute> rootAttributes = attributes.getRoots(); attributeNames.add(timestampName); for (SushiAttribute attribute : rootAttributes) { attributeNames.add(attribute.getName()); } return attributeNames; } /** * @return list of attribute expressions from the value type tree plus the timestamp name */ public ArrayList<String> getAttributeExpressions() { ArrayList<String> attributeExpressions = getAttributeExpressionsWithoutTimestampName(); attributeExpressions.add(timestampName); return attributeExpressions; } /** * @return list of attribute expressions from the value type tree */ public ArrayList<String> getAttributeExpressionsWithoutTimestampName() { ArrayList<String> attributeExpressions = new ArrayList<String>(); List<SushiAttribute> allAttributes = attributes.getAttributes(); for (SushiAttribute attribute : allAttributes) { attributeExpressions.add(attribute.getAttributeExpression()); } return attributeExpressions; } public int getID() { return ID; } public void setID(int iD) { ID = iD; } public String getTypeName() { return typeName; } public void setTypeName(String name) { if (!isValidName(name)){ throw new RuntimeException("Event type name is invalid. Allowed characters: [a-z] [A-Z] [0-9] - _"); } this.typeName = name; } /** * @return timestamp name as attribute expression */ public String getTimestampName() { return timestampName; } public String getTimestampNameAsXPath() { if (timestampName == null) { return null; } return "/" + timestampName.replace(".", "/"); } public void setTimestampName(String timestampName) { if (timestampName != null) { String strippedTimestampName = timestampName.trim().replaceAll(" +", "_"); if (!isValidName(strippedTimestampName)) { throw new RuntimeException("Timestamp name is not valid. Only characters [a-z], [A-Z], [0-9], - and _ are allowed!"); } this.timestampName = strippedTimestampName; } else { this.timestampName = null; } } @JsonIgnore public List<SushiAttribute> getRootLevelValueTypes() { return attributes.getRoots(); } @JsonIgnore public List<SushiAttribute> getValueTypes() { return attributes.getAttributes(); } @JsonIgnore public SushiAttributeTree getValueTypeTree() { return attributes; } public void setValueTypeTree(SushiAttributeTree attributes) { this.attributes = attributes; } public void setXMLEvent(boolean isXMLEvent) { this.isXMLEvent = isXMLEvent; } public boolean isXMLEvent() { return isXMLEvent; } public String getXMLName() { return schemaName; } public void setXMLName(String xmlName) { this.schemaName = xmlName; } @Override public String toString() { String processText = this.typeName + " (" + this.ID + ")"; return processText; } public static SushiEventType findByID(int ID){ List<SushiEventType> eventTypes = findByAttribute("ID", Integer.toString(ID)); if(!eventTypes.isEmpty()){ return eventTypes.get(0); }else{ return null; } } /** * return Eventtype which has the given structuredefinition */ public static SushiEventType findBySchemaName(String schemaName){ List<SushiEventType> eventTypes = findByAttribute("SchemaName", schemaName); if(!eventTypes.isEmpty()){ return eventTypes.get(0); }else{ return null; } } public static List<SushiEventType> findByIDGreaterThan(int ID){ return findByAttributeGreaterThan("ID", Integer.toString(ID)); } public static List<SushiEventType> findByIDLessThan(int ID){ return findByAttributeLessThan("ID", Integer.toString(ID)); } public static List<SushiEventType> findByAttribute(String attributeName, String value) { Query query = Persistor.getEntityManager().createNativeQuery("SELECT * FROM EventType WHERE " + attributeName + " = '" + value + "'", SushiEventType.class); return query.getResultList(); } private static List<SushiEventType> findByAttributeGreaterThan(String attributeName, String value) { Query query = Persistor.getEntityManager().createNativeQuery("" + "SELECT * FROM EventType " + "WHERE " + attributeName + " > '" + value + "'", SushiEventType.class); return query.getResultList(); } private static List<SushiEventType> findByAttributeLessThan(String attributeName, String value) { Query query = Persistor.getEntityManager().createNativeQuery("" + "SELECT * FROM EventType " + "WHERE " + attributeName + " < '" + value + "'", SushiEventType.class); return query.getResultList(); } /** * * @param typeName name of the EventType * @return */ public static SushiEventType findByTypeName(String typeName) { Query query = Persistor.getEntityManager().createNativeQuery("" + "SELECT * FROM EventType " + "WHERE TypeName = '" + typeName + "'", SushiEventType.class); // Type names should be distinct! assert(query.getResultList().size() < 2); try{ if (query.getResultList().size() > 0) { return (SushiEventType) query.getResultList().get(0); } else { return null; } } catch(Exception e){ System.err.println(e); return null; } } public List<String> getAttributeKeysFromMap() { String queryString = "" + "SELECT DISTINCT MapKey FROM SushiMapElement " + "WHERE ID IN (SELECT treeRootElements_ID FROM SushiMapTree_SushiMapTreeRootElements " + // hier nur auf flachen Events "WHERE SushiMapTree_SushiMapID IN (SELECT MapTreeID FROM Event " + "WHERE EVENTTYPE_ID = '" + ID + "'))"; Query query = Persistor.getEntityManager().createNativeQuery(queryString); if (query.getResultList() == null) return new ArrayList<String>(); return query.getResultList(); } public List<Serializable> findAttributeValues(String selectedConditionAttribute) { String queryString = "" + "SELECT DISTINCT MapValue FROM SushiMapElement " + "WHERE MapKey = '" + selectedConditionAttribute + "' AND " + "ID IN (SELECT treeRootElements_ID FROM SushiMapTree_SushiMapTreeRootElements " + // hier nur auf flachen Events "WHERE SushiMapTree_SushiMapID IN (SELECT MapTreeID FROM Event " + "WHERE EVENTTYPE_ID = '" + ID + "'))"; Query query = Persistor.getEntityManager().createNativeQuery(queryString); return query.getResultList(); } public static List<SushiEventType> findAll() { Query query = Persistor.getEntityManager().createQuery("select t from SushiEventType t"); return query.getResultList(); } /** * returns Eventtypes which have a subset of the given attributes */ public static List<SushiEventType> findMatchingEventTypes(List<String> stringValues, String importTimeName) { List<SushiEventType> selectedEventTypes = new ArrayList<SushiEventType>(); for (SushiEventType eventType: SushiEventType.findAll()) { //prepare attributes without import Time ArrayList<String> attributes = eventType.getRootAttributeNames(); attributes.remove(importTimeName); if (stringValues.containsAll(attributes)) { selectedEventTypes.add(eventType); } } return selectedEventTypes; } @Override public SushiEventType save() { attributes.save(); return (SushiEventType) super.save(); } public static boolean save(List<SushiEventType> eventTypes) { try { Persistor.getEntityManager().getTransaction().begin(); for (SushiEventType eventType : eventTypes) { Persistor.getEntityManager().persist(eventType); } Persistor.getEntityManager().getTransaction().commit(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Deletes this event type from the database. * @return */ @Override public SushiEventType remove() { try { // remove eventtype from process // delete correlation rule if correlation rule contains attribute of this event type Set<CorrelationRule> correlationRulesToBeRemoved = new HashSet<CorrelationRule>(); for (SushiProcess process : SushiProcess.findByEventType(this)) { process.removeEventType(this); if(process.getTimeCondition() != null && process.getTimeCondition().getSelectedEventType().equals(this)){ process.getTimeCondition().remove(); } for (SushiAttribute attribute : getValueTypes()) { process.removeCorrelationAttribute(attribute); } Set<CorrelationRule> correlationRulesOfProcess = new HashSet<CorrelationRule>(process.getCorrelationRules()); for (CorrelationRule correlationRule : correlationRulesOfProcess) { if (correlationRule.getFirstAttribute().getEventType().equals(this) || correlationRule.getSecondAttribute().getEventType().equals(this)) { process.getCorrelationRules().remove(correlationRule); correlationRulesToBeRemoved.add(correlationRule); } } process.save(); } for (CorrelationRule ruleToBeRemoved : correlationRulesToBeRemoved) { ruleToBeRemoved.remove(); } //delete events of eventType for (SushiEvent event : SushiEvent.findByEventType(this)) { event.remove(); } //delete eventTypeRule, that create this eventType EventTypeRule rule = EventTypeRule.findEventTypeRuleForCreatedEventType(this); if (rule != null){ rule.remove(); } //update eventTypeRule, remove if no usedType remains List<EventTypeRule> containingRules = EventTypeRule.findEventTypeRuleForContainedEventType(this); for(EventTypeRule containingRule : containingRules){ containingRule.getUsedEventTypes().remove(this); containingRule.merge(); if (containingRule.getUsedEventTypes().isEmpty()) { containingRule.remove(); } } //update eventView, remove if no usedType remains List<SushiEventView> eventViews = SushiEventView.findByEventType(this); for(SushiEventView eventView : eventViews){ eventView.getEventTypes().remove(this); if (eventView.getEventTypes().isEmpty()) { eventView.remove(); } } //remove ChartOptions List<SushiChartConfiguration> charts = SushiChartConfiguration.findByEventType(this); for(SushiChartConfiguration chart : charts){ chart.remove(); } //remove event types from monitoring points List<MonitoringPoint> monitoringPoints = MonitoringPoint.findByEventType(this); for(MonitoringPoint monitoringPoint : monitoringPoints){ monitoringPoint.setEventType(null); monitoringPoint.merge(); } //remove transformation rules referencing this event type List<TransformationRule> transformationRules = TransformationRule.findByEventType(this); for (TransformationRule transformationRule : transformationRules) { transformationRule.remove(); } } catch (Exception e) { e.printStackTrace(); } return (SushiEventType) super.remove(); } /** * Deletes the specified eventtypes from the database. * @return */ public static boolean remove(List<SushiEventType> eventTypes) { boolean removed = true; for(SushiEventType eventType : eventTypes){ removed = (eventType.remove() != null); } return removed; } public static void removeAll() { List<SushiEventType> allEventTypes = SushiEventType.findAll(); SushiEventType.remove(allEventTypes); } public static List<String> getAllTypeNames() { ArrayList<String> eventTypeNames = new ArrayList<String>(); for(SushiEventType eventType : SushiEventType.findAll()){ eventTypeNames.add(eventType.getTypeName()); } return eventTypeNames; } }