Monitor Object pattern #466
This commit is contained in:
		
							
								
								
									
										24
									
								
								monitor-object/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								monitor-object/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | <?xml version="1.0"?> | ||||||
|  | <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" | ||||||
|  |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||||||
|  |   <modelVersion>4.0.0</modelVersion> | ||||||
|  |   <parent> | ||||||
|  |     <groupId>com.iluwatar</groupId> | ||||||
|  |     <artifactId>java-design-patterns</artifactId> | ||||||
|  |     <version>1.20.0-SNAPSHOT</version> | ||||||
|  |   </parent> | ||||||
|  |   <artifactId>monitor-object</artifactId> | ||||||
|  |   <name>monitor-object</name> | ||||||
|  |   <dependencies> | ||||||
|  |     <dependency> | ||||||
|  |       <groupId>org.junit.jupiter</groupId> | ||||||
|  |       <artifactId>junit-jupiter-api</artifactId> | ||||||
|  |       <scope>test</scope> | ||||||
|  |     </dependency> | ||||||
|  |     <dependency> | ||||||
|  |       <groupId>org.junit.jupiter</groupId> | ||||||
|  |       <artifactId>junit-jupiter-engine</artifactId> | ||||||
|  |       <scope>test</scope> | ||||||
|  |     </dependency> | ||||||
|  |   </dependencies> | ||||||
|  | </project> | ||||||
| @@ -0,0 +1,214 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | import java.util.ArrayList; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A class for Monitors. Monitors provide coordination of concurrent threads. | ||||||
|  |  * Each Monitor protects some resource, usually data. At each point in time a | ||||||
|  |  * monitor object is occupied by at most one thread. | ||||||
|  |  */ | ||||||
|  | public abstract class AbstractMonitor { | ||||||
|  |   final Semaphore entrance = new Semaphore(1); | ||||||
|  |   volatile Thread occupant = null; | ||||||
|  |   private final ArrayList<MonitorListener> listOfListeners = new ArrayList<>(); | ||||||
|  |   private final String name; | ||||||
|  |  | ||||||
|  |   public String getName() { | ||||||
|  |     return name; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected AbstractMonitor() { | ||||||
|  |     this(null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected AbstractMonitor(String name) { | ||||||
|  |     this.name = name; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * The invariant. The default implementation always returns true. This method | ||||||
|  |    * should be overridden if at all possible with the strongest economically | ||||||
|  |    * evaluable invariant. | ||||||
|  |    */ | ||||||
|  |   protected boolean invariant() { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Enter the monitor. Any thread calling this method is delayed until the | ||||||
|  |    * monitor is unoccupied. Upon returning from this method, the monitor is | ||||||
|  |    * considered occupied. A thread must not attempt to enter a Monitor it is | ||||||
|  |    * already in. | ||||||
|  |    */ | ||||||
|  |   protected void enter() { | ||||||
|  |     notifyCallEnter(); | ||||||
|  |     entrance.acquire(); | ||||||
|  |     // The following assertion should never trip! | ||||||
|  |     Assertion.check(occupant == null, "2 threads in one monitor"); | ||||||
|  |     occupant = Thread.currentThread(); | ||||||
|  |     notifyReturnFromEnter(); | ||||||
|  |     Assertion.check(invariant(), "Invariant of monitor " + getName()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Leave the monitor. After returning from this method, the thread no longer | ||||||
|  |    * occupies the monitor. Only a thread that is in the monitor may leave it. | ||||||
|  |    *  | ||||||
|  |    * @throws AssertionError | ||||||
|  |    *             if the thread that leaves is not the occupant. | ||||||
|  |    */ | ||||||
|  |   protected void leave() { | ||||||
|  |     notifyLeaveMonitor(); | ||||||
|  |     leaveWithoutATrace(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Leave the monitor. After returning from this method, the thread no longer | ||||||
|  |    * occupies the monitor. Only a thread that is in the monitor may leave it. | ||||||
|  |    *  | ||||||
|  |    * @throws AssertionError | ||||||
|  |    *             if the thread that leaves is not the occupant. | ||||||
|  |    */ | ||||||
|  |   protected <T> T leave(T result) { | ||||||
|  |     leave(); | ||||||
|  |     return result; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void leaveWithoutATrace() { | ||||||
|  |     Assertion.check(invariant(), "Invariant of monitor " + getName()); | ||||||
|  |     Assertion.check(occupant == Thread.currentThread(), "Thread is not occupant"); | ||||||
|  |     occupant = null; | ||||||
|  |     entrance.release(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Run the runnable inside the monitor. Any thread calling this method will be | ||||||
|  |    * delayed until the monitor is empty. The "run" method of its argument is then | ||||||
|  |    * executed within the protection of the monitor. When the run method returns, | ||||||
|  |    * if the thread still occupies the monitor, it leaves the monitor. | ||||||
|  |    *  | ||||||
|  |    * @param runnable | ||||||
|  |    *            A Runnable object. | ||||||
|  |    */ | ||||||
|  |   protected void doWithin(Runnable runnable) { | ||||||
|  |     enter(); | ||||||
|  |     try { | ||||||
|  |       runnable.run(); | ||||||
|  |     } finally { | ||||||
|  |       if (occupant == Thread.currentThread()) { | ||||||
|  |         leave(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Run the runnable inside the monitor. Any thread calling this method will be | ||||||
|  |    * delayed until the monitor is empty. The "run" method of its argument is then | ||||||
|  |    * executed within the protection of the monitor. When the run method returns, | ||||||
|  |    * if the thread still occupies the monitor, it leaves the monitor. Thus the | ||||||
|  |    * signalAndLeave method may be called within the run method. | ||||||
|  |    *  | ||||||
|  |    * @param runnable | ||||||
|  |    *            A RunnableWithResult object. | ||||||
|  |    * @return The value computed by the run method of the runnable. | ||||||
|  |    */ | ||||||
|  |   protected <T> T doWithin(RunnableWithResult<T> runnable) { | ||||||
|  |     enter(); | ||||||
|  |     try { | ||||||
|  |       return runnable.run(); | ||||||
|  |     } finally { | ||||||
|  |       if (occupant == Thread.currentThread()) { | ||||||
|  |         leave(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Create a condition queue associated with a checked Assertion. The Assertion | ||||||
|  |    * will be checked prior to an signal of the condition. | ||||||
|  |    */ | ||||||
|  |   protected Condition makeCondition(Assertion prop) { | ||||||
|  |     return makeCondition(null, prop); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Create a condition queue with no associated checked Assertion. | ||||||
|  |    */ | ||||||
|  |   protected Condition makeCondition() { | ||||||
|  |     return makeCondition(null, TrueAssertion.singleton); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Create a condition queue associated with a checked Assertion. The Assertion | ||||||
|  |    * will be checked prior to an signal of the condition. | ||||||
|  |    */ | ||||||
|  |   protected Condition makeCondition(String name, Assertion prop) { | ||||||
|  |     return new Condition(name, this, prop); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Create a condition queue with no associated checked Assertion. | ||||||
|  |    */ | ||||||
|  |   protected Condition makeCondition(String name) { | ||||||
|  |     return makeCondition(name, TrueAssertion.singleton); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Register a listener. */ | ||||||
|  |   public void addListener(MonitorListener newListener) { | ||||||
|  |     listOfListeners.add(newListener); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void notifyCallEnter() { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.callEnterMonitor(this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void notifyReturnFromEnter() { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.returnFromEnterMonitor(this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void notifyLeaveMonitor() { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.leaveMonitor(this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void notifyCallAwait(Condition condition) { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.callAwait(condition, this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void notifyReturnFromAwait(Condition condition) { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.returnFromAwait(condition, this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void notifySignallerAwakesAwaitingThread(Condition condition) { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.signallerAwakesAwaitingThread(condition, this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void notifySignallerLeavesTemporarily(Condition condition) { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.signallerLeavesTemporarily(condition, this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void notifySignallerReenters(Condition condition) { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.signallerReenters(condition, this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void notifySignallerLeavesMonitor(Condition condition) { | ||||||
|  |     for (MonitorListener listener : listOfListeners) { | ||||||
|  |       listener.signallerLeavesMonitor(condition, this); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A final class for Monitors. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | public final class Monitor extends AbstractMonitor { | ||||||
|  |  | ||||||
|  |   private Assertion invariant; | ||||||
|  |  | ||||||
|  |   public Monitor() { | ||||||
|  |     this(TrueAssertion.singleton); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public Monitor(Assertion invariant) { | ||||||
|  |     this.invariant = invariant; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public Monitor(String name) { | ||||||
|  |     this(name, TrueAssertion.singleton); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public Monitor(String name, Assertion invariant) { | ||||||
|  |     super(name); | ||||||
|  |     this.invariant = invariant; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public boolean invariant() { | ||||||
|  |     return invariant.isTrue(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void enter() { | ||||||
|  |     super.enter(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void leave() { | ||||||
|  |     super.leave(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public <T> T leave(T result) { | ||||||
|  |     return super.leave(result); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void doWithin(Runnable runnable) { | ||||||
|  |     super.doWithin(runnable); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public <T> T doWithin(RunnableWithResult<T> runnable) { | ||||||
|  |     return super.doWithin(runnable); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public Condition makeCondition() { | ||||||
|  |     return super.makeCondition(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public Condition makeCondition(Assertion assertion) { | ||||||
|  |     return super.makeCondition(assertion); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public Condition makeCondition(String name) { | ||||||
|  |     return super.makeCondition(name); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public Condition makeCondition(String name, Assertion assertion) { | ||||||
|  |     return super.makeCondition(name, assertion); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | public interface MonitorListener { | ||||||
|  |  | ||||||
|  |   void nameThisThread(String name); | ||||||
|  |  | ||||||
|  |   void callEnterMonitor(AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void returnFromEnterMonitor(AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void leaveMonitor(AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void callAwait(Condition condition, AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void returnFromAwait(Condition condition, AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void signallerAwakesAwaitingThread(Condition condition, AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void signallerLeavesTemporarily(Condition condition, AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void signallerReenters(Condition condition, AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  |   void signallerLeavesMonitor(Condition condition, AbstractMonitor monitor); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,5 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | public interface RunnableWithResult<T> { | ||||||
|  |   public T run(); | ||||||
|  | } | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
| @@ -0,0 +1,66 @@ | |||||||
|  | package com.iluwatar.monitor.examples; | ||||||
|  |  | ||||||
|  | import com.iluwatar.monitor.AbstractMonitor; | ||||||
|  | import com.iluwatar.monitor.Condition; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * FIFO Queue implementation using {@link AbstractMonitor}. | ||||||
|  |  */ | ||||||
|  | public class Queue extends AbstractMonitor { | ||||||
|  |  | ||||||
|  |   private final int capacity = 10; | ||||||
|  |  | ||||||
|  |   private final Object[] queue = new Object[capacity]; | ||||||
|  |  | ||||||
|  |   private volatile int count = 0; | ||||||
|  |    | ||||||
|  |   private volatile int front = 0; | ||||||
|  |  | ||||||
|  |   /** Awaiting ensures: count < capacity. */ | ||||||
|  |   private final Condition notFull = makeCondition(); | ||||||
|  |  | ||||||
|  |   /** Awaiting ensures: count > 0. */ | ||||||
|  |   private final Condition notEmpty = makeCondition(); | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Method to pop the front element from queue. | ||||||
|  |    * @return the top most element | ||||||
|  |    */ | ||||||
|  |   public Object fetch() { | ||||||
|  |     enter(); | ||||||
|  |     if (!(count > 0)) { | ||||||
|  |       notEmpty.await(); | ||||||
|  |       assert count > 0; | ||||||
|  |     } | ||||||
|  |     count--; | ||||||
|  |     front = (front + 1) % capacity; | ||||||
|  |     assert count < capacity; | ||||||
|  |     notFull.signal(); | ||||||
|  |     leave(); | ||||||
|  |     Object value = queue[front]; | ||||||
|  |     return value; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Method to push an element in queue. | ||||||
|  |    * @param value the element to be pushed | ||||||
|  |    */ | ||||||
|  |   public void deposit(Object value) { | ||||||
|  |     enter(); | ||||||
|  |     if (!(count < capacity)) { | ||||||
|  |       notFull.await(); | ||||||
|  |       assert count < capacity; | ||||||
|  |     } | ||||||
|  |     queue[(front + count) % capacity] = value; | ||||||
|  |     count++; | ||||||
|  |     assert count > 0; | ||||||
|  |     notEmpty.signal(); | ||||||
|  |     leave(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected boolean invariant() { | ||||||
|  |     return 0 <= count && count <= capacity && 0 <= front && front < capacity; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | package com.iluwatar.monitor.examples; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Monitor Example. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | public interface VoteInterface { | ||||||
|  |   public boolean castVoteAndWaitForResult(boolean vote); | ||||||
|  | } | ||||||
| @@ -0,0 +1,63 @@ | |||||||
|  | package com.iluwatar.monitor.examples; | ||||||
|  |  | ||||||
|  | import com.iluwatar.monitor.AbstractMonitor; | ||||||
|  | import com.iluwatar.monitor.Assertion; | ||||||
|  | import com.iluwatar.monitor.Condition; | ||||||
|  | import com.iluwatar.monitor.RunnableWithResult; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Monitor Example. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | public class VoteMonitor extends AbstractMonitor implements VoteInterface { | ||||||
|  |  | ||||||
|  |   private final int totalVotes; | ||||||
|  |   private int votesFor = 0; | ||||||
|  |   private int votesAgainst = 0; | ||||||
|  |  | ||||||
|  |   private Condition electionDone = makeCondition(new Assertion() { | ||||||
|  |     @Override | ||||||
|  |     public boolean isTrue() { | ||||||
|  |       return votesFor + votesAgainst == totalVotes; | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   public VoteMonitor(int n) { | ||||||
|  |     assert n > 0; | ||||||
|  |     this.totalVotes = n; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected boolean invariant() { | ||||||
|  |     return 0 <= votesFor && 0 <= votesAgainst && votesFor + votesAgainst < totalVotes; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Method to cast a vote and wait for the result. | ||||||
|  |    */ | ||||||
|  |   public boolean castVoteAndWaitForResult(final boolean vote) { | ||||||
|  |     return doWithin(new RunnableWithResult<Boolean>() { | ||||||
|  |       public Boolean run() { | ||||||
|  |         if (vote) { | ||||||
|  |           votesFor++; | ||||||
|  |         } else { | ||||||
|  |           votesAgainst++; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         electionDone.conditionalAwait(); | ||||||
|  |  | ||||||
|  |         // Assert: votesFor+votesAgainst == N | ||||||
|  |         boolean result = votesFor > votesAgainst; | ||||||
|  |  | ||||||
|  |         if (!electionDone.isEmpty()) { | ||||||
|  |           electionDone.signalAndLeave(); | ||||||
|  |         } else { | ||||||
|  |           votesFor = votesAgainst = 0; | ||||||
|  |         } | ||||||
|  |         // At this point the thread could be occupying | ||||||
|  |         // the monitor, or not! | ||||||
|  |         return result; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertThrows; | ||||||
|  |  | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Test Cases for Assertion. | ||||||
|  |  */ | ||||||
|  | public class AssertionTest { | ||||||
|  |   int varX = 0; | ||||||
|  |   int varY = 0; | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testAssertionTrue() { | ||||||
|  |     Assertion a = new MyAssertion(); | ||||||
|  |     assertEquals(true, a.isTrue()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testAssertionFalse() { | ||||||
|  |     Assertion a = new MyAssertion(); | ||||||
|  |     a.check(); | ||||||
|  |     varX = 1; | ||||||
|  |     assertEquals(false, a.isTrue()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testAssertionError() { | ||||||
|  |     assertThrows(NullPointerException.class, () -> { | ||||||
|  |       Assertion a = new MyAssertion(); | ||||||
|  |       a.check(); | ||||||
|  |       varX = 1; | ||||||
|  |       a.check(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   class MyAssertion extends Assertion { | ||||||
|  |     public boolean isTrue() { | ||||||
|  |       return varX == varY; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,43 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  |  | ||||||
|  | import org.junit.jupiter.api.BeforeAll; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  |  | ||||||
|  | import com.iluwatar.monitor.examples.VoteInterface; | ||||||
|  | import com.iluwatar.monitor.examples.VoteMonitor; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Test Case for Thread Signaling. | ||||||
|  |  */ | ||||||
|  | public class ThreadSignalTest { | ||||||
|  |  | ||||||
|  |   private Voter v0; | ||||||
|  |   private Voter v1; | ||||||
|  |   private Voter v2; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Setup method for Test Case. | ||||||
|  |    */ | ||||||
|  |   @BeforeAll | ||||||
|  |   public void setUp() { | ||||||
|  |     VoteInterface vm = new VoteMonitor(3); | ||||||
|  |     v0 = new Voter0(vm); | ||||||
|  |     v1 = new Voter1(vm); | ||||||
|  |     v2 = new Voter2(vm); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testVotingResult() throws InterruptedException { | ||||||
|  |     v0.start(); | ||||||
|  |     v1.start(); | ||||||
|  |     v2.start(); | ||||||
|  |     v0.join(); | ||||||
|  |     v1.join(); | ||||||
|  |     v2.join(); | ||||||
|  |     assertEquals("Passed", v0.getTestResult()); | ||||||
|  |     assertEquals("Passed", v1.getTestResult()); | ||||||
|  |     assertEquals("Passed", v2.getTestResult()); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								monitor-object/src/test/java/com/iluwatar/monitor/Voter.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								monitor-object/src/test/java/com/iluwatar/monitor/Voter.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | import com.iluwatar.monitor.examples.VoteInterface; | ||||||
|  |  | ||||||
|  | abstract class Voter extends Thread { | ||||||
|  |  | ||||||
|  |   private VoteInterface vm; | ||||||
|  |  | ||||||
|  |   private String testResult; | ||||||
|  |  | ||||||
|  |   public String getTestResult() { | ||||||
|  |     return testResult; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void setTestResult(String testResult) { | ||||||
|  |     this.testResult = testResult; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Voter(VoteInterface vm) { | ||||||
|  |     this.vm = vm; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void run() { | ||||||
|  |     for (int i = 0; i < 100; ++i) { | ||||||
|  |       boolean vote = makeVote(i); | ||||||
|  |       boolean consensus = vm.castVoteAndWaitForResult(vote); | ||||||
|  |       boolean expected = i % 6 == 1 || i % 6 == 2 || i % 6 == 5; | ||||||
|  |       if (expected != consensus) { | ||||||
|  |         System.out.println("Failed"); | ||||||
|  |         setTestResult("Failed"); | ||||||
|  |         System.exit(1); | ||||||
|  |       } | ||||||
|  |       setTestResult("Passed"); | ||||||
|  |       System.out.println(i + ": " + consensus); | ||||||
|  |     } | ||||||
|  |     System.out.println("Done"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   abstract boolean makeVote(int i); | ||||||
|  | } | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | import com.iluwatar.monitor.examples.VoteInterface; | ||||||
|  |  | ||||||
|  | class Voter0 extends Voter { | ||||||
|  |   Voter0(VoteInterface vm) { | ||||||
|  |     super(vm); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   boolean makeVote(int i) { | ||||||
|  |     return i % 2 == 1; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | import com.iluwatar.monitor.examples.VoteInterface; | ||||||
|  |  | ||||||
|  | class Voter1 extends Voter { | ||||||
|  |   Voter1(VoteInterface vm) { | ||||||
|  |     super(vm); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   boolean makeVote(int i) { | ||||||
|  |     return i % 3 == 2; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | package com.iluwatar.monitor; | ||||||
|  |  | ||||||
|  | import com.iluwatar.monitor.examples.VoteInterface; | ||||||
|  |  | ||||||
|  | class Voter2 extends Voter { | ||||||
|  |   Voter2(VoteInterface vm) { | ||||||
|  |     super(vm); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   boolean makeVote(int i) { | ||||||
|  |     return i % 3 != 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -162,6 +162,7 @@ | |||||||
|         <module>trampoline</module> |         <module>trampoline</module> | ||||||
|         <module>serverless</module> |         <module>serverless</module> | ||||||
| 	    <module>component-object</module> | 	    <module>component-object</module> | ||||||
|  | 	    <module>monitor-object</module> | ||||||
|     </modules> |     </modules> | ||||||
|  |  | ||||||
|     <repositories> |     <repositories> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user