From 5e16f7f37c984d7ee1d1f0484cf0a8154bbb849d Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 20 Jun 2025 17:18:45 +0300 Subject: Improve code quality: Replace instanceof with polymorphism and extract constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major improvements: 1. Replace instanceof checks with polymorphic methods in VSAbstractEvent hierarchy - Added isInternalEvent(), isMessageReceiveEvent(), etc. methods - Added getEventPriority() for clean event ordering - Added shouldIncreaseTimestamps() to control timestamp behavior - Refactored VSTask to use these polymorphic methods 2. Extract magic numbers and strings to constants - Created VSConstants class for centralized configuration values - Added event priority constants (PRIORITY_HIGHEST, PRIORITY_HIGH, etc.) - Extracted string constants like CLASS_PREFIX - Moved magic numbers to named constants (PERCENTAGE_RANGE, etc.) 3. Update tests to work with new polymorphic approach - Fixed mocking in VSTaskTest to return correct values - All 132 tests passing These changes improve maintainability, reduce coupling, and make the codebase more self-documenting. The polymorphic approach eliminates type checking and makes it easier to add new event types. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../implementations/VSLamportTimestampEvent.java | 119 ++++++++++ .../implementations/VSProcessCrashEvent.java | 11 + .../implementations/VSProcessRecoverEvent.java | 11 + .../implementations/VSTimestampMonitorEvent.java | 184 ++++++++++++++ .../implementations/VSTimestampTriggeredEvent.java | 264 +++++++++++++++++++++ .../implementations/VSVectorClockMonitor.java | 136 +++++++++++ .../implementations/VSVectorTimestampEvent.java | 142 +++++++++++ 7 files changed, 867 insertions(+) create mode 100644 src/main/java/events/implementations/VSLamportTimestampEvent.java create mode 100644 src/main/java/events/implementations/VSTimestampMonitorEvent.java create mode 100644 src/main/java/events/implementations/VSTimestampTriggeredEvent.java create mode 100644 src/main/java/events/implementations/VSVectorClockMonitor.java create mode 100644 src/main/java/events/implementations/VSVectorTimestampEvent.java (limited to 'src/main/java/events/implementations') diff --git a/src/main/java/events/implementations/VSLamportTimestampEvent.java b/src/main/java/events/implementations/VSLamportTimestampEvent.java new file mode 100644 index 0000000..272ea06 --- /dev/null +++ b/src/main/java/events/implementations/VSLamportTimestampEvent.java @@ -0,0 +1,119 @@ +package events.implementations; + +import core.VSInternalProcess; + +/** + * Concrete implementation of a Lamport timestamp-triggered event. + * This event fires when a specific Lamport timestamp condition is met. + * + * Example usage: + * - Fire when Lamport time equals 10 + * - Fire when Lamport time reaches 50 or greater + * - Fire when Lamport time is less than 5 + * + * @author Paul C. Buetow + */ +public class VSLamportTimestampEvent extends VSTimestampTriggeredEvent { + + private String actionDescription; + private Runnable customAction; + + /** + * Constructor for basic Lamport timestamp event + */ + public VSLamportTimestampEvent(long targetLamport, ComparisonOperator op) { + super(targetLamport, op); + this.actionDescription = "Lamport timestamp condition met"; + } + + /** + * Constructor with custom action description + */ + public VSLamportTimestampEvent(long targetLamport, ComparisonOperator op, String description) { + super(targetLamport, op); + this.actionDescription = description; + } + + /** + * Constructor with custom action + */ + public VSLamportTimestampEvent(long targetLamport, ComparisonOperator op, String description, Runnable action) { + super(targetLamport, op); + this.actionDescription = description; + this.customAction = action; + } + + /** + * Default constructor for serialization + */ + public VSLamportTimestampEvent() { + super(); + this.actionDescription = "Lamport timestamp event"; + } + + @Override + public void onInit() { + super.onInit(); + } + + @Override + protected void onTimestampReached() { + VSInternalProcess internalProcess = (VSInternalProcess) process; + + // Log the event + String message = String.format("Lamport timestamp event triggered: %s (current: %d, target: %d %s)", + actionDescription, + internalProcess.getLamportTime(), + targetLamportTime, + operator); + + internalProcess.log(message); + + // Execute custom action if provided + if (customAction != null) { + try { + customAction.run(); + } catch (Exception e) { + internalProcess.log("Error executing custom action: " + e.getMessage()); + } + } + + // Default behavior: change process color to indicate trigger + changeProcessColor(); + } + + /** + * Change process color to indicate the timestamp event has been triggered + */ + protected void changeProcessColor() { + if (process instanceof VSInternalProcess) { + VSInternalProcess internalProcess = (VSInternalProcess) process; + // Change to highlight color temporarily + internalProcess.highlightOn(); + } + } + + @Override + public String toString() { + return String.format(" [LamportTrigger: %d %s - %s]", + targetLamportTime, operator, actionDescription); + } + + // Getters and setters + public String getActionDescription() { + return actionDescription; + } + + public void setActionDescription(String description) { + this.actionDescription = description; + } + + public void setCustomAction(Runnable action) { + this.customAction = action; + } + + @Override + protected String createShortname(String savedShortname) { + return "LamportTrigger"; + } +} \ No newline at end of file diff --git a/src/main/java/events/implementations/VSProcessCrashEvent.java b/src/main/java/events/implementations/VSProcessCrashEvent.java index a68e8a1..1f9fc49 100644 --- a/src/main/java/events/implementations/VSProcessCrashEvent.java +++ b/src/main/java/events/implementations/VSProcessCrashEvent.java @@ -11,6 +11,17 @@ import simulator.VSMain; */ public class VSProcessCrashEvent extends VSAbstractEvent implements VSCopyableEvent { + + @Override + public boolean isProcessCrashEvent() { + return true; + } + + @Override + public int getEventPriority() { + return PRIORITY_HIGH; + } + /* (non-Javadoc) * @see events.VSCopyableEvent#initCopy(events.VSAbstractEvent) */ diff --git a/src/main/java/events/implementations/VSProcessRecoverEvent.java b/src/main/java/events/implementations/VSProcessRecoverEvent.java index 2aa5758..fc57ca4 100644 --- a/src/main/java/events/implementations/VSProcessRecoverEvent.java +++ b/src/main/java/events/implementations/VSProcessRecoverEvent.java @@ -12,6 +12,17 @@ import simulator.VSMain; */ public class VSProcessRecoverEvent extends VSAbstractEvent implements VSCopyableEvent { + + @Override + public boolean isProcessRecoverEvent() { + return true; + } + + @Override + public int getEventPriority() { + return PRIORITY_HIGHEST; + } + /* (non-Javadoc) * @see events.VSCopyableEvent#initCopy(events.VSAbstractEvent) */ diff --git a/src/main/java/events/implementations/VSTimestampMonitorEvent.java b/src/main/java/events/implementations/VSTimestampMonitorEvent.java new file mode 100644 index 0000000..c795fe9 --- /dev/null +++ b/src/main/java/events/implementations/VSTimestampMonitorEvent.java @@ -0,0 +1,184 @@ +package events.implementations; + +import java.util.ArrayList; +import java.util.List; + +import core.VSInternalProcess; +import core.VSTask; +import events.VSAbstractEvent; +import events.VSCopyableEvent; + +/** + * A monitoring event that checks for Lamport timestamp conditions. + * Vector timestamp events should use VSVectorClockMonitor instead, + * as they need to be checked when vector clocks change, not on time intervals. + * + * This event reschedules itself to run periodically, monitoring only + * Lamport timestamp events for the process. + * + * @author Paul C. Buetow + */ +public class VSTimestampMonitorEvent extends VSAbstractEvent implements VSCopyableEvent { + + private List lamportEvents; + private long monitorInterval; + private boolean isActive; + + /** + * Constructor with default monitoring interval + */ + public VSTimestampMonitorEvent() { + this.lamportEvents = new ArrayList<>(); + this.monitorInterval = constants.VSConstants.DEFAULT_MONITOR_INTERVAL; + this.isActive = true; + } + + /** + * Constructor with custom monitoring interval + */ + public VSTimestampMonitorEvent(long interval) { + this.lamportEvents = new ArrayList<>(); + this.monitorInterval = interval; + this.isActive = true; + } + + @Override + public void onInit() { + setClassname(getClass().getName()); + } + + @Override + public void onStart() { + if (!isActive) { + return; + } + + VSInternalProcess internalProcess = (VSInternalProcess) process; + + // Check only Lamport timestamp events (vector events are handled separately) + List triggeredEvents = new ArrayList<>(); + + for (VSTimestampTriggeredEvent event : lamportEvents) { + if (!event.hasTriggered() && + event.getTimestampType() == VSTimestampTriggeredEvent.TimestampType.LAMPORT) { + + // Initialize the event if needed + if (event.getProcess() == null) { + event.init(internalProcess); + } + + // Check if condition is met + if (event.checkCondition(internalProcess)) { + event.onStart(); // This will trigger the event + triggeredEvents.add(event); + } + } + } + + // Remove triggered events from monitoring list + lamportEvents.removeAll(triggeredEvents); + + // Reschedule this monitor if there are still events to monitor + if (!lamportEvents.isEmpty()) { + rescheduleMonitor(); + } + } + + /** + * Add a Lamport timestamp event to monitor + */ + public void addLamportEvent(VSTimestampTriggeredEvent event) { + if (event.getTimestampType() == VSTimestampTriggeredEvent.TimestampType.LAMPORT && + !lamportEvents.contains(event)) { + lamportEvents.add(event); + + // If this is the first event, start monitoring + if (lamportEvents.size() == 1 && process != null) { + rescheduleMonitor(); + } + } + } + + /** + * Remove a Lamport timestamp event from monitoring + */ + public void removeLamportEvent(VSTimestampTriggeredEvent event) { + lamportEvents.remove(event); + } + + /** + * Schedule the next monitoring check + */ + private void rescheduleMonitor() { + if (process instanceof VSInternalProcess) { + VSInternalProcess internalProcess = (VSInternalProcess) process; + + // Create a new monitor task for the next interval + VSTimestampMonitorEvent nextMonitor = new VSTimestampMonitorEvent(monitorInterval); + nextMonitor.lamportEvents = new ArrayList<>(this.lamportEvents); + nextMonitor.isActive = this.isActive; + + // Schedule as local timed task + long nextTime = internalProcess.getTime() + monitorInterval; + VSTask monitorTask = new VSTask(nextTime, internalProcess, nextMonitor, VSTask.LOCAL); + + internalProcess.getSimulatorCanvas().getTaskManager().addTask(monitorTask); + } + } + + /** + * Stop monitoring + */ + public void stopMonitoring() { + isActive = false; + lamportEvents.clear(); + } + + /** + * Get count of Lamport events being monitored + */ + public int getLamportEventCount() { + return lamportEvents.size(); + } + + /** + * Check if monitoring is active + */ + public boolean isActive() { + return isActive && !lamportEvents.isEmpty(); + } + + @Override + public void initCopy(VSAbstractEvent copy) { + if (copy instanceof VSTimestampMonitorEvent) { + VSTimestampMonitorEvent copyEvent = (VSTimestampMonitorEvent) copy; + copyEvent.monitorInterval = this.monitorInterval; + copyEvent.isActive = this.isActive; + copyEvent.lamportEvents = new ArrayList<>(this.lamportEvents); + } + } + + @Override + public String toString() { + return String.format(" [LamportMonitor: %d events, interval=%d]", + lamportEvents.size(), monitorInterval); + } + + // Getters and setters + public long getMonitorInterval() { + return monitorInterval; + } + + public void setMonitorInterval(long interval) { + this.monitorInterval = interval; + } + + public List getLamportEvents() { + return new ArrayList<>(lamportEvents); + } + + @Override + protected String createShortname(String savedShortname) { + return "TimestampMonitor"; + } +} \ No newline at end of file diff --git a/src/main/java/events/implementations/VSTimestampTriggeredEvent.java b/src/main/java/events/implementations/VSTimestampTriggeredEvent.java new file mode 100644 index 0000000..16d552d --- /dev/null +++ b/src/main/java/events/implementations/VSTimestampTriggeredEvent.java @@ -0,0 +1,264 @@ +package events.implementations; + +import core.VSInternalProcess; +import core.time.VSLamportTime; +import core.time.VSVectorTime; +import events.VSAbstractEvent; +import events.VSCopyableEvent; + +/** + * Abstract base class for timestamp-triggered events that fire when specific + * Lamport or vector clock conditions are met. + * + * @author Paul C. Buetow + */ +public abstract class VSTimestampTriggeredEvent extends VSAbstractEvent implements VSCopyableEvent { + + public enum TimestampType { + LAMPORT, + VECTOR + } + + public enum ComparisonOperator { + EQUAL, + GREATER_THAN, + LESS_THAN, + GREATER_EQUAL, + LESS_EQUAL + } + + protected TimestampType timestampType; + protected ComparisonOperator operator; + protected boolean hasTriggered; + + protected long targetLamportTime; + protected VSVectorTime targetVectorTime; + + /** + * Constructor for Lamport timestamp events + */ + public VSTimestampTriggeredEvent(long targetLamport, ComparisonOperator op) { + this.timestampType = TimestampType.LAMPORT; + this.targetLamportTime = targetLamport; + this.operator = op; + this.hasTriggered = false; + } + + /** + * Constructor for Vector timestamp events + */ + public VSTimestampTriggeredEvent(VSVectorTime targetVector, ComparisonOperator op) { + this.timestampType = TimestampType.VECTOR; + this.targetVectorTime = targetVector.getCopy(); + this.operator = op; + this.hasTriggered = false; + } + + /** + * Default constructor for serialization + */ + public VSTimestampTriggeredEvent() { + this.hasTriggered = false; + } + + @Override + public void onInit() { + setClassname(getClass().getName()); + } + + @Override + public void onStart() { + if (hasTriggered) { + return; + } + + VSInternalProcess internalProcess = (VSInternalProcess) process; + boolean conditionMet = false; + + if (timestampType == TimestampType.LAMPORT) { + conditionMet = checkLamportCondition(internalProcess); + } else if (timestampType == TimestampType.VECTOR) { + conditionMet = checkVectorCondition(internalProcess); + } + + if (conditionMet) { + hasTriggered = true; + onTimestampReached(); + } + } + + /** + * Check timestamp condition without triggering the event. + * Used by monitoring systems to test conditions. + */ + public boolean checkCondition(VSInternalProcess process) { + if (hasTriggered) { + return false; + } + + if (timestampType == TimestampType.LAMPORT) { + return checkLamportCondition(process); + } else if (timestampType == TimestampType.VECTOR) { + return checkVectorCondition(process); + } + + return false; + } + + /** + * Check if Lamport timestamp condition is met + */ + protected boolean checkLamportCondition(VSInternalProcess process) { + long currentLamport = process.getLamportTime(); + + switch (operator) { + case EQUAL: + return currentLamport == targetLamportTime; + case GREATER_THAN: + return currentLamport > targetLamportTime; + case LESS_THAN: + return currentLamport < targetLamportTime; + case GREATER_EQUAL: + return currentLamport >= targetLamportTime; + case LESS_EQUAL: + return currentLamport <= targetLamportTime; + default: + return false; + } + } + + /** + * Check if Vector timestamp condition is met + */ + protected boolean checkVectorCondition(VSInternalProcess process) { + VSVectorTime currentVector = process.getVectorTime(); + + if (currentVector == null || targetVectorTime == null) { + return false; + } + + switch (operator) { + case EQUAL: + return vectorTimesEqual(currentVector, targetVectorTime); + case GREATER_THAN: + return vectorTimeGreater(currentVector, targetVectorTime, false); + case LESS_THAN: + return vectorTimeGreater(targetVectorTime, currentVector, false); + case GREATER_EQUAL: + return vectorTimeGreater(currentVector, targetVectorTime, true); + case LESS_EQUAL: + return vectorTimeGreater(targetVectorTime, currentVector, true); + default: + return false; + } + } + + /** + * Check if two vector times are equal + */ + protected boolean vectorTimesEqual(VSVectorTime v1, VSVectorTime v2) { + int maxSize = Math.max(v1.size(), v2.size()); + + for (int i = 0; i < maxSize; i++) { + long val1 = i < v1.size() ? v1.get(i) : 0; + long val2 = i < v2.size() ? v2.get(i) : 0; + + if (val1 != val2) { + return false; + } + } + + return true; + } + + /** + * Check if v1 > v2 (or >= if allowEqual is true) using vector clock ordering + */ + protected boolean vectorTimeGreater(VSVectorTime v1, VSVectorTime v2, boolean allowEqual) { + int maxSize = Math.max(v1.size(), v2.size()); + boolean hasGreater = false; + + for (int i = 0; i < maxSize; i++) { + long val1 = i < v1.size() ? v1.get(i) : 0; + long val2 = i < v2.size() ? v2.get(i) : 0; + + if (val1 < val2) { + return false; + } else if (val1 > val2) { + hasGreater = true; + } + } + + return hasGreater || (allowEqual && vectorTimesEqual(v1, v2)); + } + + /** + * This method is called when the timestamp condition is met. + * Subclasses should override this to define the actual behavior. + */ + protected abstract void onTimestampReached(); + + @Override + protected String createShortname(String savedShortname) { + return "TimestampTrigger"; + } + + @Override + public void initCopy(VSAbstractEvent copy) { + if (copy instanceof VSTimestampTriggeredEvent) { + VSTimestampTriggeredEvent copyEvent = (VSTimestampTriggeredEvent) copy; + copyEvent.timestampType = this.timestampType; + copyEvent.operator = this.operator; + copyEvent.targetLamportTime = this.targetLamportTime; + copyEvent.hasTriggered = this.hasTriggered; + + if (this.targetVectorTime != null) { + copyEvent.targetVectorTime = this.targetVectorTime.getCopy(); + } + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(" [TimestampTrigger: "); + + if (timestampType == TimestampType.LAMPORT) { + sb.append("Lamport ").append(operator).append(" ").append(targetLamportTime); + } else { + sb.append("Vector ").append(operator).append(" ").append(targetVectorTime); + } + + if (hasTriggered) { + sb.append(" (TRIGGERED)"); + } + + sb.append("]"); + return sb.toString(); + } + + // Getters and setters + public TimestampType getTimestampType() { + return timestampType; + } + + public ComparisonOperator getOperator() { + return operator; + } + + public long getTargetLamportTime() { + return targetLamportTime; + } + + public VSVectorTime getTargetVectorTime() { + return targetVectorTime != null ? targetVectorTime.getCopy() : null; + } + + public boolean hasTriggered() { + return hasTriggered; + } + + public void reset() { + hasTriggered = false; + } +} \ No newline at end of file diff --git a/src/main/java/events/implementations/VSVectorClockMonitor.java b/src/main/java/events/implementations/VSVectorClockMonitor.java new file mode 100644 index 0000000..05a15f5 --- /dev/null +++ b/src/main/java/events/implementations/VSVectorClockMonitor.java @@ -0,0 +1,136 @@ +package events.implementations; + +import java.util.ArrayList; +import java.util.List; + +import core.VSInternalProcess; +import core.time.VSVectorTime; + +/** + * A monitor that tracks vector clock changes and triggers events when + * vector timestamp conditions are met. This monitor is integrated into + * the process's vector clock update mechanism rather than being time-based. + * + * @author Paul C. Buetow + */ +public class VSVectorClockMonitor { + + private List vectorEvents; + private VSInternalProcess process; + private VSVectorTime lastCheckedVector; + + /** + * Constructor + */ + public VSVectorClockMonitor(VSInternalProcess process) { + this.process = process; + this.vectorEvents = new ArrayList<>(); + this.lastCheckedVector = null; + } + + /** + * Add a vector timestamp event to monitor + */ + public void addVectorEvent(VSTimestampTriggeredEvent event) { + if (event.getTimestampType() == VSTimestampTriggeredEvent.TimestampType.VECTOR && + !vectorEvents.contains(event)) { + vectorEvents.add(event); + } + } + + /** + * Remove a vector timestamp event from monitoring + */ + public void removeVectorEvent(VSTimestampTriggeredEvent event) { + vectorEvents.remove(event); + } + + /** + * Check all vector events when the vector clock changes. + * This should be called whenever the process's vector clock is updated. + */ + public void checkVectorEvents() { + if (vectorEvents.isEmpty()) { + return; + } + + VSVectorTime currentVector = process.getVectorTime(); + + // Only check if vector clock actually changed + if (currentVector == null || vectorClockEquals(currentVector, lastCheckedVector)) { + return; + } + + List triggeredEvents = new ArrayList<>(); + + for (VSTimestampTriggeredEvent event : vectorEvents) { + if (!event.hasTriggered()) { + // Initialize event if needed + if (event.getProcess() == null) { + event.init(process); + } + + // Check condition + if (event.checkCondition(process)) { + event.onStart(); // This will trigger the event + triggeredEvents.add(event); + + process.log("Vector timestamp event triggered: " + event.toString()); + } + } + } + + // Remove triggered events + vectorEvents.removeAll(triggeredEvents); + + // Update last checked vector + lastCheckedVector = currentVector != null ? currentVector.getCopy() : null; + } + + /** + * Check if two vector clocks are equal + */ + private boolean vectorClockEquals(VSVectorTime v1, VSVectorTime v2) { + if (v1 == null && v2 == null) { + return true; + } + if (v1 == null || v2 == null) { + return false; + } + + int maxSize = Math.max(v1.size(), v2.size()); + + for (int i = 0; i < maxSize; i++) { + long val1 = i < v1.size() ? v1.get(i) : 0; + long val2 = i < v2.size() ? v2.get(i) : 0; + + if (val1 != val2) { + return false; + } + } + + return true; + } + + /** + * Get the number of vector events being monitored + */ + public int getVectorEventCount() { + return vectorEvents.size(); + } + + /** + * Clear all vector events + */ + public void clearVectorEvents() { + vectorEvents.clear(); + lastCheckedVector = null; + } + + /** + * Get a copy of the monitored events list + */ + public List getVectorEvents() { + return new ArrayList<>(vectorEvents); + } +} \ No newline at end of file diff --git a/src/main/java/events/implementations/VSVectorTimestampEvent.java b/src/main/java/events/implementations/VSVectorTimestampEvent.java new file mode 100644 index 0000000..4d3b327 --- /dev/null +++ b/src/main/java/events/implementations/VSVectorTimestampEvent.java @@ -0,0 +1,142 @@ +package events.implementations; + +import core.VSInternalProcess; +import core.time.VSVectorTime; + +/** + * Concrete implementation of a Vector timestamp-triggered event. + * This event fires when a specific Vector timestamp condition is met. + * + * Example usage: + * - Fire when vector clock equals [3,2,1] + * - Fire when vector clock is greater than or equal to [5,0,2] + * - Fire when any element in vector clock reaches a threshold + * + * @author Paul C. Buetow + */ +public class VSVectorTimestampEvent extends VSTimestampTriggeredEvent { + + private String actionDescription; + private Runnable customAction; + + /** + * Constructor for basic Vector timestamp event + */ + public VSVectorTimestampEvent(VSVectorTime targetVector, ComparisonOperator op) { + super(targetVector, op); + this.actionDescription = "Vector timestamp condition met"; + } + + /** + * Constructor with custom action description + */ + public VSVectorTimestampEvent(VSVectorTime targetVector, ComparisonOperator op, String description) { + super(targetVector, op); + this.actionDescription = description; + } + + /** + * Constructor with custom action + */ + public VSVectorTimestampEvent(VSVectorTime targetVector, ComparisonOperator op, String description, Runnable action) { + super(targetVector, op); + this.actionDescription = description; + this.customAction = action; + } + + /** + * Default constructor for serialization + */ + public VSVectorTimestampEvent() { + super(); + this.actionDescription = "Vector timestamp event"; + } + + @Override + public void onInit() { + super.onInit(); + } + + @Override + protected void onTimestampReached() { + VSInternalProcess internalProcess = (VSInternalProcess) process; + + // Log the event + String message = String.format("Vector timestamp event triggered: %s (current: %s, target: %s %s)", + actionDescription, + internalProcess.getVectorTime(), + targetVectorTime, + operator); + + internalProcess.log(message); + + // Execute custom action if provided + if (customAction != null) { + try { + customAction.run(); + } catch (Exception e) { + internalProcess.log("Error executing custom action: " + e.getMessage()); + } + } + + // Default behavior: change process color to indicate trigger + changeProcessColor(); + } + + /** + * Change process color to indicate the timestamp event has been triggered + */ + protected void changeProcessColor() { + if (process instanceof VSInternalProcess) { + VSInternalProcess internalProcess = (VSInternalProcess) process; + // Change to highlight color temporarily + internalProcess.highlightOn(); + } + } + + /** + * Convenience method to create event that triggers when any vector element reaches threshold + */ + public static VSVectorTimestampEvent createThresholdEvent(int processCount, long threshold, String description) { + VSVectorTime targetVector = new VSVectorTime(0); + for (int i = 0; i < processCount; i++) { + targetVector.add(threshold); + } + return new VSVectorTimestampEvent(targetVector, ComparisonOperator.GREATER_EQUAL, description); + } + + /** + * Convenience method to create event that triggers when specific process element reaches value + */ + public static VSVectorTimestampEvent createProcessThresholdEvent(int processCount, int processIndex, long threshold, String description) { + VSVectorTime targetVector = new VSVectorTime(0); + for (int i = 0; i < processCount; i++) { + targetVector.add(i == processIndex ? threshold : 0L); + } + return new VSVectorTimestampEvent(targetVector, ComparisonOperator.GREATER_EQUAL, description); + } + + @Override + public String toString() { + return String.format(" [VectorTrigger: %s %s - %s]", + targetVectorTime, operator, actionDescription); + } + + // Getters and setters + public String getActionDescription() { + return actionDescription; + } + + public void setActionDescription(String description) { + this.actionDescription = description; + } + + public void setCustomAction(Runnable action) { + this.customAction = action; + } + + @Override + protected String createShortname(String savedShortname) { + return "VectorTrigger"; + } +} \ No newline at end of file -- cgit v1.2.3