From 98ffbf5f382cb1f97c8a6b004a04bea91a40f34a Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Tue, 13 May 2014 13:30:22 -0500
Subject: [PATCH 001/202] Fixed mProducerCounter to mConsumerCounter.
---
.../src/edu/vuum/mooca/SynchronizedQueue.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java b/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
index c8a8c5edc..c4ffb3c18 100644
--- a/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
+++ b/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
@@ -186,7 +186,7 @@ public void run() {
System.out.println("Exception " + e.toString()
+ " occurred in consumerRunnable");
// Indicate a timeout.
- mProducerCounter = TIMEOUT_OCCURRED;
+ mConsumerCounter = TIMEOUT_OCCURRED;
return;
} catch (Exception e) {
System.out.println("Exception " + e.toString()
From 79b6ed5e88c6027100810e1d2af0e3700e1eb932 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 14 May 2014 02:31:58 -0500
Subject: [PATCH 002/202] (re)fixed the project name to include the W1-A0
prefix.
---
assignments/week-1-assignment-0/.project | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assignments/week-1-assignment-0/.project b/assignments/week-1-assignment-0/.project
index 1108d1f6e..5b2ee43b7 100644
--- a/assignments/week-1-assignment-0/.project
+++ b/assignments/week-1-assignment-0/.project
@@ -1,6 +1,6 @@
- SynchronizedQueueTest
+ W1-A0-SynchronizedQueueTest
From bec5722173076359292792ce2ed76da36a97f652 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 14 May 2014 15:23:24 -0500
Subject: [PATCH 003/202] Renamed mIterationCount to mTurnCountDown.
---
.../console/src/edu/vuum/mocca/PlayPingPong.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java b/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java
index 2e18703c7..aef9f4700 100644
--- a/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java
+++ b/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java
@@ -178,7 +178,7 @@ static class PingPongThreadCond extends PingPongThread
/**
* Number of times we've iterated thus far in our "turn".
*/
- private int mIterationCount = 0;
+ private int mTurnCountDown = 0;
/**
* Id for the other thread.
@@ -208,7 +208,7 @@ public void setOtherThreadId(long otherThreadId)
boolean isOwner)
{
super(stringToPrint);
- mIterationCount = mMaxTurns;
+ mTurnCountDown = mMaxTurns;
mLock = lock;
mConds[FIRST_COND] = firstCond;
mConds[SECOND_COND] = secondCond;
@@ -235,11 +235,11 @@ void acquire() {
void release() {
mLock.lock();
- --mIterationCount;
+ --mTurnCountDown;
- if (mIterationCount == 0) {
+ if (mTurnCountDown == 0) {
mThreadOwner = mOtherThreadId;
- mIterationCount = mMaxTurns;
+ mTurnCountDown = mMaxTurns;
mConds[SECOND_COND].signal();
}
mLock.unlock();
From 6618744d50e857ce27d1c1d813c1f467700e4c22 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 14 May 2014 18:49:29 -0500
Subject: [PATCH 004/202] Fixed "Lock" to be "Long".
---
.../week-2-assignment-1/Assignment-Description.txt | 6 +++---
ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java | 8 ++++----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/assignments/week-2-assignment-1/Assignment-Description.txt b/assignments/week-2-assignment-1/Assignment-Description.txt
index 5ce1096ec..01006d970 100644
--- a/assignments/week-2-assignment-1/Assignment-Description.txt
+++ b/assignments/week-2-assignment-1/Assignment-Description.txt
@@ -3,7 +3,7 @@ Programming Assignment 0
In this first (intentionally simple) assignment, you will use a Java
ReentrantReadWriteLock to implement a subset of the
java.util.concurrent.atomic.AtomicLong class, which we call
-SimpleAtomicLock. The goal is to understand how to use
+SimpleAtomicLong. The goal is to understand how to use
ReentrantReadWriteLock to serialize access to a variable that's shared
by multiple threads. The SimpleAtomicLongTest.java program creates
two Threads that increment and decrement the AtomicLong 10,000,000
@@ -67,11 +67,11 @@ http://www.courera.org/course/posa
To compile this code you can either use the provided Eclipse project
or simply type
-% javac SimpleAtomicLockTest.java SimpleAtomicLock.java
+% javac SimpleAtomicLongTest.java SimpleAtomicLong.java
on the command-line and then run the resulting class file by typing
-% java SimpleAtomicLockTest
+% java SimpleAtomicLongTest
The output for a correct solution should look exactly like this:
diff --git a/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java b/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java
index aef9f4700..52560fe57 100644
--- a/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java
+++ b/ex/PingPong/console/src/edu/vuum/mocca/PlayPingPong.java
@@ -188,7 +188,7 @@ static class PingPongThreadCond extends PingPongThread
/**
* Thread whose turn it currently is.
*/
- private static long mThreadOwner;
+ private static long mTurnOwner;
public void setOtherThreadId(long otherThreadId)
{
@@ -213,7 +213,7 @@ public void setOtherThreadId(long otherThreadId)
mConds[FIRST_COND] = firstCond;
mConds[SECOND_COND] = secondCond;
if (isOwner)
- mThreadOwner = this.getId();
+ mTurnOwner = this.getId();
}
/**
@@ -222,7 +222,7 @@ public void setOtherThreadId(long otherThreadId)
void acquire() {
mLock.lock();
- while (mThreadOwner != this.getId()) {
+ while (mTurnOwner != this.getId()) {
mConds[FIRST_COND].awaitUninterruptibly();
}
@@ -238,7 +238,7 @@ void release() {
--mTurnCountDown;
if (mTurnCountDown == 0) {
- mThreadOwner = mOtherThreadId;
+ mTurnOwner = mOtherThreadId;
mTurnCountDown = mMaxTurns;
mConds[SECOND_COND].signal();
}
From 9a4a563a725996ac02e68a3ac0321dd8cee011fe Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 14 May 2014 19:51:02 -0500
Subject: [PATCH 005/202] Added a new test for assignment 0.
---
assignments/week-1-assignment-0-v2/.classpath | 7 +
assignments/week-1-assignment-0-v2/.project | 17 +
.../Assignment-Description.txt | 90 +++++
.../edu/vuum/mooca/BuggyBlockingQueue.java | 129 +++++++
.../src/edu/vuum/mooca/SynchronizedQueue.java | 336 ++++++++++++++++++
.../edu/vuum/mooca/SynchronizedQueueImpl.java | 42 +++
.../edu/vuum/mooca/SynchronizedQueueTest.java | 121 +++++++
7 files changed, 742 insertions(+)
create mode 100644 assignments/week-1-assignment-0-v2/.classpath
create mode 100644 assignments/week-1-assignment-0-v2/.project
create mode 100644 assignments/week-1-assignment-0-v2/Assignment-Description.txt
create mode 100644 assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/BuggyBlockingQueue.java
create mode 100644 assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java
create mode 100644 assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java
create mode 100644 assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueTest.java
diff --git a/assignments/week-1-assignment-0-v2/.classpath b/assignments/week-1-assignment-0-v2/.classpath
new file mode 100644
index 000000000..b10b8d9b2
--- /dev/null
+++ b/assignments/week-1-assignment-0-v2/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/assignments/week-1-assignment-0-v2/.project b/assignments/week-1-assignment-0-v2/.project
new file mode 100644
index 000000000..5b2ee43b7
--- /dev/null
+++ b/assignments/week-1-assignment-0-v2/.project
@@ -0,0 +1,17 @@
+
+
+ W1-A0-SynchronizedQueueTest
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/assignments/week-1-assignment-0-v2/Assignment-Description.txt b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
new file mode 100644
index 000000000..4d4ff565a
--- /dev/null
+++ b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
@@ -0,0 +1,90 @@
+Week 1: Programming Assignment 0
+
+Released Monday, May 12, 2014
+Due Monday, May 26th, 2014
+
+In this (intentionally simple) initial assignment, you will use Java
+Threads to test several implementations of the Java BlockingQueue
+interface. The goal is to learn how to (1) create, (2) start, (3)
+interrupt, and (4) wait for the completion of multiple Java Threads.
+The test program also illustrates some problems that can occur if Java
+Threads concurrently access an object that isn't synchronized
+properly.
+
+In the "src/edu/vuum/mocca" folder in this directory you'll find the
+SynchronizedQueueImpl.java class, which contains the skeleton Java
+code that you'll implement by completing the "TODO - You fill in here"
+comments to provide a working solution. DO NOT CHANGE THE OVERALL
+STRUCTURE OF THE SKELETON - just fill in the "TODO - You fill in here"
+portions!!!
+
+In particular, you'll need to do the following:
+
+. Implement the "TODO" portions of the createThreads() and
+ startThreads() methods so that the two Java mProducer and mConsumer
+ Threads are created and started to run the mProducerRunnable and
+ mConsumerRunnable objects. Please keep the "TODO" comments in the
+ code so that peer reviewers can find them quickly during the
+ assessment phase.
+
+. Implement the "TODO" portion of the interruptThreads() method, which
+ interrupts both the mProducer and mConsumer Threads so they will
+ shutdown.
+
+. Implement the "TODO" portion of the "joinThreads()" method, which
+ waits for both Threads to exit before continuing with the test
+ (which is done for you by the testQueue() template method in the
+ SynchronizedQueue.java file).
+
+. If you'd like to enable verbose debugging output please set the
+ diagnosticsEnabled flag in SynchronizedQueueImpl to true (it
+ defaults to false).
+
+All the information needed to write this code is described in these
+videos:
+
+ Section 1: Module 2: Part 1: Overview of Java Threads (Part 1)
+ Section 1: Module 2: Part 2: Overview of Java Threads (Part 2)
+ Section 1: Module 2: Part 3: Motivating Java Synchronization and Scheduling Mechanisms
+
+Make sure to watch these videos and read all the supplied Java code
+carefully prior to starting the assignment. These videos are
+available at
+
+https://class.coursera.org/posa-002/lecture
+
+We'll also discuss this assignment specification (and later its
+solution) in the POSA MOOC "Virtual Office Hours", which are described
+in item #38 at the POSA MOOC FAQ available from
+
+http://www.courera.org/course/posa
+
+The SynchronizerQueueTest.java file uses JUnit to run the tests. We
+do this to automate the testing process and leverage the integration
+of JUnit with Eclipse, as described here:
+
+http://www.vogella.com/tutorials/JUnit/article.html#eclipse
+
+When you first open the project in Eclipse, you might see compile
+errors if JUnit is not included in your build path. To fix these
+errors, open SynchronizedQueueTest.java, hover over "org.junit," and
+click "Fix project setup." Make sure "Add JUnit 4 library to the
+build path" is selected and then click "OK." At this point, the
+compile errors should disappear!
+
+To run the JUnit tests in Eclipse, right-click on
+SynchronizedQueueTest.java and go to "Run As > JUnit Test". The JUnit
+view will pop up in Eclipse and run the tests contained therein. All
+tests should pass. The ArrayBlockingQueue will pass because your
+testQueue method runs successfully. The tests for BuggyBlockingQueue
+(which is an intentionally flawed class), should "pass" if some error
+occurs while running testQueue (these errors are expected). As long
+as these JUnit tests both "pass" successfully your program will be be
+consider "correct" for the purposes of assessing this assignment.
+
+If the tests run and "pass," you should see check-marks next to each
+of the tests in the JUnit view. If you set the diagnosticsEnabled
+flag to true then debugging output will be printed to the console as
+the tests run. This text is for informational purposes only and have
+no bearing on whether your program is "correct," but will help you to
+better understand what it's doing.
diff --git a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/BuggyBlockingQueue.java b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/BuggyBlockingQueue.java
new file mode 100644
index 000000000..2cfebfcc6
--- /dev/null
+++ b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/BuggyBlockingQueue.java
@@ -0,0 +1,129 @@
+package edu.vuum.mooca;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @class BuggyBlockingQueue
+ *
+ * @brief Defines a buggy version of the BlockingQueue interface that
+ * doesn't implement any synchronization mechanisms, so of
+ * course it will fail horribly, which is the intent!
+ */
+public class BuggyBlockingQueue implements BlockingQueue {
+ /**
+ * ArrayList doesn't provide any synchronization, so it will not
+ * work correctly when called from multiple Java Threads.
+ */
+ private ArrayList mList = null;
+
+ /**
+ * Constructor just creates an ArrayList of the appropriate size.
+ */
+ public BuggyBlockingQueue(int initialSize) {
+ mList = new ArrayList(initialSize);
+ }
+
+ /**
+ * Returns the number of elements in this queue.
+ */
+ public int size() {
+ return mList.size();
+ }
+
+ /**
+ * Insert msg at the tail of the queue, but doesn't block if the
+ * queue is full.
+ */
+ public void put(E msg) throws InterruptedException {
+ mList.add(msg);
+ }
+
+ /**
+ * Remove msg from the head of the queue, but doesn't block if the
+ * queue is empty.
+ */
+ public E take() throws InterruptedException {
+ return mList.remove(0);
+ }
+
+ /**
+ * All these methods are inherited from the BlockingQueue
+ * interface. They are defined as no-ops to ensure the "Buggyness"
+ * of this class ;-)
+ */
+ public int drainTo(Collection super E> c) {
+ return 0;
+ }
+ public int drainTo(Collection super E> c, int maxElements) {
+ return 0;
+ }
+ public boolean contains(Object o) {
+ return false;
+ }
+ public boolean remove(Object o) {
+ return false;
+ }
+ public int remainingCapacity() {
+ return 0;
+ }
+ public E poll() {
+ return null;
+ }
+ public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+ return take();
+ }
+ public E peek() {
+ return null;
+ }
+ public boolean offer(E e) {
+ return false;
+ }
+ public boolean offer(E e, long timeout, TimeUnit unit) {
+ try {
+ put(e);
+ }
+ catch (InterruptedException ex) {
+ // Just swallow this exception for this simple (buggy) test.
+ }
+ return true;
+ }
+ public boolean add(E e) {
+ return false;
+ }
+ public E element() {
+ return null;
+ }
+ public E remove() {
+ return null;
+ }
+ public void clear() {
+ }
+ public boolean retainAll(Collection> collection) {
+ return false;
+ }
+ public boolean removeAll(Collection> collection) {
+ return false;
+ }
+ public boolean addAll(Collection extends E> collection) {
+ return false;
+ }
+ public boolean containsAll(Collection> collection) {
+ return false;
+ }
+ public Object[] toArray() {
+ return null;
+ }
+ public T[] toArray(T[] array) {
+ return null;
+ }
+ public Iterator iterator() {
+ return null;
+ }
+ public boolean isEmpty() {
+ return false;
+ }
+}
diff --git a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java
new file mode 100644
index 000000000..25437d26e
--- /dev/null
+++ b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java
@@ -0,0 +1,336 @@
+package edu.vuum.mooca;
+import java.util.concurrent.*;
+
+/**
+ * @class SynchronizedQueue
+ *
+ * @brief This class tests the use of Java Threads and several
+ * implementations of the Java BlockingQueue interface. It
+ * plays the role of the Abstract Class in the Template Method
+ * pattern.
+ */
+public abstract class SynchronizedQueue {
+ /**
+ * Keep track of the number of times the producer test iterates.
+ */
+ static volatile int mProducerCounter = 0;
+
+ /**
+ * Keep track of the number of times the consumer test iterates.
+ */
+ static volatile int mConsumerCounter = 0;
+
+ /**
+ * Maximum timeout.
+ */
+ static final int TIMEOUT_SECONDS = 5;
+
+ /**
+ * Error value for a timeout.
+ */
+ static final int TIMEOUT_OCCURRED = -1;
+
+ /**
+ * Error value for a failure.
+ */
+ static final int FAILURE_OCCURRED = -2;
+
+ /**
+ * @class SynchronizedQueueResult
+ *
+ * @brief Enumerated type for return values of testing logic, has
+ * String for easy output.
+ */
+ public enum SynchronizedQueueResult {
+ RAN_PROPERLY("Threads Ran Properly."),
+ JOIN_NEVER_CALLED("Join() never called."),
+ THREADS_NEVER_RAN("Threads never ran."),
+ THREADS_NEVER_INTERUPTED("Threads never interrupted."),
+ THREADS_THREW_EXCEPTION("Thread threw an exception."),
+ THREADS_NEVER_CREATED("Threads never created."),
+ TESTING_LOGIC_THREW_EXCEPTION("Testing Logic threw Exception."),
+ THREADS_TIMEDOUT("Threads Timed-out, Interupt likely not called."),
+ INCORRECT_COUNT("The size of mQueue is not consistent with the number of puts() and takes() performed.");
+
+ /**
+ * String value for the enumerated type.
+ */
+ private String mValue = null;
+
+ /**
+ * Initialize the mValue string.
+ */
+ private SynchronizedQueueResult(String value) {
+ mValue = value;
+ }
+
+ /**
+ * Return the mValue string.
+ */
+ public String getString() {
+ return mValue;
+ }
+ }
+
+ /**
+ * @class QueueAdapter
+ *
+ * @brief Applies a variant of the GoF Adapter pattern that
+ * enables us to test several implementations of the
+ * BlockingQueue interface.
+ */
+ public static class QueueAdapter {
+ /**
+ * Stores the queue that we're adapting.
+ */
+ private BlockingQueue mQueue;
+
+ /**
+ * Store the queue that we're adapting.
+ */
+ public QueueAdapter(BlockingQueue queue) {
+ mQueue = queue;
+ }
+
+ /**
+ * Returns the number of elements in this queue.
+ */
+ int size() {
+ return mQueue.size();
+ }
+
+ /**
+ * Insert msg at the tail of the queue.
+ *
+ * @throws TimeoutException and InterruptedException
+ */
+ public void put(E msg) throws InterruptedException, TimeoutException {
+ // Keep track of how many times we're called.
+ boolean timeoutValue = mQueue.offer(msg,
+ TIMEOUT_SECONDS,
+ TimeUnit.SECONDS);
+ if (timeoutValue == false)
+ throw new TimeoutException();
+
+ mProducerCounter++;
+ }
+
+ /**
+ * Remove msg from the head of the queue.
+ *
+ * @throws TimeoutException
+ * , InterruptedException
+ */
+ public E take() throws InterruptedException, TimeoutException {
+ // Keep track of how many times we're called.
+ E rValue = mQueue.poll(TIMEOUT_SECONDS,
+ TimeUnit.SECONDS);
+
+ if (rValue == null)
+ throw new TimeoutException();
+
+ mConsumerCounter++;
+
+ return rValue;
+ }
+ }
+
+ /**
+ * Adapter object used to test different BlockingQueue
+ * implementations.
+ */
+ private static QueueAdapter mQueue = null;
+
+ /**
+ * This runnable loops for mMaxIterations and calls put() on
+ * mQueue to insert the iteration number into the queue.
+ */
+ protected static Runnable mProducerRunnable = new Runnable() {
+ public void run() {
+ for (int i = 0; i < mMaxIterations; i++)
+ try {
+ mQueue.put(i);
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ } catch (InterruptedException e) {
+ if (diagnosticsEnabled)
+ System.out.println("Thread "
+ + Thread.currentThread().getId()
+ + " in test "
+ + mTestName
+ + " properly interrupted by "
+ + e.toString() + " in producerRunnable");
+ // This isn't an error - it just means that
+ // we've been interrupted by the main Thread.
+ return;
+ } catch (TimeoutException e) {
+ if (diagnosticsEnabled)
+ System.out.println("Thread "
+ + Thread.currentThread().getId()
+ + " in test "
+ + mTestName
+ + " Exception "
+ + e.toString()
+ + " occurred in producerRunnable");
+ // Indicate a timeout.
+ mProducerCounter = TIMEOUT_OCCURRED;
+ return;
+ } catch (Exception e) {
+ if (diagnosticsEnabled)
+ System.out.println("Thread "
+ + Thread.currentThread().getId()
+ + " in test "
+ + mTestName
+ + " Exception "
+ + e.toString()
+ + " occurred in producerRunnable");
+ // Indicate a failure.
+ mProducerCounter = FAILURE_OCCURRED;
+ return;
+ }
+ }
+ };
+
+ /**
+ * This runnable loops for mMaxIterations and calls take() on mQueue to
+ * remove the iteration from the queue.
+ */
+ protected static Runnable mConsumerRunnable = new Runnable() {
+ public void run() {
+ for (int i = 0; i < mMaxIterations; i++)
+ try {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+ Integer result = (Integer) mQueue.take();
+
+ if (diagnosticsEnabled)
+ System.out.println("iteration = " + result);
+ } catch (InterruptedException e) {
+ if (diagnosticsEnabled)
+ System.out.println("Thread "
+ + Thread.currentThread().getId()
+ + " in test "
+ + mTestName
+ + " properly interrupted by "
+ + e.toString() + " in consumerRunnable");
+ // This isn't an error - it just means that
+ // we've been interrupted by the main Thread.
+ return;
+ } catch (TimeoutException e) {
+ if (diagnosticsEnabled)
+ System.out.println("Thread "
+ + Thread.currentThread().getId()
+ + " in test "
+ + mTestName
+ + " Exception "
+ + e.toString()
+ + " occurred in consumerRunnable");
+ // Indicate a timeout.
+ mConsumerCounter = TIMEOUT_OCCURRED;
+ return;
+ } catch (Exception e) {
+ if (diagnosticsEnabled)
+ System.out.println("Thread "
+ + Thread.currentThread().getId()
+ + " in test "
+ + mTestName
+ + " Exception "
+ + e.toString()
+ + " occurred in consumerRunnable");
+ // Indicate a failure.
+ mConsumerCounter = FAILURE_OCCURRED;
+ return;
+ }
+ }
+ };
+
+ protected SynchronizedQueueResult checkResults() {
+ int numberOfRemainingItemsInQueue =
+ mProducerCounter - mConsumerCounter;
+
+ // Do some sanity checking to see if the Threads work as
+ // expected.
+ if (mConsumer == null
+ || mProducer == null)
+ return SynchronizedQueueResult.THREADS_NEVER_CREATED;
+ else if (mConsumer.isAlive()
+ || mProducer.isAlive())
+ return SynchronizedQueueResult.JOIN_NEVER_CALLED;
+ else if (mConsumerCounter == 0
+ || mProducerCounter == 0)
+ return SynchronizedQueueResult.THREADS_NEVER_RAN;
+ else if (mConsumerCounter == mMaxIterations
+ || mProducerCounter == mMaxIterations)
+ return SynchronizedQueueResult.THREADS_NEVER_INTERUPTED;
+ else if (mConsumerCounter == FAILURE_OCCURRED
+ || mProducerCounter == FAILURE_OCCURRED)
+ return SynchronizedQueueResult.THREADS_THREW_EXCEPTION;
+ else if (mConsumerCounter == TIMEOUT_OCCURRED
+ || mProducerCounter == TIMEOUT_OCCURRED)
+ return SynchronizedQueueResult.THREADS_TIMEDOUT;
+ else if (mQueue.size() != numberOfRemainingItemsInQueue)
+ return SynchronizedQueueResult.INCORRECT_COUNT;
+ else
+ return SynchronizedQueueResult.RAN_PROPERLY;
+ }
+
+ /**
+ * Number of iterations to test (the actual test shouldn't run
+ * this many iterations since the Threads ought to be interrupted
+ * long before it gets this far).
+ */
+ public static int mMaxIterations = 1000000;
+
+ /**
+ * The Java Threads that are used to produce and consume messages
+ * on the queue.
+ */
+ protected Thread mConsumer = null;
+ protected Thread mProducer = null;
+
+ /**
+ * The name of the test that's being run, e.g.,
+ */
+ protected static String mTestName = null;
+
+ public static boolean diagnosticsEnabled = false;
+
+ protected abstract void createThreads();
+ protected abstract void startThreads();
+ protected abstract void interruptThreads();
+ protected abstract void joinThreads() throws InterruptedException;
+
+ /**
+ * This template method runs the test on the queue parameter.
+ */
+ public SynchronizedQueueResult testQueue(QueueAdapter queue,
+ String testName) {
+ try {
+ mQueue = queue;
+ mTestName = testName;
+ mProducerCounter = 0;
+ mConsumerCounter = 0;
+
+ // Invoke the various hook methods, which are "primitive
+ // operations" in the Template Method pattern.
+ createThreads();
+ startThreads();
+
+ // Give the Threads a chance to run before interrupting
+ // them. (disabling console output makes them run really
+ // fast).
+ if (diagnosticsEnabled)
+ Thread.sleep(1000);
+ else
+ Thread.sleep(100);
+
+ interruptThreads();
+ joinThreads();
+
+ return checkResults();
+ } catch (Exception e) {
+ return SynchronizedQueueResult.TESTING_LOGIC_THREW_EXCEPTION;
+ }
+ }
+}
diff --git a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java
new file mode 100644
index 000000000..6924d4b18
--- /dev/null
+++ b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java
@@ -0,0 +1,42 @@
+package edu.vuum.mooca;
+
+/**
+ * @class SynchronizedQueueImpl
+ *
+ * @brief This is where you put your implementation code to to (1)
+ * create, (2) start, (3) interrupt, and (4) wait for the
+ * completion of multiple Java Threads.
+ *
+ * Make sure to keep all the "TODO" comments in the code below
+ * to make it easy for peer reviewers to find them.
+ */
+public class SynchronizedQueueImpl extends SynchronizedQueue {
+ // TODO - change this to true if you want to see diagnostic
+ // output on the console as the test runs.
+ static {
+ diagnosticsEnabled = false;
+ }
+
+ protected void createThreads() {
+ // TODO - replace the "null" assignments below to create two
+ // Java Threads, one that's passed the mProducerRunnable and
+ // the other that's passed the mConsumerRunnable.
+ mConsumer = null;
+ mProducer = null;
+ }
+
+ protected void startThreads() {
+ // TODO - you fill in here to start the threads. More
+ // interesting results will occur if you start the
+ // consumer first.
+ }
+
+ protected void interruptThreads() {
+ // TODO - you fill in here to interrupt the threads.
+ }
+
+ protected void joinThreads() throws InterruptedException {
+ // TODO - you fill in here to wait for the threads to
+ // exit.
+ }
+}
diff --git a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueTest.java b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueTest.java
new file mode 100644
index 000000000..aa67caa4d
--- /dev/null
+++ b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueTest.java
@@ -0,0 +1,121 @@
+package edu.vuum.mooca;
+import static org.junit.Assert.*;
+
+import java.util.concurrent.ArrayBlockingQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import edu.vuum.mooca.SynchronizedQueue.*;
+
+/**
+ * @class SynchronizedQueueTest
+ *
+ * @brief This class tests queues for proper functionality by
+ * using the testQueue method defined in SynchronizedQueue.java
+ */
+public class SynchronizedQueueTest {
+ /**
+ * Indicates how big the queue should be.
+ */
+ int mQueueSize;
+
+ /**
+ * Run the test for the queue parameter.
+ *
+ * @return result. If SynchronizedQueue test ran properly, returns
+ * null. If not, returns error message.
+ */
+ static SynchronizedQueueResult runQueueTest(String qName,
+ QueueAdapter queue) {
+ if (SynchronizedQueue.diagnosticsEnabled) {
+ System.out.println("Starting "
+ + qName
+ + " test...");
+ if (qName == "BuggyBlockingQueue")
+ System.out.println("An exception may be thrown since "
+ + qName
+ + " is intentially BUGGY.");
+ }
+
+ /**
+ * We have to instantiate this object because Java doesn't
+ * like things being abstract AND static, which makes
+ * implementing the Template Pattern statically more painful
+ * than it should be.
+ */
+ SynchronizedQueueResult result =
+ new SynchronizedQueueImpl().testQueue(queue, qName);
+
+ if (SynchronizedQueue.diagnosticsEnabled) {
+ System.out.println("End " + qName + " test.\n");
+ System.out.println("See JUnit view for results -- \n"
+ + "Green check-marks denote program correctness. \n"
+ + "Blue x-marks indicate a problem with your implementation. \n");
+ }
+
+ if (result != SynchronizedQueueResult.RAN_PROPERLY)
+ return result;
+ else
+ return null;
+ }
+
+ /**
+ * Runs before each test. Sets mQueueSize.
+ * @throws Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Indicate how big the queue should be, which should be
+ // smaller than the number of iterations to induce blocking
+ // behavior.
+ mQueueSize = SynchronizedQueue.mMaxIterations / 10;
+ }
+
+ /**
+ * Tests the ArrayBlockingQueue, which should pass without error.
+ */
+ @Test
+ public void arrayBlockingQueueTest() {
+ // Make the appropriate QueueAdapter for the
+ // ArrayBlockingQueue.
+ QueueAdapter queueAdapter =
+ new QueueAdapter(new ArrayBlockingQueue(mQueueSize));
+
+ // Run a test on the ArrayBlockingQueue.
+ SynchronizedQueueResult errors =
+ runQueueTest("ArrayBlockingQueue", queueAdapter);
+
+ String errorMessage = "";
+
+ if (errors != null)
+ errorMessage = errors.getString();
+
+ assertNull("Error occurred: " +
+ errorMessage,
+ errors);
+ }
+
+ /**
+ * Tests the BuggyBlockingQueue, an intentionally flawed class.
+ * The buggyBlockingQueueTest() will succeed if the testQueue
+ * method fails, i.e., this test succeeds if our queue causes
+ * errors (which is what we expect)!
+ */
+ @Test
+ public void buggyBlockingQueueTest() {
+ // Make the appropriate QueueAdapter for the
+ // BuggyBlockingQueue.
+
+ QueueAdapter queueAdapter =
+ new QueueAdapter(new BuggyBlockingQueue(mQueueSize));
+
+ // Run a test on the BuggyBlockingQueue.
+ SynchronizedQueueResult errors =
+ runQueueTest("BuggyBlockingQueue", queueAdapter);
+
+ assertNotNull("Test should not complete without errors. " +
+ "BuggyBlockingQueue is intended to function incorrectly.",
+ errors);
+ }
+}
From cfdc09de8cb59e1c01660e50c1bed4ef8746c1ae Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 14 May 2014 21:21:13 -0500
Subject: [PATCH 006/202] Changed the project name for v2 of the unit tests.
---
assignments/week-1-assignment-0-v2/.project | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assignments/week-1-assignment-0-v2/.project b/assignments/week-1-assignment-0-v2/.project
index 5b2ee43b7..f4aa3946a 100644
--- a/assignments/week-1-assignment-0-v2/.project
+++ b/assignments/week-1-assignment-0-v2/.project
@@ -1,6 +1,6 @@
- W1-A0-SynchronizedQueueTest
+ W1-A0-SynchronizedQueueTestv2
From da62e22aa9a4f2710edc5cbffc83a8121ac55319 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 09:17:15 -0500
Subject: [PATCH 007/202] Clarified the role of week-1-assignment-0-v2.
---
.../Assignment-Description.txt | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/assignments/week-1-assignment-0-v2/Assignment-Description.txt b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
index 4d4ff565a..0fc1996d7 100644
--- a/assignments/week-1-assignment-0-v2/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
@@ -1,7 +1,12 @@
-Week 1: Programming Assignment 0
-
-Released Monday, May 12, 2014
-Due Monday, May 26th, 2014
+Week 1: Programming Assignment 0 v2
+
+[Note, this is a different skeleton for assignment 0, which fixes some
+problems with the "official" version, provides better diagnostics, and
+also has a cleaner design that uses the Template Method pattern to
+decouple the test infrastructure from the student-supplied
+code. However, it is NOT the offical version that will be peer graded
+and is provided solely as a way students to understand better how
+concurrency and Java Threads work.]
In this (intentionally simple) initial assignment, you will use Java
Threads to test several implementations of the Java BlockingQueue
From 1f712f0b568b50789e33ea18a6ee82011f16bbe2 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 09:22:09 -0500
Subject: [PATCH 008/202] Removed the BuggyBlockingQueue code and tests since
it was confusing.
---
.../Assignment-Description.txt | 10 +-
.../edu/vuum/mooca/BuggyBlockingQueue.java | 125 ------------------
.../edu/vuum/mooca/SynchronizedQueueTest.java | 17 ---
3 files changed, 4 insertions(+), 148 deletions(-)
delete mode 100644 assignments/week-1-assignment-0/src/edu/vuum/mooca/BuggyBlockingQueue.java
diff --git a/assignments/week-1-assignment-0/Assignment-Description.txt b/assignments/week-1-assignment-0/Assignment-Description.txt
index e485c2765..02b4809dc 100644
--- a/assignments/week-1-assignment-0/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0/Assignment-Description.txt
@@ -68,12 +68,10 @@ compile errors should disappear!
To run the JUnit tests in Eclipse, right-click on
SynchronizedQueueTest.java and go to "Run As > JUnit Test". The JUnit
view will pop up in Eclipse and run the tests contained therein. All
-tests should pass. The ArrayBlockingQueue will pass because your
-testQueue method runs successfully. The tests for BuggyBlockingQueue
-(which is an intentionally flawed class), should "pass" if some error
-occurs while running testQueue (these errors are expected). As long
-as these JUnit tests both "pass" successfully your program will be be
-consider "correct" for the purposes of assessing this assignment.
+tests should pass. The ArrayBlockingQueue should pass if your
+testQueue method runs successfully. As long as this JUnit test
+"passes" successfully your program will be be consider "correct" for
+the purposes of assessing this assignment.
If the tests run and "pass," you should see check-marks next to each
of the tests in the JUnit view. As the tests run, you will also find
diff --git a/assignments/week-1-assignment-0/src/edu/vuum/mooca/BuggyBlockingQueue.java b/assignments/week-1-assignment-0/src/edu/vuum/mooca/BuggyBlockingQueue.java
deleted file mode 100644
index be2ea68f2..000000000
--- a/assignments/week-1-assignment-0/src/edu/vuum/mooca/BuggyBlockingQueue.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package edu.vuum.mooca;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @class BuggyBlockingQueue
- *
- * @brief Defines a buggy version of the BlockingQueue interface that
- * doesn't implement any synchronization mechanisms, so of
- * course it will fail horribly, which is the intent!
- */
-public class BuggyBlockingQueue implements BlockingQueue {
- /**
- * ArrayList doesn't provide any synchronization, so it will not
- * work correctly when called from multiple Java Threads.
- */
- private ArrayList mList = null;
-
- /**
- * Constructor just creates an ArrayList of the appropriate size.
- */
- public BuggyBlockingQueue(int initialSize) {
- mList = new ArrayList(initialSize);
- }
-
- /**
- * Insert msg at the tail of the queue, but doesn't block if the
- * queue is full.
- */
- public void put(E msg) throws InterruptedException {
- mList.add(msg);
- }
-
- /**
- * Remove msg from the head of the queue, but doesn't block if the
- * queue is empty.
- */
- public E take() throws InterruptedException {
- return mList.remove(0);
- }
-
- /**
- * All these methods are inherited from the BlockingQueue
- * interface. They are defined as no-ops to ensure the "Buggyness"
- * of this class ;-)
- */
- public int drainTo(Collection super E> c) {
- return 0;
- }
- public int drainTo(Collection super E> c, int maxElements) {
- return 0;
- }
- public boolean contains(Object o) {
- return false;
- }
- public boolean remove(Object o) {
- return false;
- }
- public int remainingCapacity() {
- return 0;
- }
- public E poll() {
- return null;
- }
- public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- return take();
- }
- public E peek() {
- return null;
- }
- public boolean offer(E e) {
- return false;
- }
- public boolean offer(E e, long timeout, TimeUnit unit) {
- try {
- put(e);
- }
- catch (InterruptedException ex) {
- // Just swallow this exception for this simple (buggy) test.
- }
- return true;
- }
- public boolean add(E e) {
- return false;
- }
- public E element() {
- return null;
- }
- public E remove() {
- return null;
- }
- public void clear() {
- }
- public boolean retainAll(Collection> collection) {
- return false;
- }
- public boolean removeAll(Collection> collection) {
- return false;
- }
- public boolean addAll(Collection extends E> collection) {
- return false;
- }
- public boolean containsAll(Collection> collection) {
- return false;
- }
- public Object[] toArray() {
- return null;
- }
- public T[] toArray(T[] array) {
- return null;
- }
- public Iterator iterator() {
- return null;
- }
- public boolean isEmpty() {
- return false;
- }
- public int size() {
- return 0;
- }
-}
diff --git a/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java b/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java
index 2a459546b..427448946 100644
--- a/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java
+++ b/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java
@@ -68,21 +68,4 @@ public void arrayBlockingQueueTest() {
errors,
errors);
}
-
- /**
- * Tests the BuggyBlockingQueue, an intentionally flawed class.
- * The buggyBlockingQueueTest() will succeed if the testQueue
- * method fails, i.e., this test succeeds if our queue causes
- * errors (which is what we expect)!
- */
- @Test
- public void buggyBlockingQueueTest() {
- QueueAdapter queueAdapter =
- new QueueAdapter(new BuggyBlockingQueue(queueSize));
- String errors = runQueueTest("BuggyBlockingQueue", queueAdapter);
- assertNotNull("Test should not complete without errors. " +
- "BuggyBlockingQueue is intended to function incorrectly.",
- errors);
- }
-
}
From 25b7286215faa030d383dc97080fccd2883aee7f Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 09:28:33 -0500
Subject: [PATCH 009/202] Added the grading driver for week-1-assignment-0.
---
.../week-1-assignment-0/.classpath | 7 +
grading-drivers/week-1-assignment-0/.project | 17 ++
.../Assignment-Description.txt | 80 ++++++
.../src/edu/vuum/mooca/SynchronizedQueue.java | 265 ++++++++++++++++++
.../edu/vuum/mooca/SynchronizedQueueTest.java | 71 +++++
5 files changed, 440 insertions(+)
create mode 100644 grading-drivers/week-1-assignment-0/.classpath
create mode 100644 grading-drivers/week-1-assignment-0/.project
create mode 100644 grading-drivers/week-1-assignment-0/Assignment-Description.txt
create mode 100644 grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
create mode 100644 grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java
diff --git a/grading-drivers/week-1-assignment-0/.classpath b/grading-drivers/week-1-assignment-0/.classpath
new file mode 100644
index 000000000..b10b8d9b2
--- /dev/null
+++ b/grading-drivers/week-1-assignment-0/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/grading-drivers/week-1-assignment-0/.project b/grading-drivers/week-1-assignment-0/.project
new file mode 100644
index 000000000..3cc6dcf74
--- /dev/null
+++ b/grading-drivers/week-1-assignment-0/.project
@@ -0,0 +1,17 @@
+
+
+ W1-A0-SynchronizedQueueTest-Grading
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/grading-drivers/week-1-assignment-0/Assignment-Description.txt b/grading-drivers/week-1-assignment-0/Assignment-Description.txt
new file mode 100644
index 000000000..02b4809dc
--- /dev/null
+++ b/grading-drivers/week-1-assignment-0/Assignment-Description.txt
@@ -0,0 +1,80 @@
+Week 1: Programming Assignment 0
+
+Released Monday, May 12, 2014
+Due Monday, May 26th, 2014
+
+In this (intentionally simple) initial assignment, you will use Java
+Threads to test several implementations of the Java BlockingQueue
+interface. The goal is to learn how to (1) create, (2) start, (3)
+interrupt, and (4) wait for the completion of multiple Java Threads.
+The test program also illustrates some problems that can occur if Java
+Threads concurrently access an object that isn't synchronized
+properly.
+
+In the "src/edu/vuum/mocca" folder in this directory you'll find the
+SynchronizedQueue.java class, which contains the skeleton Java code
+that you'll implement by completing the "TODO - You fill in here"
+comments to provide a working solution. DO NOT CHANGE THE OVERALL
+STRUCTURE OF THE SKELETON - just fill in the "TODO - You fill in here"
+portions!!!
+
+In particular, you'll need to do the following:
+
+. Implement the "TODO" portions of the testQueue() method so that two
+ Java Threads are created and started to run the producerRunnable and
+ consumerRunnable objects. Please keep the "TODO" comments in the
+ code so that peer reviewers can find them quickly during the
+ assessment phase.
+
+. After giving the Threads a chance to run for a short while (which is
+ done for you via the Thread.sleep() method) you'll interrupt both of
+ them so they will shutdown.
+
+. After interrupting the Threads you'll wait for both Threads to exit
+ before continuing with the test (which is also done for you).
+
+All the information needed to write this code is described in these
+videos:
+
+ Section 1: Module 2: Part 1: Overview of Java Threads (Part 1)
+ Section 1: Module 2: Part 2: Overview of Java Threads (Part 2)
+ Section 1: Module 2: Part 3: Motivating Java Synchronization and Scheduling Mechanisms
+
+Make sure to watch these videos and read all the supplied Java code
+carefully prior to starting the assignment. These videos are
+available at
+
+https://class.coursera.org/posa-002/lecture
+
+We'll also discuss this assignment specification (and later its
+solution) in the POSA MOOC "Virtual Office Hours", which are described
+in item #38 at the POSA MOOC FAQ available from
+
+http://www.courera.org/course/posa
+
+The SynchronizerQueueTest.java file uses JUnit to run the tests. We
+do this to automate the testing process and leverage the integration
+of JUnit with Eclipse, as described here:
+
+http://www.vogella.com/tutorials/JUnit/article.html#eclipse
+
+When you first open the project in Eclipse, you might see compile
+errors if JUnit is not included in your build path. To fix these
+errors, open SynchronizedQueueTest.java, hover over "org.junit," and
+click "Fix project setup." Make sure "Add JUnit 4 library to the
+build path" is selected and then click "OK." At this point, the
+compile errors should disappear!
+
+To run the JUnit tests in Eclipse, right-click on
+SynchronizedQueueTest.java and go to "Run As > JUnit Test". The JUnit
+view will pop up in Eclipse and run the tests contained therein. All
+tests should pass. The ArrayBlockingQueue should pass if your
+testQueue method runs successfully. As long as this JUnit test
+"passes" successfully your program will be be consider "correct" for
+the purposes of assessing this assignment.
+
+If the tests run and "pass," you should see check-marks next to each
+of the tests in the JUnit view. As the tests run, you will also find
+output being printed to the console. This text is for informational
+purposes only and have no bearing on whether your program is
+"correct."
diff --git a/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java b/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
new file mode 100644
index 000000000..c4ffb3c18
--- /dev/null
+++ b/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
@@ -0,0 +1,265 @@
+package edu.vuum.mooca;
+import java.util.concurrent.*;
+
+/**
+ * @class SynchronizedQueue
+ *
+ * @brief This class tests the use of Java Threads and several
+ * implementations of the Java BlockingQueue interface.
+ */
+public class SynchronizedQueue {
+ /**
+ * Keep track of the number of times the producer test iterates.
+ */
+ static volatile int mProducerCounter = 0;
+
+ /**
+ * Keep track of the number of times the consumer test iterates.
+ */
+ static volatile int mConsumerCounter = 0;
+
+ /**
+ * Maximum timeout.
+ */
+ static final int TIMEOUT_SECONDS = 5;
+
+ /**
+ * Error value for a timeout.
+ */
+ static final int TIMEOUT_OCCURRED = -1;
+
+ /**
+ * Error value for a failure.
+ */
+ static final int FAILURE_OCCURRED = -2;
+
+ /**
+ * @class SynchronizedQueueResult
+ *
+ * @brief Enumerated type for return values of testing logic, has
+ * String for easy output.
+ */
+ public enum SynchronizedQueueResult {
+ RAN_PROPERLY("Threads Ran Properly."),
+ JOIN_NEVER_CALLED("Join() never called."),
+ THREADS_NEVER_RAN("Threads never ran."),
+ THREADS_NEVER_INTERUPTED("Threads never interrupted."),
+ THREADS_THREW_EXCEPTION("Thread threw an exception."),
+ THREADS_NEVER_CREATED("Threads never created."),
+ TESTING_LOGIC_THREW_EXCEPTION("Testing Logic threw Exception."),
+ THREADS_TIMEDOUT("Threads Timed-out, Interupt likely not called.");
+
+ /**
+ * String value for the enumerated type.
+ */
+ private String mValue = null;
+
+ /**
+ * Initialize the mValue string.
+ */
+ private SynchronizedQueueResult(String value) {
+ mValue = value;
+ }
+
+ /**
+ * Return the mValue string.
+ */
+ public String getString() {
+ return mValue;
+ }
+ }
+
+ /**
+ * @class QueueAdapter
+ *
+ * @brief Applies a variant of the GoF Adapter pattern that
+ * enables us to test several implementations of the
+ * BlockingQueue interface.
+ */
+ public static class QueueAdapter {
+ /**
+ * Stores the queue that we're adapting.
+ */
+ private BlockingQueue mQueue;
+
+ /**
+ * Store the queue that we're adapting.
+ */
+ public QueueAdapter(BlockingQueue queue) {
+ mQueue = queue;
+ }
+
+ /**
+ * Insert msg at the tail of the queue.
+ *
+ * @throws TimeoutException and InterruptedException
+ */
+ public void put(E msg) throws InterruptedException, TimeoutException {
+ // Keep track of how many times we're called.
+ mProducerCounter++;
+ boolean timeoutValue = mQueue.offer(msg,
+ TIMEOUT_SECONDS,
+ TimeUnit.SECONDS);
+ if (timeoutValue == false)
+ throw new TimeoutException();
+ }
+
+ /**
+ * Remove msg from the head of the queue.
+ *
+ * @throws TimeoutException
+ * , InterruptedException
+ */
+ public E take() throws InterruptedException, TimeoutException {
+ // Keep track of how many times we're called.
+ mConsumerCounter++;
+ E rValue = mQueue.poll(TIMEOUT_SECONDS,
+ TimeUnit.SECONDS);
+
+ if (rValue == null)
+ throw new TimeoutException();
+
+ return rValue;
+ }
+ }
+
+ /**
+ * Adapter object used to test different BlockingQueue
+ * implementations.
+ */
+ private static QueueAdapter mQueue = null;
+
+ /**
+ * This runnable loops for mMaxIterations and calls put() on
+ * mQueue to insert the iteration number into the queue.
+ */
+ static Runnable producerRunnable = new Runnable() {
+ public void run() {
+ for (int i = 0; i < mMaxIterations; i++)
+ try {
+ mQueue.put(i);
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ } catch (InterruptedException e) {
+ System.out.println("Thread properly interrupted by "
+ + e.toString() + " in producerRunnable");
+ // This isn't an error - it just means that
+ // we've been interrupted by the main Thread.
+ return;
+ } catch (TimeoutException e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in producerRunnable");
+ // Indicate a timeout.
+ mProducerCounter = TIMEOUT_OCCURRED;
+ return;
+ } catch (Exception e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in producerRunnable");
+ // Indicate a failure.
+ mProducerCounter = FAILURE_OCCURRED;
+ return;
+ }
+ }
+ };
+
+ /**
+ * This runnable loops for mMaxIterations and calls take() on mQueue to
+ * remove the iteration from the queue.
+ */
+ static Runnable consumerRunnable = new Runnable() {
+ public void run() {
+ for (int i = 0; i < mMaxIterations; i++)
+ try {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+ Integer result = (Integer) mQueue.take();
+
+ System.out.println("iteration = " + result);
+ } catch (InterruptedException e) {
+ System.out.println("Thread properly interrupted by "
+ + e.toString() + " in consumerRunnable");
+ // This isn't an error - it just means that
+ // we've been interrupted by the main Thread.
+ return;
+ } catch (TimeoutException e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in consumerRunnable");
+ // Indicate a timeout.
+ mConsumerCounter = TIMEOUT_OCCURRED;
+ return;
+ } catch (Exception e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in consumerRunnable");
+ // Indicate a failure.
+ mConsumerCounter = FAILURE_OCCURRED;
+ return;
+ }
+ }
+ };
+
+ /**
+ * Number of iterations to test (the actual test shouldn't run
+ * this many iterations since the Threads ought to be interrupted
+ * long before it gets this far).
+ */
+ public static int mMaxIterations = 1000000;
+
+ /**
+ * Run the test for the queue parameter.
+ */
+ public static SynchronizedQueueResult testQueue(QueueAdapter queue) {
+ try {
+ mQueue = queue;
+
+ // Please make sure to keep all the "TODO" comments in the
+ // code below to make it easy for peer reviewers to find
+ // them.
+
+ // TODO - you fill in here to replace the null
+ // initialization below to create two Java Threads, one
+ // that's passed the producerRunnable and the other that's
+ // passed the consumerRunnable.
+ Thread consumer = null;
+ Thread producer = null;
+
+ // TODO - you fill in here to start the threads. More
+ // interesting results will occur if you start the
+ // consumer first.
+
+ // Give the Threads a chance to run before interrupting
+ // them.
+ Thread.sleep(100);
+
+ // TODO - you fill in here to interrupt the threads.
+
+ // TODO - you fill in here to wait for the threads to
+ // exit.
+
+ // Do some sanity checking to see if the Threads work as
+ // expected.
+ if (consumer == null
+ || producer == null)
+ return SynchronizedQueueResult.THREADS_NEVER_CREATED;
+ else if (consumer.isAlive()
+ || producer.isAlive())
+ return SynchronizedQueueResult.JOIN_NEVER_CALLED;
+ else if (mConsumerCounter == 0
+ || mProducerCounter == 0)
+ return SynchronizedQueueResult.THREADS_NEVER_RAN;
+ else if (mConsumerCounter == mMaxIterations
+ || mProducerCounter == mMaxIterations)
+ return SynchronizedQueueResult.THREADS_NEVER_INTERUPTED;
+ else if (mConsumerCounter == FAILURE_OCCURRED
+ || mProducerCounter == FAILURE_OCCURRED)
+ return SynchronizedQueueResult.THREADS_THREW_EXCEPTION;
+ else if (mConsumerCounter == TIMEOUT_OCCURRED
+ || mProducerCounter == TIMEOUT_OCCURRED)
+ return SynchronizedQueueResult.THREADS_TIMEDOUT;
+ else
+ return SynchronizedQueueResult.RAN_PROPERLY;
+ } catch (Exception e) {
+ return SynchronizedQueueResult.TESTING_LOGIC_THREW_EXCEPTION;
+ }
+ }
+}
diff --git a/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java b/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java
new file mode 100644
index 000000000..427448946
--- /dev/null
+++ b/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueueTest.java
@@ -0,0 +1,71 @@
+package edu.vuum.mooca;
+import static org.junit.Assert.*;
+
+import java.util.concurrent.ArrayBlockingQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import edu.vuum.mooca.SynchronizedQueue.*;
+
+/**
+ * @class SynchronizedQueueTest
+ *
+ * @brief This class tests queues for proper functionality by
+ * using the testQueue method defined in SynchronizedQueue.java
+ */
+public class SynchronizedQueueTest {
+ /**
+ * Indicates how big the queue should be.
+ */
+ int queueSize;
+
+ /**
+ * Run the test for the queue parameter.
+ *
+ * @return result. If SynchronizedQueue test ran properly, returns
+ * null. If not, returns error message.
+ */
+ static String runQueueTest(String qName, QueueAdapter queue) {
+ System.out.println("Starting " + qName + " test...");
+
+ SynchronizedQueueResult result =
+ SynchronizedQueue.testQueue(queue);
+
+ System.out.println("End " + qName + " test.\n");
+ System.out.println("See JUnit view for results -- \n" +
+ "Green check-marks denote program correctness. \n" +
+ "Blue x-marks indicate a problem with your implementation. \n");
+
+ if (result != SynchronizedQueueResult.RAN_PROPERLY)
+ return result.getString();
+
+ return null;
+ }
+
+ /**
+ * Runs before each test. Sets queueSize.
+ * @throws Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Indicate how big the queue should be, which should be
+ // smaller than the number of iterations to induce blocking
+ // behavior.
+ queueSize = SynchronizedQueue.mMaxIterations / 10;
+ }
+
+ /**
+ * Tests the ArrayBlockingQueue, which should pass without error.
+ */
+ @Test
+ public void arrayBlockingQueueTest() {
+ QueueAdapter queueAdapter =
+ new QueueAdapter(new ArrayBlockingQueue(queueSize));
+ String errors = runQueueTest("ArrayBlockingQueue", queueAdapter);
+
+ assertNull("Error occurred: " +
+ errors,
+ errors);
+ }
+}
From 53a8c84d550f44470f3df961832317e567c40cd0 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 09:37:16 -0500
Subject: [PATCH 010/202] Renamed Assignment-Description.txt to
Assessment-Description.txt.
---
.../Assessment-Description.txt | 25 ++++++
.../Assignment-Description.txt | 80 -------------------
2 files changed, 25 insertions(+), 80 deletions(-)
create mode 100644 grading-drivers/week-1-assignment-0/Assessment-Description.txt
delete mode 100644 grading-drivers/week-1-assignment-0/Assignment-Description.txt
diff --git a/grading-drivers/week-1-assignment-0/Assessment-Description.txt b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
new file mode 100644
index 000000000..9dc3d5147
--- /dev/null
+++ b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
@@ -0,0 +1,25 @@
+Week 1: Programming Assignment 0
+
+Released Monday, May 12, 2014
+Due Monday, May 26th, 2014
+
+You will be asked to evaluate five other student's projects as well as
+do a self assessment of your own project. If you do not assess the
+work of others, then you will not pass this assignment.
+
+As you do your evaluation, please keep an open mind and focus on the positive. Our goal is not to find every way to deduct points over small deviations from the requirements or for legitimate differences in implementation styles, etc. Look for ways to give points when it's clear that the submitter has given a good faith effort to do the project, and when it's likely that they've succeeded.
+
+Review the submitter's source code. Since you did your own project, you know where the changes should be and you have a good idea of the kind of method calls and work flows that should be in the submitter's code. Remember that they may have done things differently than you did. That's fine.
+
+Next, get a copy of the grading driver files from
+
+https://github.com/douglascraigschmidt/POSA-14/tree/master/grading-drivers/week-1-assignment-0
+
+and make sure it compiles in your environment. This way, we ensure that all submissions are tested against the "master" regression tests and minimize the amount of code that comes from "the wild". Note that the grading drivers are in a different location than the original skeletons.
+
+Last, copy the submitter's SynchronizedQueue.java file into your IDE (which may have been given a random, odd name by Coursera, so you'll need to rename it) and replace the file of the same name that's already there. I recommend scanning the submitted code to ensure there are no changes other than replacing the "TODO" comments with the appropriate solution (a quick way to do this automatically is to run "diff" on the original SynchronizedQueue.java file and the submitted SynchronizedQueue.java file to make sure all the changes are as expected, in the expected places in the code).
+
+Once you've reviewed the code against the rubric described below please try to compile and run it, walking through the steps called out in the grading video that we'll create in each week's "VIrtual Office Hours" (see item #38 in the POSA MOOC FAQ at http://www.coursera.org/course/posa for info on Virtual Office Hours). I suggest you make a fresh Eclipse workspace when doing this, so that the submitter's code is isolated and easily distinguishable from yours. One way you can do that is to select File > Open Workspace > Browse > New Folder. This will lead to a new, empty Eclipse workspace. Then you can copy that submitter's SynchronizedQueue.java file into this new workspace. Also, make sure to run the submitted code in an Android emulator, rather than on your Android device to further isolate it from causing harm.
+
+And again, remember that most everyone is working very hard and putting in a serious effort. When in doubt, err on the side of giving too many points, rather than giving too few.
+
diff --git a/grading-drivers/week-1-assignment-0/Assignment-Description.txt b/grading-drivers/week-1-assignment-0/Assignment-Description.txt
deleted file mode 100644
index 02b4809dc..000000000
--- a/grading-drivers/week-1-assignment-0/Assignment-Description.txt
+++ /dev/null
@@ -1,80 +0,0 @@
-Week 1: Programming Assignment 0
-
-Released Monday, May 12, 2014
-Due Monday, May 26th, 2014
-
-In this (intentionally simple) initial assignment, you will use Java
-Threads to test several implementations of the Java BlockingQueue
-interface. The goal is to learn how to (1) create, (2) start, (3)
-interrupt, and (4) wait for the completion of multiple Java Threads.
-The test program also illustrates some problems that can occur if Java
-Threads concurrently access an object that isn't synchronized
-properly.
-
-In the "src/edu/vuum/mocca" folder in this directory you'll find the
-SynchronizedQueue.java class, which contains the skeleton Java code
-that you'll implement by completing the "TODO - You fill in here"
-comments to provide a working solution. DO NOT CHANGE THE OVERALL
-STRUCTURE OF THE SKELETON - just fill in the "TODO - You fill in here"
-portions!!!
-
-In particular, you'll need to do the following:
-
-. Implement the "TODO" portions of the testQueue() method so that two
- Java Threads are created and started to run the producerRunnable and
- consumerRunnable objects. Please keep the "TODO" comments in the
- code so that peer reviewers can find them quickly during the
- assessment phase.
-
-. After giving the Threads a chance to run for a short while (which is
- done for you via the Thread.sleep() method) you'll interrupt both of
- them so they will shutdown.
-
-. After interrupting the Threads you'll wait for both Threads to exit
- before continuing with the test (which is also done for you).
-
-All the information needed to write this code is described in these
-videos:
-
- Section 1: Module 2: Part 1: Overview of Java Threads (Part 1)
- Section 1: Module 2: Part 2: Overview of Java Threads (Part 2)
- Section 1: Module 2: Part 3: Motivating Java Synchronization and Scheduling Mechanisms
-
-Make sure to watch these videos and read all the supplied Java code
-carefully prior to starting the assignment. These videos are
-available at
-
-https://class.coursera.org/posa-002/lecture
-
-We'll also discuss this assignment specification (and later its
-solution) in the POSA MOOC "Virtual Office Hours", which are described
-in item #38 at the POSA MOOC FAQ available from
-
-http://www.courera.org/course/posa
-
-The SynchronizerQueueTest.java file uses JUnit to run the tests. We
-do this to automate the testing process and leverage the integration
-of JUnit with Eclipse, as described here:
-
-http://www.vogella.com/tutorials/JUnit/article.html#eclipse
-
-When you first open the project in Eclipse, you might see compile
-errors if JUnit is not included in your build path. To fix these
-errors, open SynchronizedQueueTest.java, hover over "org.junit," and
-click "Fix project setup." Make sure "Add JUnit 4 library to the
-build path" is selected and then click "OK." At this point, the
-compile errors should disappear!
-
-To run the JUnit tests in Eclipse, right-click on
-SynchronizedQueueTest.java and go to "Run As > JUnit Test". The JUnit
-view will pop up in Eclipse and run the tests contained therein. All
-tests should pass. The ArrayBlockingQueue should pass if your
-testQueue method runs successfully. As long as this JUnit test
-"passes" successfully your program will be be consider "correct" for
-the purposes of assessing this assignment.
-
-If the tests run and "pass," you should see check-marks next to each
-of the tests in the JUnit view. As the tests run, you will also find
-output being printed to the console. This text is for informational
-purposes only and have no bearing on whether your program is
-"correct."
From 20a0ddb83a188e99fc36cd8f55096d9288780d10 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 09:45:59 -0500
Subject: [PATCH 011/202] Integrated the grading driver instructions.
---
.../Assignment-Description.txt | 2 +-
.../Assessment-Description.txt | 67 ++++++++++++++-----
2 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/assignments/week-1-assignment-0/Assignment-Description.txt b/assignments/week-1-assignment-0/Assignment-Description.txt
index 02b4809dc..04bee8455 100644
--- a/assignments/week-1-assignment-0/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0/Assignment-Description.txt
@@ -1,4 +1,4 @@
-Week 1: Programming Assignment 0
+Week 1: Programming Assignment 0 Description
Released Monday, May 12, 2014
Due Monday, May 26th, 2014
diff --git a/grading-drivers/week-1-assignment-0/Assessment-Description.txt b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
index 9dc3d5147..34c07f942 100644
--- a/grading-drivers/week-1-assignment-0/Assessment-Description.txt
+++ b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
@@ -1,25 +1,56 @@
-Week 1: Programming Assignment 0
+Week 1: Programming Assignment 0 Peer Assessment Description
-Released Monday, May 12, 2014
-Due Monday, May 26th, 2014
+Due Monday, June 2nd, 2014
You will be asked to evaluate five other student's projects as well as
do a self assessment of your own project. If you do not assess the
work of others, then you will not pass this assignment.
-As you do your evaluation, please keep an open mind and focus on the positive. Our goal is not to find every way to deduct points over small deviations from the requirements or for legitimate differences in implementation styles, etc. Look for ways to give points when it's clear that the submitter has given a good faith effort to do the project, and when it's likely that they've succeeded.
-
-Review the submitter's source code. Since you did your own project, you know where the changes should be and you have a good idea of the kind of method calls and work flows that should be in the submitter's code. Remember that they may have done things differently than you did. That's fine.
-
-Next, get a copy of the grading driver files from
-
-https://github.com/douglascraigschmidt/POSA-14/tree/master/grading-drivers/week-1-assignment-0
-
-and make sure it compiles in your environment. This way, we ensure that all submissions are tested against the "master" regression tests and minimize the amount of code that comes from "the wild". Note that the grading drivers are in a different location than the original skeletons.
-
-Last, copy the submitter's SynchronizedQueue.java file into your IDE (which may have been given a random, odd name by Coursera, so you'll need to rename it) and replace the file of the same name that's already there. I recommend scanning the submitted code to ensure there are no changes other than replacing the "TODO" comments with the appropriate solution (a quick way to do this automatically is to run "diff" on the original SynchronizedQueue.java file and the submitted SynchronizedQueue.java file to make sure all the changes are as expected, in the expected places in the code).
-
-Once you've reviewed the code against the rubric described below please try to compile and run it, walking through the steps called out in the grading video that we'll create in each week's "VIrtual Office Hours" (see item #38 in the POSA MOOC FAQ at http://www.coursera.org/course/posa for info on Virtual Office Hours). I suggest you make a fresh Eclipse workspace when doing this, so that the submitter's code is isolated and easily distinguishable from yours. One way you can do that is to select File > Open Workspace > Browse > New Folder. This will lead to a new, empty Eclipse workspace. Then you can copy that submitter's SynchronizedQueue.java file into this new workspace. Also, make sure to run the submitted code in an Android emulator, rather than on your Android device to further isolate it from causing harm.
-
-And again, remember that most everyone is working very hard and putting in a serious effort. When in doubt, err on the side of giving too many points, rather than giving too few.
+As you do your evaluation, please keep an open mind and focus on the
+positive. Our goal is not to find every way to deduct points over
+small deviations from the requirements or for legitimate differences
+in implementation styles, etc. Look for ways to give points when it's
+clear that the submitter has given a good faith effort to do the
+project, and when it's likely that they've succeeded.
+
+Review the submitter's source code. Since you did your own project,
+you know where the changes should be and you have a good idea of the
+kind of method calls and work flows that should be in the submitter's
+code. Remember that they may have done things differently than you
+did. That's fine.
+
+Use the grading driver files rooted in the "src" directory and make
+sure it compiles in your environment. This way, we ensure that all
+submissions are tested against the "master" regression tests and
+minimize the amount of code that comes from "the wild". Note that
+these grading drivers are in a different location than the original
+skeletons.
+
+Last, copy the submitter's SynchronizedQueue.java file into your IDE
+(which may have been given a random, odd name by Coursera, so you'll
+need to rename it) and replace the file of the same name that's
+already there. I recommend scanning the submitted code to ensure
+there are no changes other than replacing the "TODO" comments with the
+appropriate solution (a quick way to do this automatically is to run
+"diff" on the original SynchronizedQueue.java file and the submitted
+SynchronizedQueue.java file to make sure all the changes are as
+expected, in the expected places in the code).
+
+Once you've reviewed the code against the rubric described below
+please try to compile and run it, walking through the steps called out
+in the grading video that we'll create in each week's "VIrtual Office
+Hours" (see item #38 in the POSA MOOC FAQ at
+http://www.coursera.org/course/posa for info on Virtual Office
+Hours). I suggest you make a fresh Eclipse workspace when doing this,
+so that the submitter's code is isolated and easily distinguishable
+from yours. One way you can do that is to select File > Open Workspace
+> Browse > New Folder. This will lead to a new, empty Eclipse
+workspace. Then you can copy that submitter's SynchronizedQueue.java
+file into this new workspace. Also, make sure to run the submitted
+code in an Android emulator, rather than on your Android device to
+further isolate it from causing harm.
+
+And again, remember that most everyone is working very hard and
+putting in a serious effort. When in doubt, err on the side of giving
+too many points, rather than giving too few.
From c7b5726e0ab57a3b80a132e302faaf15ae557c23 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 10:14:43 -0500
Subject: [PATCH 012/202] Fixed a typo.
---
assignments/week-1-assignment-0-v2/Assignment-Description.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assignments/week-1-assignment-0-v2/Assignment-Description.txt b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
index 0fc1996d7..65648f258 100644
--- a/assignments/week-1-assignment-0-v2/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
@@ -5,7 +5,7 @@ problems with the "official" version, provides better diagnostics, and
also has a cleaner design that uses the Template Method pattern to
decouple the test infrastructure from the student-supplied
code. However, it is NOT the offical version that will be peer graded
-and is provided solely as a way students to understand better how
+and is provided solely as a way for students to understand better how
concurrency and Java Threads work.]
In this (intentionally simple) initial assignment, you will use Java
From 31708332d7c68f8f52316f15a76f9a2eed0fbe4c Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 18:45:12 -0500
Subject: [PATCH 013/202] Enhanced the comments to clearly show how this
relates to the Template Method pattern.
---
.../src/edu/vuum/mooca/SynchronizedQueueImpl.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java
index 6924d4b18..c34c74bb7 100644
--- a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java
+++ b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java
@@ -5,7 +5,10 @@
*
* @brief This is where you put your implementation code to to (1)
* create, (2) start, (3) interrupt, and (4) wait for the
- * completion of multiple Java Threads.
+ * completion of multiple Java Threads. This class plays the
+ * role of the "Concrete Class" in the Template Method pattern
+ * and isolates the code written by students from the
+ * underlying SynchronizedQueue test infrastructure.
*
* Make sure to keep all the "TODO" comments in the code below
* to make it easy for peer reviewers to find them.
From c1c01aab0ee25927a0ad49847659578387d43b65 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 15 May 2014 21:25:17 -0500
Subject: [PATCH 014/202] Updated the JUnit tests for SimpleAtomicLong.
---
assignments/week-2-assignment-1/.classpath | 3 +-
.../Assignment-Description.txt | 61 ++--
.../src/SimpleAtomicLongTest.java | 132 --------
.../{ => edu/vuum/mocca}/BuggyLongTest.java | 8 +-
.../vuum/mocca}/SimpleAtomicLong.java | 36 +-
.../SimpleAtomicLongMultithreadedTest.java | 320 ++++++++++++++++++
.../SimpleAtomicLongSingleThreadedTest.java | 235 +++++++++++++
.../edu/vuum/mocca/SimpleAtomicLongTests.java | 18 +
8 files changed, 630 insertions(+), 183 deletions(-)
delete mode 100644 assignments/week-2-assignment-1/src/SimpleAtomicLongTest.java
rename assignments/week-2-assignment-1/src/{ => edu/vuum/mocca}/BuggyLongTest.java (92%)
rename assignments/week-2-assignment-1/src/{ => edu/vuum/mocca}/SimpleAtomicLong.java (75%)
create mode 100644 assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java
create mode 100644 assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java
create mode 100644 assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java
diff --git a/assignments/week-2-assignment-1/.classpath b/assignments/week-2-assignment-1/.classpath
index 18d70f02c..3e0fb272a 100644
--- a/assignments/week-2-assignment-1/.classpath
+++ b/assignments/week-2-assignment-1/.classpath
@@ -1,6 +1,7 @@
-
+
+
diff --git a/assignments/week-2-assignment-1/Assignment-Description.txt b/assignments/week-2-assignment-1/Assignment-Description.txt
index 01006d970..89bd37f56 100644
--- a/assignments/week-2-assignment-1/Assignment-Description.txt
+++ b/assignments/week-2-assignment-1/Assignment-Description.txt
@@ -1,14 +1,13 @@
-Programming Assignment 0
+Week 2: Programming Assignment 1
-In this first (intentionally simple) assignment, you will use a Java
-ReentrantReadWriteLock to implement a subset of the
-java.util.concurrent.atomic.AtomicLong class, which we call
-SimpleAtomicLong. The goal is to understand how to use
+Released Monday, May 19th, 2014
+Due Monday, June 2nd, 2014
+
+In this seonc assignment, you will implement a subset of the
+java.util.concurrent.atomic.SimpleAtomicLong class using a Java
+ReentrantReadWriteLock. The goal is to understand how to use
ReentrantReadWriteLock to serialize access to a variable that's shared
-by multiple threads. The SimpleAtomicLongTest.java program creates
-two Threads that increment and decrement the AtomicLong 10,000,000
-times each. If the SimpleAtomicLong implementation is properly
-serialized it's final value should be 0.
+by multiple threads.
The BuggyLongTest.java program shows what happens if concurrent access
to a long isn't properly serialized. This test program works best on
@@ -17,11 +16,12 @@ failure due to race conditions stemming from parallel execution. If
this test "succeeds" then your target platform is not sufficiently
parallel to demonstrate the bug.
-In this directory you'll find the SimpleAtomicLong.java class, which
-contains the skeleton Java code that you'll implement by completing
-the "TODO - You fill in here" comments to provide a working solution.
-DO NOT CHANGE THE OVERALL STRUCTURE OF THE SKELETON - just fill in the
-"TODO - You fill in here" portions!!!
+In the src/edu/vuum/mocca directory you'll find the
+SimpleAtomicLong.java class, which contains the skeleton Java code
+that you'll implement by completing the "TODO - You fill in here"
+comments to provide a working solution. DO NOT CHANGE THE OVERALL
+STRUCTURE OF THE SKELETON - just fill in the "TODO - You fill in here"
+portions!!!
In particular, you'll need to do the following:
@@ -34,17 +34,17 @@ In particular, you'll need to do the following:
http://tutorials.jenkov.com/java-util-concurrent/readwritelock.html
-. Make sure to use a readLock() for AtomicLong.get() and writeLock()
- for all the other SimpleAtomicLong methods.
+. Make sure to use a readLock() for SimpleAtomicLong.get() and
+ writeLock() for all the other SimpleAtomicLong methods.
-. The SimpleAtomicLongTest.java program uses various features of Java
- Threads and Runnables, which are described in these videos:
+Note that the SimpleAtomicLongTest.java program uses Java Threads and
+Runnables, which are described in these videos:
Section 1: Module 2: Part 1: Overview of Java Threads (Part 1)
Section 1: Module 2: Part 2: Overview of Java Threads (Part 2)
- Likewise, it also uses the Java CountDownLatch and CyclicBarrier
- classes, which are described in this video:
+Likewise, it also uses the Java CountDownLatch and CyclicBarrier
+classes, which are described in this video:
Section 1: Module 2: Part 9: Java CountDownLatch
@@ -58,23 +58,16 @@ available at
https://class.coursera.org/posa-002/lecture
-We'll also discuss this assignment specification (and later its
-solution) in the POSA MOOC "Virtual Office Hours", which are described
-in item #38 at the POSA MOOC FAQ available from
-
-http://www.courera.org/course/posa
+To test this code in Eclipse, right-click on
+SimpleAtomicLongTests.java and Run As > JUnit Test. The JUnit view
+will pop up in Eclipse and run the the tests, which are divided into
+two subsets: multi-threaded and single-threaded tests. The
+single-threaded tests verify functionality of all methods within a
+single thread, while the multi-threaded tests do the same in a
+multi-threaded environment. All tests should run successfully.
-To compile this code you can either use the provided Eclipse project
-or simply type
-% javac SimpleAtomicLongTest.java SimpleAtomicLong.java
-on the command-line and then run the resulting class file by typing
-% java SimpleAtomicLongTest
-The output for a correct solution should look exactly like this:
-Starting SimpleAtomicLongTest
-test worked
-Finishing SimpleAtomicLongTest
diff --git a/assignments/week-2-assignment-1/src/SimpleAtomicLongTest.java b/assignments/week-2-assignment-1/src/SimpleAtomicLongTest.java
deleted file mode 100644
index a86ed7d4d..000000000
--- a/assignments/week-2-assignment-1/src/SimpleAtomicLongTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-// Import the necessary Java synchronization and scheduling classes.
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.CyclicBarrier;
-
-/**
- * @class SimpleAtomicLongTest
- *
- * @brief This class tests our implementation of SimpleAtomicLong to ensure
- * it works properly.
- */
-class SimpleAtomicLongTest
-{
- /**
- * Number of iterations to run the test.
- */
- final static long mMaxIterations = 10000000;
-
- /**
- * Barrier synchronizer that controls when the two threads start
- * running the test.
- */
- final static CyclicBarrier mStartBarrier = new CyclicBarrier(2);
-
- /**
- * Barrier synchronizer that controls when the main thread can
- * return.
- */
- final static CountDownLatch mStopLatch = new CountDownLatch(2);
-
- /**
- * An instance of our implementation of SimpleAtomicLong.
- */
- final static SimpleAtomicLong mCounter = new SimpleAtomicLong(0);
-
- /**
- * @brief This class runs the test by invoking a command each time
- * through the loop.
- */
- static class RunTest implements Runnable
- {
- /**
- * A Command that determines what operation is done within the
- * loop.
- */
- private Runnable mCommand;
-
- /**
- * Store the command in a data member field.
- */
- RunTest(Runnable command) {
- mCommand = command;
- }
-
- /**
- * Run the command within a loop.
- */
- public void run() {
- try
- {
- /**
- * Wait for both Threads to start running before
- * beginning the loop.
- */
- mStartBarrier.await();
-
- for (int i = 0; i < mMaxIterations; ++i)
- mCommand.run();
-
- /**
- * Inform the main thread that we're done.
- */
- mStopLatch.countDown();
- }
- catch (Exception e) {
- System.out.println("problem here");
- }
- }
- }
-
- /**
- * Main entry point method that runs the test.
- */
- public static void main(String[] args) {
- try {
- System.out.println("Starting SimpleAtomicLongTest");
-
- /**
- * A Runnable command that decrements the mCounter.
- */
- final Runnable decrementCommand =
- new Runnable() { public void run() { mCounter.getAndDecrement(); } };
-
- /**
- * A Runnable command that decrements the mCounter.
- */
- final Runnable incrementCommand =
- new Runnable() { public void run() { mCounter.getAndIncrement(); } };
-
- /**
- * Start a Thread whose Runnable command decrements the
- * SimpleAtomicLong mMaxIterations number of times.
- */
- new Thread(new RunTest(decrementCommand)).start();
-
- /**
- * Start a Thread whose Runnable command increments the
- * SimpleAtomicLong mMaxIterations number of times.
- */
- new Thread(new RunTest(incrementCommand)).start();
-
- /**
- * Barrier synchronizer that waits for both worker threads
- * to exit before continuing.
- */
- mStopLatch.await();
-
- long result = mCounter.get();
- /**
- * Check to ensure the test worked, i.e., mCounter's value
- * should be 0.
- */
- if (result == 0)
- System.out.println("test worked");
- else
- System.out.println("test failed: mCounter = " + result);
-
- System.out.println("Finishing SimpleAtomicLongTest");
- }
- catch (Exception e) { }
- }
-}
diff --git a/assignments/week-2-assignment-1/src/BuggyLongTest.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/BuggyLongTest.java
similarity index 92%
rename from assignments/week-2-assignment-1/src/BuggyLongTest.java
rename to assignments/week-2-assignment-1/src/edu/vuum/mocca/BuggyLongTest.java
index 74c467b24..fc854689b 100644
--- a/assignments/week-2-assignment-1/src/BuggyLongTest.java
+++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/BuggyLongTest.java
@@ -1,4 +1,4 @@
-// Import the necessary Java synchronization and scheduling classes.
+package edu.vuum.mocca;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
@@ -14,7 +14,7 @@ class BuggyLongTest
/**
* Number of iterations to run the test.
*/
- static final long mMaxIterations = 10000000;
+ static final long mMaxIterations = 100000000;
/**
* Barrier synchronizer that controls when the two threads start
@@ -41,7 +41,7 @@ public static void main(String[] args) {
System.out.println("Starting BuggyLongTest");
/**
- * Start a Thread whose Runnable decrements the AtomicLong
+ * Start a Thread whose Runnable decrements the SimpleAtomicLong
* mMaxIterations number of times.
*/
new Thread(new Runnable()
@@ -70,7 +70,7 @@ public static void main(String[] args) {
}).start();
/**
- * Start a Thread whose Runnable increments the AtomicLong
+ * Start a Thread whose Runnable increments the SimpleAtomicLong
* mMaxIterations number of times.
*/
new Thread(new Runnable()
diff --git a/assignments/week-2-assignment-1/src/SimpleAtomicLong.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java
similarity index 75%
rename from assignments/week-2-assignment-1/src/SimpleAtomicLong.java
rename to assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java
index fc781e4ee..b8851333a 100644
--- a/assignments/week-2-assignment-1/src/SimpleAtomicLong.java
+++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java
@@ -1,4 +1,4 @@
-// Import the necessary Java synchronization and scheduling classes.
+package edu.vuum.mocca;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.Lock;
@@ -20,7 +20,9 @@ class SimpleAtomicLong
/**
* The ReentrantReadWriteLock used to serialize access to mValue.
*/
- // TODO - replace the null with the appropriate initialization:
+
+ // TODO -- you fill in here by replacing the null with an
+ // initialization of ReentrantReadWriteLock.
private ReentrantReadWriteLock mRWLock = null;
/**
@@ -28,7 +30,7 @@ class SimpleAtomicLong
*/
public SimpleAtomicLong(long initialValue)
{
- // TODO - you fill in here
+ // TODO -- you fill in here
}
/**
@@ -39,7 +41,9 @@ public SimpleAtomicLong(long initialValue)
public long get()
{
long value;
- // TODO - you fill in here, using a readLock()
+
+ // TODO -- you fill in here
+
return value;
}
@@ -50,8 +54,10 @@ public long get()
*/
public long decrementAndGet()
{
- long value;
- // TODO - you fill in here, using a writeLock()
+ long value = 0;
+
+ // TODO -- you fill in here
+
return value;
}
@@ -62,8 +68,10 @@ public long decrementAndGet()
*/
public long getAndIncrement()
{
- long value;
- // TODO - you fill in here, using a writeLock()
+ long value = 0;
+
+ // TODO -- you fill in here
+
return value;
}
@@ -74,8 +82,10 @@ public long getAndIncrement()
*/
public long getAndDecrement()
{
- long value;
- // TODO - you fill in here, using a writeLock()
+ long value = 0;
+
+ // TODO -- you fill in here
+
return value;
}
@@ -86,8 +96,10 @@ public long getAndDecrement()
*/
public long incrementAndGet()
{
- long value;
- // TODO - you fill in here, using a writeLock()
+ long value = 0;
+
+ // TODO -- you fill in here
+
return value;
}
}
diff --git a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java
new file mode 100644
index 000000000..401bcd63f
--- /dev/null
+++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java
@@ -0,0 +1,320 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.*;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @class SimpleAtomicLongMultithreadedTest
+ *
+ * @brief Test the logic and multithreaded implementation of the
+ * SimpleAtomicLong class by having concurrent threads call the
+ * SimpleAtomicLong instance for various methods.
+ */
+public class SimpleAtomicLongMultithreadedTest {
+
+ /**
+ * Our start points.
+ */
+ final static long INITIAL_VALUE = 0;
+
+ /**
+ * Number of iterations to run the commands.
+ */
+ final static long mMaxIterations = 1000000;
+
+ /**
+ * Barrier synchronizer that controls when the threads start
+ * running the test.
+ */
+ static CyclicBarrier mStartBarrier;
+
+ /**
+ * Barrier synchronizer that controls when the main thread can
+ * return.
+ */
+ static CountDownLatch mStopLatch;
+
+ /**
+ * An instance of our implementation of SimpleAtomicLong.
+ */
+ static SimpleAtomicLong mCounter;
+
+ /**
+ * Runnable commands that use the mCounter methods
+ * get()
+ * incrementAndGet()
+ * getAndIncrement()
+ * decrementAndGet()
+ * getAndDecrement()
+ */
+ static Runnable getCommand;
+ static Runnable incrementGetCommand;
+ static Runnable getIncrementCommand;
+ static Runnable decrementGetCommand;
+ static Runnable getDecrementCommand;
+
+ /**
+ * The value of mCounter prior to any changes made by testing.
+ */
+ long preTestValue;
+
+ /**
+ * The number of duplicate threads to run when testing each
+ * individual command.
+ */
+ final int numThreads = 5;
+
+ /**
+ * @class RunTest
+ *
+ * @brief This class runs the test by invoking a command each time
+ * through the loop.
+ */
+ static class RunTest implements Runnable
+ {
+ /**
+ * A Command that determines what operation is done within the
+ * loop.
+ */
+ private Runnable mCommand;
+
+ /**
+ * An integer which keeps track of the number of times the
+ * command has been called. Initially equal to zero.
+ */
+ private long iterations = 0;
+
+ /**
+ * Store the command in a data member field.
+ */
+ RunTest(Runnable command) {
+ mCommand = command;
+ }
+
+ /**
+ * Run the command within a loop.
+ */
+ public void run() {
+ try
+ {
+ /**
+ * Wait for all Threads to start running before
+ * beginning the loop.
+ */
+ mStartBarrier.await();
+
+ for (; iterations < mMaxIterations; ++iterations) {
+ mCommand.run();
+ }
+ /**
+ * Inform the main thread that we're done.
+ */
+ mStopLatch.countDown();
+ } catch (Exception e) {
+ fail("Runnable failed.");
+ }
+ }
+
+ /**
+ * Returns the number of times this command has been performed.
+ * @return iterations
+ */
+ public long getIterations() {
+ return iterations;
+ }
+ }
+
+ /**
+ * Runs prior to all tests. Creates a static instance of
+ * SimpleAtomicLong and all runnable commands.
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ /**
+ * Instance of SimpleAtomicLong class
+ */
+ mCounter = new SimpleAtomicLong(INITIAL_VALUE);
+
+ /**
+ * Runnable commands that execute get(), incrementAndGet(),
+ * getAndIncrement(), decrementAndGet(), getAndDecrement(),
+ * respectively, on the SimpleAtomicLong instance
+ */
+ getCommand = new Runnable() { public void run() { mCounter.get(); } };
+ incrementGetCommand = new Runnable() { public void run() { mCounter.incrementAndGet(); } };
+ getIncrementCommand = new Runnable() { public void run() { mCounter.getAndIncrement(); } };
+ decrementGetCommand = new Runnable() { public void run() { mCounter.decrementAndGet(); } };
+ getDecrementCommand = new Runnable() { public void run() { mCounter.getAndDecrement(); } };
+ }
+
+ /**
+ * Runs prior to each test. Stores the pre-test value of the mCounter.
+ */
+ @Before
+ public void setUp() throws Exception {
+ preTestValue = mCounter.get();
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code get()}.
+ */
+ @Test
+ public void multiGetTest() {
+ /**
+ * run multiple threads calling mCounter.get().
+ */
+ runThreads(getCommand);
+ /**
+ * The expected post-test value is no change in the pre-test
+ * value.
+ */
+ assertEquals(preTestValue,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code
+ * incrementAndGet()}.
+ */
+ @Test
+ public void multiIncrementAndGetTest() {
+ runThreads(incrementGetCommand);
+ /**
+ * expected value after threads are run should be the number
+ * of maximum iterations times the number of threads plus the
+ * pre-test value
+ */
+ assertEquals(preTestValue
+ + mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code getAndIncrement()}.
+ */
+ @Test
+ public void multiGetAndIncrementTest() {
+ runThreads(getIncrementCommand);
+ assertEquals(preTestValue
+ + mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code
+ * decrementAndGet()}.
+ */
+ @Test
+ public void multiDecrementAndGetTest() {
+ runThreads(decrementGetCommand);
+ /**
+ * Expected value of mCounter after threads have completed
+ * running is the pre-test value minus the maximum iterations
+ * times the number of threads that were run.
+ */
+ assertEquals(preTestValue -
+ mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code getAndIncrement()}.
+ */
+ @Test
+ public void multiGetAndDecrementTest() {
+ runThreads(getDecrementCommand);
+ /**
+ * expected value of mCounter after threads have completed running
+ * is the pre-test value minus the maximum iterations times the number
+ * of threads that were run
+ */
+ assertEquals(preTestValue -
+ mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests concurrent running of threads performing a variety of
+ * operations on mCounter (e.g. {@code get()}, {@code
+ * getAndIncrement()}, {@code getAndDecrement()},{@code
+ * incrementAndGet()}, and {@code decrementAndGet()}).
+ */
+ @Test
+ public void multiThreadedTest() {
+ /**
+ * Run five threads concurrently, each performing a different
+ * method on the SimpleAtomicLong instance
+ */
+ runThreads(null);
+ /**
+ * Check to ensure the pre-test and post-test values are
+ * equal. This indicates the test was successful.
+ */
+ assertEquals(preTestValue,
+ mCounter.get());
+ }
+
+ /**
+ * Runs numThreads concurrent threads executing the same command.
+ * Has a CyclicBarrier and CountDownLatch to facilitate
+ * concurrency.
+ * @param command
+ */
+ private void runThreads(Runnable command) {
+ mStartBarrier = new CyclicBarrier(numThreads);
+ mStopLatch = new CountDownLatch(numThreads);
+ try {
+ /**
+ * Create an array of RunTests whose Runnable commands
+ * execute on the SimpleAtomicLong mMaxIterations number
+ * of times. If given a command, each thread should run
+ * duplicates. If command is null, then run one of each
+ * type of command.
+ */
+ RunTest[] runTests;
+ if(command == null) {
+ runTests = new RunTest[5];
+ runTests[0] = new RunTest(getCommand);
+ runTests[1] = new RunTest(incrementGetCommand);
+ runTests[2] = new RunTest(decrementGetCommand);
+ runTests[3] = new RunTest(getDecrementCommand);
+ runTests[4] = new RunTest(getIncrementCommand);
+ }
+ else {
+ runTests = new RunTest[numThreads];
+ for(int i = 0; i < runTests.length; i++)
+ runTests[i] = new RunTest(command);
+ }
+
+ /**
+ * Start threads whose Runnable commands execute on the
+ * SimpleAtomicLong mMaxIterations number of times.
+ */
+ for(int i = 0; i < runTests.length; i++)
+ new Thread(runTests[i]).start();
+
+ /**
+ * Barrier synchronizer that waits for all worker threads
+ * to exit before continuing.
+ */
+ mStopLatch.await();
+
+ /**
+ * Check to ensure threads have run.
+ */
+ for(int i = 0; i < runTests.length; i++)
+ assertEquals("Threads have not executed.",
+ mMaxIterations,
+ runTests[i].getIterations());
+ } catch (Exception e) {
+ fail("Exception thrown.");
+ }
+ }
+
+}
diff --git a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java
new file mode 100644
index 000000000..ef28e3e0a
--- /dev/null
+++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java
@@ -0,0 +1,235 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @brief SimpleAtomicLongSingleThreadedTest
+ *
+ * @class Evalutes the logic of the SimpleAtomicLong class by testing
+ * every method with each of the values in mTestValues.
+ */
+public class SimpleAtomicLongSingleThreadedTest {
+ /*
+ * Test possible edge cases at 0, and a large negative and
+ * positive.
+ */
+ final static long[] mTestValues = { -100, -1, 0, 1, 100 };
+
+ /**
+ * Test Constructor.
+ */
+ @Test
+ public void constructorTest() {
+ for (long testValue : mTestValues) {
+ SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ Assert.assertNotNull(counter);
+ assertEquals(testValue, counter.get());
+ }
+ }
+
+ /**
+ * Test get()
+ */
+ @Test
+ public void getTest() {
+ for (long testValue : mTestValues) {
+ SimpleAtomicLong counter = new SimpleAtomicLong(testValue);
+ assertEquals(testValue,
+ counter.get());
+ }
+ }
+
+ /**
+ * test decrementAndGet()
+ */
+ @Test
+ public void decrementAndGetTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ decrementAndGetTestLogic(counter,
+ testValue,
+ testValue - 1,
+ testValue - 1);
+ }
+ }
+
+ /**
+ * test getAndDecrement()
+ */
+ @Test
+ public void getAndDecrementTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ getAndDecrementTestLogic(counter,
+ testValue,
+ testValue,
+ testValue - 1);
+ }
+ }
+
+ /**
+ * test incrementAndGet()
+ */
+ @Test
+ public void incrementAndGetTestTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ incrementAndGetTestLogic(counter,
+ testValue,
+ testValue + 1,
+ testValue + 1);
+ }
+ }
+
+ /**
+ * test getAndIncrement()
+ */
+ @Test
+ public void getAndIncrementTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ getAndIncrementTestLogic(counter,
+ testValue,
+ testValue,
+ testValue + 1);
+ }
+ }
+
+ /**
+ * Compares the values expected with the values produced by each test logic.
+ *
+ * @param pre
+ * The 'pre' number produced by the test
+ * @param preValue
+ * The 'pre' number expected
+ * @param result
+ * The 'result' number produced by the test
+ * @param resultValue
+ * The 'result' expected
+ * @param post
+ * The 'post' number produced by the test
+ * @param postValue
+ * The 'post' expected
+ */
+ private void compareResults(long pre, long preValue, long result,
+ long resultValue, long post, long postValue) {
+ assertEquals(pre, preValue);
+ assertEquals(result, resultValue);
+ assertEquals(post, postValue);
+ }
+
+ /**
+ * The Logic of testing decrementAndGet
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void decrementAndGetTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.decrementAndGet();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre - 1, result);
+ assertEquals(result, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post,
+ postValue);
+ }
+
+ /**
+ * The Logic of testing getAndDecrement
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void getAndDecrementTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.getAndDecrement();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre, result);
+ assertEquals(pre - 1, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post,
+ postValue);
+ }
+
+ /**
+ * The Logic of testing incrementAndGet
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void incrementAndGetTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.incrementAndGet();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre + 1, result);
+ assertEquals(result, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post,
+ postValue);
+ }
+
+ /**
+ * The Logic of testing getAndIncrement
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void getAndIncrementTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.getAndIncrement();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre, result);
+ assertEquals(pre + 1, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post, postValue);
+ }
+}
diff --git a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java
new file mode 100644
index 000000000..990496762
--- /dev/null
+++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java
@@ -0,0 +1,18 @@
+package edu.vuum.mocca;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+
+@RunWith(Suite.class)
+@SuiteClasses({ SimpleAtomicLongMultithreadedTest.class,
+ SimpleAtomicLongSingleThreadedTest.class })
+/**
+ * @class SimpleAtomicLongTest
+ *
+ * @brief Entry point for running all the regression tests for the
+ * SimpleAtomicLong implementation.
+ */
+public class SimpleAtomicLongTests {
+}
From 7cd4a36c5dcc9d37f612387b7e4789bb661ee753 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Fri, 16 May 2014 23:04:34 -0500
Subject: [PATCH 015/202] Clarified several things.
---
.../Assessment-Description.txt | 14 +-
.../src/edu/vuum/mooca/SynchronizedQueue.java | 265 ------------------
2 files changed, 7 insertions(+), 272 deletions(-)
delete mode 100644 grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
diff --git a/grading-drivers/week-1-assignment-0/Assessment-Description.txt b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
index 34c07f942..cbc5da9ba 100644
--- a/grading-drivers/week-1-assignment-0/Assessment-Description.txt
+++ b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
@@ -28,13 +28,13 @@ skeletons.
Last, copy the submitter's SynchronizedQueue.java file into your IDE
(which may have been given a random, odd name by Coursera, so you'll
-need to rename it) and replace the file of the same name that's
-already there. I recommend scanning the submitted code to ensure
-there are no changes other than replacing the "TODO" comments with the
-appropriate solution (a quick way to do this automatically is to run
-"diff" on the original SynchronizedQueue.java file and the submitted
-SynchronizedQueue.java file to make sure all the changes are as
-expected, in the expected places in the code).
+need to rename it) and store it in the src/edu/vuum/mocca directory.
+I recommend scanning the submitted code to ensure there are no changes
+other than replacing the "TODO" comments with the appropriate solution
+(a quick way to do this automatically is to run "diff" on the original
+SynchronizedQueue.java file and the submitted SynchronizedQueue.java
+file to make sure all the changes are as expected, in the expected
+places in the code).
Once you've reviewed the code against the rubric described below
please try to compile and run it, walking through the steps called out
diff --git a/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java b/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
deleted file mode 100644
index c4ffb3c18..000000000
--- a/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package edu.vuum.mooca;
-import java.util.concurrent.*;
-
-/**
- * @class SynchronizedQueue
- *
- * @brief This class tests the use of Java Threads and several
- * implementations of the Java BlockingQueue interface.
- */
-public class SynchronizedQueue {
- /**
- * Keep track of the number of times the producer test iterates.
- */
- static volatile int mProducerCounter = 0;
-
- /**
- * Keep track of the number of times the consumer test iterates.
- */
- static volatile int mConsumerCounter = 0;
-
- /**
- * Maximum timeout.
- */
- static final int TIMEOUT_SECONDS = 5;
-
- /**
- * Error value for a timeout.
- */
- static final int TIMEOUT_OCCURRED = -1;
-
- /**
- * Error value for a failure.
- */
- static final int FAILURE_OCCURRED = -2;
-
- /**
- * @class SynchronizedQueueResult
- *
- * @brief Enumerated type for return values of testing logic, has
- * String for easy output.
- */
- public enum SynchronizedQueueResult {
- RAN_PROPERLY("Threads Ran Properly."),
- JOIN_NEVER_CALLED("Join() never called."),
- THREADS_NEVER_RAN("Threads never ran."),
- THREADS_NEVER_INTERUPTED("Threads never interrupted."),
- THREADS_THREW_EXCEPTION("Thread threw an exception."),
- THREADS_NEVER_CREATED("Threads never created."),
- TESTING_LOGIC_THREW_EXCEPTION("Testing Logic threw Exception."),
- THREADS_TIMEDOUT("Threads Timed-out, Interupt likely not called.");
-
- /**
- * String value for the enumerated type.
- */
- private String mValue = null;
-
- /**
- * Initialize the mValue string.
- */
- private SynchronizedQueueResult(String value) {
- mValue = value;
- }
-
- /**
- * Return the mValue string.
- */
- public String getString() {
- return mValue;
- }
- }
-
- /**
- * @class QueueAdapter
- *
- * @brief Applies a variant of the GoF Adapter pattern that
- * enables us to test several implementations of the
- * BlockingQueue interface.
- */
- public static class QueueAdapter {
- /**
- * Stores the queue that we're adapting.
- */
- private BlockingQueue mQueue;
-
- /**
- * Store the queue that we're adapting.
- */
- public QueueAdapter(BlockingQueue queue) {
- mQueue = queue;
- }
-
- /**
- * Insert msg at the tail of the queue.
- *
- * @throws TimeoutException and InterruptedException
- */
- public void put(E msg) throws InterruptedException, TimeoutException {
- // Keep track of how many times we're called.
- mProducerCounter++;
- boolean timeoutValue = mQueue.offer(msg,
- TIMEOUT_SECONDS,
- TimeUnit.SECONDS);
- if (timeoutValue == false)
- throw new TimeoutException();
- }
-
- /**
- * Remove msg from the head of the queue.
- *
- * @throws TimeoutException
- * , InterruptedException
- */
- public E take() throws InterruptedException, TimeoutException {
- // Keep track of how many times we're called.
- mConsumerCounter++;
- E rValue = mQueue.poll(TIMEOUT_SECONDS,
- TimeUnit.SECONDS);
-
- if (rValue == null)
- throw new TimeoutException();
-
- return rValue;
- }
- }
-
- /**
- * Adapter object used to test different BlockingQueue
- * implementations.
- */
- private static QueueAdapter mQueue = null;
-
- /**
- * This runnable loops for mMaxIterations and calls put() on
- * mQueue to insert the iteration number into the queue.
- */
- static Runnable producerRunnable = new Runnable() {
- public void run() {
- for (int i = 0; i < mMaxIterations; i++)
- try {
- mQueue.put(i);
- if (Thread.interrupted())
- throw new InterruptedException();
- } catch (InterruptedException e) {
- System.out.println("Thread properly interrupted by "
- + e.toString() + " in producerRunnable");
- // This isn't an error - it just means that
- // we've been interrupted by the main Thread.
- return;
- } catch (TimeoutException e) {
- System.out.println("Exception " + e.toString()
- + " occurred in producerRunnable");
- // Indicate a timeout.
- mProducerCounter = TIMEOUT_OCCURRED;
- return;
- } catch (Exception e) {
- System.out.println("Exception " + e.toString()
- + " occurred in producerRunnable");
- // Indicate a failure.
- mProducerCounter = FAILURE_OCCURRED;
- return;
- }
- }
- };
-
- /**
- * This runnable loops for mMaxIterations and calls take() on mQueue to
- * remove the iteration from the queue.
- */
- static Runnable consumerRunnable = new Runnable() {
- public void run() {
- for (int i = 0; i < mMaxIterations; i++)
- try {
- if (Thread.interrupted()) {
- throw new InterruptedException();
- }
- Integer result = (Integer) mQueue.take();
-
- System.out.println("iteration = " + result);
- } catch (InterruptedException e) {
- System.out.println("Thread properly interrupted by "
- + e.toString() + " in consumerRunnable");
- // This isn't an error - it just means that
- // we've been interrupted by the main Thread.
- return;
- } catch (TimeoutException e) {
- System.out.println("Exception " + e.toString()
- + " occurred in consumerRunnable");
- // Indicate a timeout.
- mConsumerCounter = TIMEOUT_OCCURRED;
- return;
- } catch (Exception e) {
- System.out.println("Exception " + e.toString()
- + " occurred in consumerRunnable");
- // Indicate a failure.
- mConsumerCounter = FAILURE_OCCURRED;
- return;
- }
- }
- };
-
- /**
- * Number of iterations to test (the actual test shouldn't run
- * this many iterations since the Threads ought to be interrupted
- * long before it gets this far).
- */
- public static int mMaxIterations = 1000000;
-
- /**
- * Run the test for the queue parameter.
- */
- public static SynchronizedQueueResult testQueue(QueueAdapter queue) {
- try {
- mQueue = queue;
-
- // Please make sure to keep all the "TODO" comments in the
- // code below to make it easy for peer reviewers to find
- // them.
-
- // TODO - you fill in here to replace the null
- // initialization below to create two Java Threads, one
- // that's passed the producerRunnable and the other that's
- // passed the consumerRunnable.
- Thread consumer = null;
- Thread producer = null;
-
- // TODO - you fill in here to start the threads. More
- // interesting results will occur if you start the
- // consumer first.
-
- // Give the Threads a chance to run before interrupting
- // them.
- Thread.sleep(100);
-
- // TODO - you fill in here to interrupt the threads.
-
- // TODO - you fill in here to wait for the threads to
- // exit.
-
- // Do some sanity checking to see if the Threads work as
- // expected.
- if (consumer == null
- || producer == null)
- return SynchronizedQueueResult.THREADS_NEVER_CREATED;
- else if (consumer.isAlive()
- || producer.isAlive())
- return SynchronizedQueueResult.JOIN_NEVER_CALLED;
- else if (mConsumerCounter == 0
- || mProducerCounter == 0)
- return SynchronizedQueueResult.THREADS_NEVER_RAN;
- else if (mConsumerCounter == mMaxIterations
- || mProducerCounter == mMaxIterations)
- return SynchronizedQueueResult.THREADS_NEVER_INTERUPTED;
- else if (mConsumerCounter == FAILURE_OCCURRED
- || mProducerCounter == FAILURE_OCCURRED)
- return SynchronizedQueueResult.THREADS_THREW_EXCEPTION;
- else if (mConsumerCounter == TIMEOUT_OCCURRED
- || mProducerCounter == TIMEOUT_OCCURRED)
- return SynchronizedQueueResult.THREADS_TIMEDOUT;
- else
- return SynchronizedQueueResult.RAN_PROPERLY;
- } catch (Exception e) {
- return SynchronizedQueueResult.TESTING_LOGIC_THREW_EXCEPTION;
- }
- }
-}
From c79e3c234d14d25dff8f59921edbd121ae7c8bd4 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 17 May 2014 04:44:16 -0500
Subject: [PATCH 016/202] Emphasized "green" checkmarks.
---
.../week-1-assignment-0/Assignment-Description.txt | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/assignments/week-1-assignment-0/Assignment-Description.txt b/assignments/week-1-assignment-0/Assignment-Description.txt
index 04bee8455..a00867268 100644
--- a/assignments/week-1-assignment-0/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0/Assignment-Description.txt
@@ -73,8 +73,8 @@ testQueue method runs successfully. As long as this JUnit test
"passes" successfully your program will be be consider "correct" for
the purposes of assessing this assignment.
-If the tests run and "pass," you should see check-marks next to each
-of the tests in the JUnit view. As the tests run, you will also find
-output being printed to the console. This text is for informational
-purposes only and have no bearing on whether your program is
-"correct."
+If the tests run and "pass," you should see green check-marks next to
+each of the tests in the JUnit view. As the tests run, you will also
+find output being printed to the console. This text is for
+informational purposes only and have no bearing on whether your
+program is "correct."
From 28fc105db9d7d2f84173e967c84a71f97b01ce27 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 17 May 2014 04:46:22 -0500
Subject: [PATCH 017/202] Clarified what the output means.
---
assignments/week-1-assignment-0/Assignment-Description.txt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/assignments/week-1-assignment-0/Assignment-Description.txt b/assignments/week-1-assignment-0/Assignment-Description.txt
index a00867268..3ed4d4b67 100644
--- a/assignments/week-1-assignment-0/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0/Assignment-Description.txt
@@ -75,6 +75,6 @@ the purposes of assessing this assignment.
If the tests run and "pass," you should see green check-marks next to
each of the tests in the JUnit view. As the tests run, you will also
-find output being printed to the console. This text is for
-informational purposes only and have no bearing on whether your
-program is "correct."
+find debugging output being printed to the console. This debugging
+output is for informational purposes only and have no bearing on
+whether your program is "correct."
From 10812ce1413b71f9afb8579bd6834823b927ad2d Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 17 May 2014 04:49:03 -0500
Subject: [PATCH 018/202] Yet more clarifications.
---
.../Assignment-Description.txt | 23 ++++++++++---------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/assignments/week-1-assignment-0/Assignment-Description.txt b/assignments/week-1-assignment-0/Assignment-Description.txt
index 3ed4d4b67..a5564a35b 100644
--- a/assignments/week-1-assignment-0/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0/Assignment-Description.txt
@@ -67,14 +67,15 @@ compile errors should disappear!
To run the JUnit tests in Eclipse, right-click on
SynchronizedQueueTest.java and go to "Run As > JUnit Test". The JUnit
-view will pop up in Eclipse and run the tests contained therein. All
-tests should pass. The ArrayBlockingQueue should pass if your
-testQueue method runs successfully. As long as this JUnit test
-"passes" successfully your program will be be consider "correct" for
-the purposes of assessing this assignment.
-
-If the tests run and "pass," you should see green check-marks next to
-each of the tests in the JUnit view. As the tests run, you will also
-find debugging output being printed to the console. This debugging
-output is for informational purposes only and have no bearing on
-whether your program is "correct."
+view will pop up in Eclipse and run the test contained therein. If
+your testQueue method runs successfully the ArrayBlockingQueue should
+pass, i.e., a green-check mark will appear net to the test in the
+JUnit view. As long as this JUnit test "passes" successfully your
+program will be be consider "correct" for the purposes of assessing
+this assignment.
+
+As the tests run, you will also find debugging output being printed to
+the console. This debugging output is for informational purposes only
+and have no bearing on whether your program is "correct." If the
+tests run and "pass," you should see a green check-mark next to the
+test in the JUnit view, which is all that matters.
From 52582e95019fbd2c1a561ab9c4f79d4f5d4048c9 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 17 May 2014 07:22:10 -0500
Subject: [PATCH 019/202] Clarified "TODO" comments.
---
.../week-1-assignment-0/Assessment-Description.txt | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/grading-drivers/week-1-assignment-0/Assessment-Description.txt b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
index cbc5da9ba..4ad64454b 100644
--- a/grading-drivers/week-1-assignment-0/Assessment-Description.txt
+++ b/grading-drivers/week-1-assignment-0/Assessment-Description.txt
@@ -30,11 +30,11 @@ Last, copy the submitter's SynchronizedQueue.java file into your IDE
(which may have been given a random, odd name by Coursera, so you'll
need to rename it) and store it in the src/edu/vuum/mocca directory.
I recommend scanning the submitted code to ensure there are no changes
-other than replacing the "TODO" comments with the appropriate solution
-(a quick way to do this automatically is to run "diff" on the original
-SynchronizedQueue.java file and the submitted SynchronizedQueue.java
-file to make sure all the changes are as expected, in the expected
-places in the code).
+other than adding the appropriate code as indicated by the "TODO"
+comments. A quick way to check for this automatically is to run "diff"
+on the original SynchronizedQueue.java file and the submitted
+SynchronizedQueue.java file to make sure all the changes are as
+expected, in the expected places in the code.
Once you've reviewed the code against the rubric described below
please try to compile and run it, walking through the steps called out
From 00abff2a2c550972b5ef674ac55e5bd38f40bd41 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 17 May 2014 10:40:24 -0500
Subject: [PATCH 020/202] Clarified the diagnosticsEnabled variable behavior
and added more pattern-oriented comments.
---
.../src/edu/vuum/mooca/SynchronizedQueue.java | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java
index 25437d26e..bd6a10c9f 100644
--- a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java
+++ b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueue.java
@@ -294,15 +294,27 @@ else if (mQueue.size() != numberOfRemainingItemsInQueue)
*/
protected static String mTestName = null;
- public static boolean diagnosticsEnabled = false;
+ /**
+ * If this is set to true in SynchronizedQueueImpl.java then lots
+ * of debugging output will be generated.
+ */
+ public static boolean diagnosticsEnabled;
+ /**
+ * These are hook methods that play the role of "primitive
+ * operations" in the Template Method pattern. They must be
+ * defined in SynchronizedQueueImpl.java by adding code after the
+ * "TODO" comments.
+ */
protected abstract void createThreads();
protected abstract void startThreads();
protected abstract void interruptThreads();
protected abstract void joinThreads() throws InterruptedException;
/**
- * This template method runs the test on the queue parameter.
+ * This template method runs the test on the queue parameter. It
+ * decouples the test code from the user-defined code using the
+ * Template Method pattern.
*/
public SynchronizedQueueResult testQueue(QueueAdapter queue,
String testName) {
From e487ce8db4fe0d46ac9e96cdcb1ef8cdd82ed9c1 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 17 May 2014 12:42:33 -0500
Subject: [PATCH 021/202] Added new grading driver.
---
.../Assignment-Description.txt | 15 +-
.../Assignment-Description.txt | 2 +-
.../Assignment-Description.txt | 33 +-
.../week-2-assignment-1/.classpath | 7 +
grading-drivers/week-2-assignment-1/.project | 17 +
.../Assessment-Description.txt | 57 ++++
.../src/edu/vuum/mocca/BuggyLongTest.java | 117 +++++++
.../SimpleAtomicLongMultithreadedTest.java | 320 ++++++++++++++++++
.../SimpleAtomicLongSingleThreadedTest.java | 235 +++++++++++++
.../edu/vuum/mocca/SimpleAtomicLongTests.java | 18 +
10 files changed, 800 insertions(+), 21 deletions(-)
create mode 100644 grading-drivers/week-2-assignment-1/.classpath
create mode 100644 grading-drivers/week-2-assignment-1/.project
create mode 100644 grading-drivers/week-2-assignment-1/Assessment-Description.txt
create mode 100644 grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/BuggyLongTest.java
create mode 100644 grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java
create mode 100644 grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java
create mode 100644 grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java
diff --git a/assignments/week-1-assignment-0-v2/Assignment-Description.txt b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
index 65648f258..3550b2ed8 100644
--- a/assignments/week-1-assignment-0-v2/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
@@ -83,13 +83,16 @@ view will pop up in Eclipse and run the tests contained therein. All
tests should pass. The ArrayBlockingQueue will pass because your
testQueue method runs successfully. The tests for BuggyBlockingQueue
(which is an intentionally flawed class), should "pass" if some error
-occurs while running testQueue (these errors are expected). As long
-as these JUnit tests both "pass" successfully your program will be be
-consider "correct" for the purposes of assessing this assignment.
+occurs while running testQueue (these errors are expected). If a test
+passes a green-check mark will appear next to the test in the JUnit
+view. As long as this JUnit test "passes" successfully your program
+will be be consider "correct" for the purposes of assessing this
+assignment.
If the tests run and "pass," you should see check-marks next to each
of the tests in the JUnit view. If you set the diagnosticsEnabled
flag to true then debugging output will be printed to the console as
-the tests run. This text is for informational purposes only and have
-no bearing on whether your program is "correct," but will help you to
-better understand what it's doing.
+the tests run. This debugging output is for informational purposes
+only and have no bearing on whether your program is "correct." If the
+tests run and "pass," you should see a green check-mark next to the
+test in the JUnit view, which is all that matters.
diff --git a/assignments/week-1-assignment-0/Assignment-Description.txt b/assignments/week-1-assignment-0/Assignment-Description.txt
index a5564a35b..ea5578535 100644
--- a/assignments/week-1-assignment-0/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0/Assignment-Description.txt
@@ -69,7 +69,7 @@ To run the JUnit tests in Eclipse, right-click on
SynchronizedQueueTest.java and go to "Run As > JUnit Test". The JUnit
view will pop up in Eclipse and run the test contained therein. If
your testQueue method runs successfully the ArrayBlockingQueue should
-pass, i.e., a green-check mark will appear net to the test in the
+pass, i.e., a green-check mark will appear next to the test in the
JUnit view. As long as this JUnit test "passes" successfully your
program will be be consider "correct" for the purposes of assessing
this assignment.
diff --git a/assignments/week-2-assignment-1/Assignment-Description.txt b/assignments/week-2-assignment-1/Assignment-Description.txt
index 89bd37f56..cd35d72e6 100644
--- a/assignments/week-2-assignment-1/Assignment-Description.txt
+++ b/assignments/week-2-assignment-1/Assignment-Description.txt
@@ -3,7 +3,7 @@ Week 2: Programming Assignment 1
Released Monday, May 19th, 2014
Due Monday, June 2nd, 2014
-In this seonc assignment, you will implement a subset of the
+In this second assignment, you'll implement a subset of the
java.util.concurrent.atomic.SimpleAtomicLong class using a Java
ReentrantReadWriteLock. The goal is to understand how to use
ReentrantReadWriteLock to serialize access to a variable that's shared
@@ -11,10 +11,10 @@ by multiple threads.
The BuggyLongTest.java program shows what happens if concurrent access
to a long isn't properly serialized. This test program works best on
-a multi-core/multi-processor machine, which should actually induce
-failure due to race conditions stemming from parallel execution. If
-this test "succeeds" then your target platform is not sufficiently
-parallel to demonstrate the bug.
+a multi-core/multi-processor machine, which should induce a failure
+due to race conditions stemming from parallel execution. If this test
+"succeeds" then your target platform may not be sufficiently parallel
+to demonstrate the race conditions.
In the src/edu/vuum/mocca directory you'll find the
SimpleAtomicLong.java class, which contains the skeleton Java code
@@ -48,23 +48,28 @@ classes, which are described in this video:
Section 1: Module 2: Part 9: Java CountDownLatch
-At the moment, all these videos are available in the YouTube playlist
-at
-
-https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4tbiFYip6tDNIEBRUDyPQK
-
-When the 2014 POSA MOOC officially starts these videos will be
-available at
+These videos are available at
https://class.coursera.org/posa-002/lecture
-To test this code in Eclipse, right-click on
+When you first open the project in Eclipse, you might see compile
+errors if JUnit is not included in your build path. To fix these
+errors, open SynchronizedQueueTest.java, hover over "org.junit," and
+click "Fix project setup." Make sure "Add JUnit 4 library to the
+build path" is selected and then click "OK." At this point, the
+compile errors should disappear!
+
+To run the JUnit tests in Eclipse, right-click on
SimpleAtomicLongTests.java and Run As > JUnit Test. The JUnit view
will pop up in Eclipse and run the the tests, which are divided into
two subsets: multi-threaded and single-threaded tests. The
single-threaded tests verify functionality of all methods within a
single thread, while the multi-threaded tests do the same in a
-multi-threaded environment. All tests should run successfully.
+multi-threaded environment. All tests should run successfully, i.e.,
+a green-check mark will appear next to the test in the JUnit view. As
+long as this JUnit test "passes" successfully your program will be be
+consider "correct" for the purposes of assessing this assignment.
+
diff --git a/grading-drivers/week-2-assignment-1/.classpath b/grading-drivers/week-2-assignment-1/.classpath
new file mode 100644
index 000000000..3e0fb272a
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/grading-drivers/week-2-assignment-1/.project b/grading-drivers/week-2-assignment-1/.project
new file mode 100644
index 000000000..72dbe761b
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/.project
@@ -0,0 +1,17 @@
+
+
+ W2-A1-SimpleAtomicLong-Grading
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/grading-drivers/week-2-assignment-1/Assessment-Description.txt b/grading-drivers/week-2-assignment-1/Assessment-Description.txt
new file mode 100644
index 000000000..724b2df23
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/Assessment-Description.txt
@@ -0,0 +1,57 @@
+Week 2: Programming Assignment 1 Peer Assessment Description
+
+Due Monday, June 9th, 2014
+
+You will be asked to evaluate five other student's projects as well as
+do a self assessment of your own project. If you do not assess the
+work of others, then you will not pass this assignment.
+
+As you do your evaluation, please keep an open mind and focus on the
+positive. Our goal is not to find every way to deduct points over
+small deviations from the requirements or for legitimate differences
+in implementation styles, etc. Look for ways to give points when it's
+clear that the submitter has given a good faith effort to do the
+project, and when it's likely that they've succeeded.
+
+Review the submitter's source code. Since you did your own project,
+you know where the changes should be and you have a good idea of the
+kind of method calls and work flows that should be in the submitter's
+code. Remember that they may have done things differently than you
+did. That's fine.
+
+Next, get a copy of the grading driver files from
+
+https://github.com/douglascraigschmidt/POSA-14/tree/master/grading-drivers/week-2-assignment-1
+
+and copy the submitter's SimpleAtomicLong.java file into your IDE
+(which may have been given a random, odd name by Coursera, so you'll
+need to rename it) and store it in the src/edu/vuum/mocca/ directory.
+I recommend scanning the submitted code to ensure there are no changes
+other than adding the appropriate code as indicated by the "TODO"
+comments. A quick way to check for this automatically is to run "diff"
+on the original SimpleAtomicLong.java file and the submitted
+SimpleAtomicLong.java file to make sure all the changes are as
+expected, in the expected places in the code. Then make sure
+everything compiles properly in your environment. Note that the
+grading drivers are in a different location than the original
+skeletons to ensure that all submissions are tested against the
+"master" regression tests and minimize the amount of code that comes
+from "the wild".
+
+Once you've reviewed the code against the rubric described below
+please try to run it, walking through the steps called out in the
+grading video that we'll create in each week's "VIrtual Office Hours"
+(see item #38 in the POSA MOOC FAQ at
+http://www.coursera.org/course/posa for info on Virtual Office
+Hours). I suggest you make a fresh Eclipse workspace when doing this,
+so that the submitter's code is isolated and easily distinguishable
+from yours. One way you can do that is to select File > Open Workspace
+> Browse > New Folder. This will lead to a new, empty Eclipse
+workspace. Then you can copy that submitter's SimpleAtomicLong.java
+file into this new workspace. Also, it's recommended to run the
+submitted code a virtual machine sandbox to further isolate it from
+causing harm.
+
+And again, remember that most everyone is working very hard and
+putting in a serious effort. When in doubt, err on the side of giving
+too many points, rather than giving too few.
diff --git a/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/BuggyLongTest.java b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/BuggyLongTest.java
new file mode 100644
index 000000000..fc854689b
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/BuggyLongTest.java
@@ -0,0 +1,117 @@
+package edu.vuum.mocca;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+
+/**
+ * @class BuggyLongTest
+ *
+ * @brief This class shows what happens if concurrent access to a long
+ * isn't properly serialized.
+ */
+class BuggyLongTest
+{
+ /**
+ * Number of iterations to run the test.
+ */
+ static final long mMaxIterations = 100000000;
+
+ /**
+ * Barrier synchronizer that controls when the two threads start
+ * running the test.
+ */
+ static CyclicBarrier mStartBarrier = new CyclicBarrier(2);
+
+ /**
+ * Barrier synchronizer that controls when the main thread can
+ * return.
+ */
+ static CountDownLatch mStopLatch = new CountDownLatch(2);
+
+ /**
+ * An instance of long that's not protected by a lock.
+ */
+ static long mCounter = 0;
+
+ /**
+ * Main entry point method that runs the test.
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("Starting BuggyLongTest");
+
+ /**
+ * Start a Thread whose Runnable decrements the SimpleAtomicLong
+ * mMaxIterations number of times.
+ */
+ new Thread(new Runnable()
+ { public void run() {
+ try
+ {
+ /**
+ * Wait for both Threads to start running
+ * before beginning the loop.
+ */
+ mStartBarrier.await();
+
+ for (int i = 0; i < mMaxIterations; ++i)
+ mCounter--;
+
+ /**
+ * Inform the main thread that we're done.
+ */
+ mStopLatch.countDown();
+ }
+ catch (Exception e)
+ {
+ System.out.println("problem here");
+ }
+ }
+ }).start();
+
+ /**
+ * Start a Thread whose Runnable increments the SimpleAtomicLong
+ * mMaxIterations number of times.
+ */
+ new Thread(new Runnable()
+ { public void run() {
+ try {
+ /**
+ * Wait for both Threads to start running
+ * before beginning the loop.
+ */
+ mStartBarrier.await();
+
+ for (int i = 0; i < mMaxIterations; ++i)
+ mCounter++;
+
+ /**
+ * Inform the main thread that we're done.
+ */
+ mStopLatch.countDown();
+ }
+ catch (Exception e) { }
+ }
+ }).start();
+
+ /**
+ * Barrier synchronizer that waits for both worker threads
+ * to exit before continuing.
+ */
+ mStopLatch.await();
+
+ long result = mCounter;
+ /**
+ * Check to ensure the test worked, i.e., mCounter's value
+ * should be 0.
+ */
+ if (result == 0)
+ System.out.println("test worked");
+ else
+ System.out.println("test failed: mCounter = " + result);
+
+ System.out.println("Finishing BuggyLongTest");
+ }
+ catch (Exception e) { }
+ }
+}
diff --git a/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java
new file mode 100644
index 000000000..401bcd63f
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java
@@ -0,0 +1,320 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.*;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @class SimpleAtomicLongMultithreadedTest
+ *
+ * @brief Test the logic and multithreaded implementation of the
+ * SimpleAtomicLong class by having concurrent threads call the
+ * SimpleAtomicLong instance for various methods.
+ */
+public class SimpleAtomicLongMultithreadedTest {
+
+ /**
+ * Our start points.
+ */
+ final static long INITIAL_VALUE = 0;
+
+ /**
+ * Number of iterations to run the commands.
+ */
+ final static long mMaxIterations = 1000000;
+
+ /**
+ * Barrier synchronizer that controls when the threads start
+ * running the test.
+ */
+ static CyclicBarrier mStartBarrier;
+
+ /**
+ * Barrier synchronizer that controls when the main thread can
+ * return.
+ */
+ static CountDownLatch mStopLatch;
+
+ /**
+ * An instance of our implementation of SimpleAtomicLong.
+ */
+ static SimpleAtomicLong mCounter;
+
+ /**
+ * Runnable commands that use the mCounter methods
+ * get()
+ * incrementAndGet()
+ * getAndIncrement()
+ * decrementAndGet()
+ * getAndDecrement()
+ */
+ static Runnable getCommand;
+ static Runnable incrementGetCommand;
+ static Runnable getIncrementCommand;
+ static Runnable decrementGetCommand;
+ static Runnable getDecrementCommand;
+
+ /**
+ * The value of mCounter prior to any changes made by testing.
+ */
+ long preTestValue;
+
+ /**
+ * The number of duplicate threads to run when testing each
+ * individual command.
+ */
+ final int numThreads = 5;
+
+ /**
+ * @class RunTest
+ *
+ * @brief This class runs the test by invoking a command each time
+ * through the loop.
+ */
+ static class RunTest implements Runnable
+ {
+ /**
+ * A Command that determines what operation is done within the
+ * loop.
+ */
+ private Runnable mCommand;
+
+ /**
+ * An integer which keeps track of the number of times the
+ * command has been called. Initially equal to zero.
+ */
+ private long iterations = 0;
+
+ /**
+ * Store the command in a data member field.
+ */
+ RunTest(Runnable command) {
+ mCommand = command;
+ }
+
+ /**
+ * Run the command within a loop.
+ */
+ public void run() {
+ try
+ {
+ /**
+ * Wait for all Threads to start running before
+ * beginning the loop.
+ */
+ mStartBarrier.await();
+
+ for (; iterations < mMaxIterations; ++iterations) {
+ mCommand.run();
+ }
+ /**
+ * Inform the main thread that we're done.
+ */
+ mStopLatch.countDown();
+ } catch (Exception e) {
+ fail("Runnable failed.");
+ }
+ }
+
+ /**
+ * Returns the number of times this command has been performed.
+ * @return iterations
+ */
+ public long getIterations() {
+ return iterations;
+ }
+ }
+
+ /**
+ * Runs prior to all tests. Creates a static instance of
+ * SimpleAtomicLong and all runnable commands.
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ /**
+ * Instance of SimpleAtomicLong class
+ */
+ mCounter = new SimpleAtomicLong(INITIAL_VALUE);
+
+ /**
+ * Runnable commands that execute get(), incrementAndGet(),
+ * getAndIncrement(), decrementAndGet(), getAndDecrement(),
+ * respectively, on the SimpleAtomicLong instance
+ */
+ getCommand = new Runnable() { public void run() { mCounter.get(); } };
+ incrementGetCommand = new Runnable() { public void run() { mCounter.incrementAndGet(); } };
+ getIncrementCommand = new Runnable() { public void run() { mCounter.getAndIncrement(); } };
+ decrementGetCommand = new Runnable() { public void run() { mCounter.decrementAndGet(); } };
+ getDecrementCommand = new Runnable() { public void run() { mCounter.getAndDecrement(); } };
+ }
+
+ /**
+ * Runs prior to each test. Stores the pre-test value of the mCounter.
+ */
+ @Before
+ public void setUp() throws Exception {
+ preTestValue = mCounter.get();
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code get()}.
+ */
+ @Test
+ public void multiGetTest() {
+ /**
+ * run multiple threads calling mCounter.get().
+ */
+ runThreads(getCommand);
+ /**
+ * The expected post-test value is no change in the pre-test
+ * value.
+ */
+ assertEquals(preTestValue,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code
+ * incrementAndGet()}.
+ */
+ @Test
+ public void multiIncrementAndGetTest() {
+ runThreads(incrementGetCommand);
+ /**
+ * expected value after threads are run should be the number
+ * of maximum iterations times the number of threads plus the
+ * pre-test value
+ */
+ assertEquals(preTestValue
+ + mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code getAndIncrement()}.
+ */
+ @Test
+ public void multiGetAndIncrementTest() {
+ runThreads(getIncrementCommand);
+ assertEquals(preTestValue
+ + mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code
+ * decrementAndGet()}.
+ */
+ @Test
+ public void multiDecrementAndGetTest() {
+ runThreads(decrementGetCommand);
+ /**
+ * Expected value of mCounter after threads have completed
+ * running is the pre-test value minus the maximum iterations
+ * times the number of threads that were run.
+ */
+ assertEquals(preTestValue -
+ mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests for proper concurrency and functionality of {@code getAndIncrement()}.
+ */
+ @Test
+ public void multiGetAndDecrementTest() {
+ runThreads(getDecrementCommand);
+ /**
+ * expected value of mCounter after threads have completed running
+ * is the pre-test value minus the maximum iterations times the number
+ * of threads that were run
+ */
+ assertEquals(preTestValue -
+ mMaxIterations*numThreads,
+ mCounter.get());
+ }
+
+ /**
+ * Tests concurrent running of threads performing a variety of
+ * operations on mCounter (e.g. {@code get()}, {@code
+ * getAndIncrement()}, {@code getAndDecrement()},{@code
+ * incrementAndGet()}, and {@code decrementAndGet()}).
+ */
+ @Test
+ public void multiThreadedTest() {
+ /**
+ * Run five threads concurrently, each performing a different
+ * method on the SimpleAtomicLong instance
+ */
+ runThreads(null);
+ /**
+ * Check to ensure the pre-test and post-test values are
+ * equal. This indicates the test was successful.
+ */
+ assertEquals(preTestValue,
+ mCounter.get());
+ }
+
+ /**
+ * Runs numThreads concurrent threads executing the same command.
+ * Has a CyclicBarrier and CountDownLatch to facilitate
+ * concurrency.
+ * @param command
+ */
+ private void runThreads(Runnable command) {
+ mStartBarrier = new CyclicBarrier(numThreads);
+ mStopLatch = new CountDownLatch(numThreads);
+ try {
+ /**
+ * Create an array of RunTests whose Runnable commands
+ * execute on the SimpleAtomicLong mMaxIterations number
+ * of times. If given a command, each thread should run
+ * duplicates. If command is null, then run one of each
+ * type of command.
+ */
+ RunTest[] runTests;
+ if(command == null) {
+ runTests = new RunTest[5];
+ runTests[0] = new RunTest(getCommand);
+ runTests[1] = new RunTest(incrementGetCommand);
+ runTests[2] = new RunTest(decrementGetCommand);
+ runTests[3] = new RunTest(getDecrementCommand);
+ runTests[4] = new RunTest(getIncrementCommand);
+ }
+ else {
+ runTests = new RunTest[numThreads];
+ for(int i = 0; i < runTests.length; i++)
+ runTests[i] = new RunTest(command);
+ }
+
+ /**
+ * Start threads whose Runnable commands execute on the
+ * SimpleAtomicLong mMaxIterations number of times.
+ */
+ for(int i = 0; i < runTests.length; i++)
+ new Thread(runTests[i]).start();
+
+ /**
+ * Barrier synchronizer that waits for all worker threads
+ * to exit before continuing.
+ */
+ mStopLatch.await();
+
+ /**
+ * Check to ensure threads have run.
+ */
+ for(int i = 0; i < runTests.length; i++)
+ assertEquals("Threads have not executed.",
+ mMaxIterations,
+ runTests[i].getIterations());
+ } catch (Exception e) {
+ fail("Exception thrown.");
+ }
+ }
+
+}
diff --git a/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java
new file mode 100644
index 000000000..ef28e3e0a
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongSingleThreadedTest.java
@@ -0,0 +1,235 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @brief SimpleAtomicLongSingleThreadedTest
+ *
+ * @class Evalutes the logic of the SimpleAtomicLong class by testing
+ * every method with each of the values in mTestValues.
+ */
+public class SimpleAtomicLongSingleThreadedTest {
+ /*
+ * Test possible edge cases at 0, and a large negative and
+ * positive.
+ */
+ final static long[] mTestValues = { -100, -1, 0, 1, 100 };
+
+ /**
+ * Test Constructor.
+ */
+ @Test
+ public void constructorTest() {
+ for (long testValue : mTestValues) {
+ SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ Assert.assertNotNull(counter);
+ assertEquals(testValue, counter.get());
+ }
+ }
+
+ /**
+ * Test get()
+ */
+ @Test
+ public void getTest() {
+ for (long testValue : mTestValues) {
+ SimpleAtomicLong counter = new SimpleAtomicLong(testValue);
+ assertEquals(testValue,
+ counter.get());
+ }
+ }
+
+ /**
+ * test decrementAndGet()
+ */
+ @Test
+ public void decrementAndGetTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ decrementAndGetTestLogic(counter,
+ testValue,
+ testValue - 1,
+ testValue - 1);
+ }
+ }
+
+ /**
+ * test getAndDecrement()
+ */
+ @Test
+ public void getAndDecrementTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ getAndDecrementTestLogic(counter,
+ testValue,
+ testValue,
+ testValue - 1);
+ }
+ }
+
+ /**
+ * test incrementAndGet()
+ */
+ @Test
+ public void incrementAndGetTestTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ incrementAndGetTestLogic(counter,
+ testValue,
+ testValue + 1,
+ testValue + 1);
+ }
+ }
+
+ /**
+ * test getAndIncrement()
+ */
+ @Test
+ public void getAndIncrementTest() {
+ for (long testValue : mTestValues) {
+ final SimpleAtomicLong counter =
+ new SimpleAtomicLong(testValue);
+ getAndIncrementTestLogic(counter,
+ testValue,
+ testValue,
+ testValue + 1);
+ }
+ }
+
+ /**
+ * Compares the values expected with the values produced by each test logic.
+ *
+ * @param pre
+ * The 'pre' number produced by the test
+ * @param preValue
+ * The 'pre' number expected
+ * @param result
+ * The 'result' number produced by the test
+ * @param resultValue
+ * The 'result' expected
+ * @param post
+ * The 'post' number produced by the test
+ * @param postValue
+ * The 'post' expected
+ */
+ private void compareResults(long pre, long preValue, long result,
+ long resultValue, long post, long postValue) {
+ assertEquals(pre, preValue);
+ assertEquals(result, resultValue);
+ assertEquals(post, postValue);
+ }
+
+ /**
+ * The Logic of testing decrementAndGet
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void decrementAndGetTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.decrementAndGet();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre - 1, result);
+ assertEquals(result, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post,
+ postValue);
+ }
+
+ /**
+ * The Logic of testing getAndDecrement
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void getAndDecrementTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.getAndDecrement();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre, result);
+ assertEquals(pre - 1, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post,
+ postValue);
+ }
+
+ /**
+ * The Logic of testing incrementAndGet
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void incrementAndGetTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.incrementAndGet();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre + 1, result);
+ assertEquals(result, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post,
+ postValue);
+ }
+
+ /**
+ * The Logic of testing getAndIncrement
+ *
+ * @param simpleAtomicLong
+ * The SimpleAtomicLong to be tested
+ * @param preValue
+ * The expected 'pre' value
+ * @param resultValue
+ * The expected 'result' value
+ * @param postValue
+ * The expected 'post' value
+ */
+ public void getAndIncrementTestLogic(SimpleAtomicLong simpleAtomicLong,
+ long preValue, long resultValue, long postValue) {
+ long pre = simpleAtomicLong.get();
+ long result = simpleAtomicLong.getAndIncrement();
+ long post = simpleAtomicLong.get();
+ assertEquals(pre, result);
+ assertEquals(pre + 1, post);
+ compareResults(pre,
+ preValue,
+ result,
+ resultValue,
+ post, postValue);
+ }
+}
diff --git a/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java
new file mode 100644
index 000000000..990496762
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongTests.java
@@ -0,0 +1,18 @@
+package edu.vuum.mocca;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+
+@RunWith(Suite.class)
+@SuiteClasses({ SimpleAtomicLongMultithreadedTest.class,
+ SimpleAtomicLongSingleThreadedTest.class })
+/**
+ * @class SimpleAtomicLongTest
+ *
+ * @brief Entry point for running all the regression tests for the
+ * SimpleAtomicLong implementation.
+ */
+public class SimpleAtomicLongTests {
+}
From f5a7afd229c125991d20700699adbb898169c8ab Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Tue, 20 May 2014 11:46:49 -0500
Subject: [PATCH 022/202] added SynchronizedQueue.java back.
---
.../src/edu/vuum/mooca/SynchronizedQueue.java | 265 ++++++++++++++++++
1 file changed, 265 insertions(+)
create mode 100644 grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
diff --git a/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java b/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
new file mode 100644
index 000000000..c4ffb3c18
--- /dev/null
+++ b/grading-drivers/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java
@@ -0,0 +1,265 @@
+package edu.vuum.mooca;
+import java.util.concurrent.*;
+
+/**
+ * @class SynchronizedQueue
+ *
+ * @brief This class tests the use of Java Threads and several
+ * implementations of the Java BlockingQueue interface.
+ */
+public class SynchronizedQueue {
+ /**
+ * Keep track of the number of times the producer test iterates.
+ */
+ static volatile int mProducerCounter = 0;
+
+ /**
+ * Keep track of the number of times the consumer test iterates.
+ */
+ static volatile int mConsumerCounter = 0;
+
+ /**
+ * Maximum timeout.
+ */
+ static final int TIMEOUT_SECONDS = 5;
+
+ /**
+ * Error value for a timeout.
+ */
+ static final int TIMEOUT_OCCURRED = -1;
+
+ /**
+ * Error value for a failure.
+ */
+ static final int FAILURE_OCCURRED = -2;
+
+ /**
+ * @class SynchronizedQueueResult
+ *
+ * @brief Enumerated type for return values of testing logic, has
+ * String for easy output.
+ */
+ public enum SynchronizedQueueResult {
+ RAN_PROPERLY("Threads Ran Properly."),
+ JOIN_NEVER_CALLED("Join() never called."),
+ THREADS_NEVER_RAN("Threads never ran."),
+ THREADS_NEVER_INTERUPTED("Threads never interrupted."),
+ THREADS_THREW_EXCEPTION("Thread threw an exception."),
+ THREADS_NEVER_CREATED("Threads never created."),
+ TESTING_LOGIC_THREW_EXCEPTION("Testing Logic threw Exception."),
+ THREADS_TIMEDOUT("Threads Timed-out, Interupt likely not called.");
+
+ /**
+ * String value for the enumerated type.
+ */
+ private String mValue = null;
+
+ /**
+ * Initialize the mValue string.
+ */
+ private SynchronizedQueueResult(String value) {
+ mValue = value;
+ }
+
+ /**
+ * Return the mValue string.
+ */
+ public String getString() {
+ return mValue;
+ }
+ }
+
+ /**
+ * @class QueueAdapter
+ *
+ * @brief Applies a variant of the GoF Adapter pattern that
+ * enables us to test several implementations of the
+ * BlockingQueue interface.
+ */
+ public static class QueueAdapter {
+ /**
+ * Stores the queue that we're adapting.
+ */
+ private BlockingQueue mQueue;
+
+ /**
+ * Store the queue that we're adapting.
+ */
+ public QueueAdapter(BlockingQueue queue) {
+ mQueue = queue;
+ }
+
+ /**
+ * Insert msg at the tail of the queue.
+ *
+ * @throws TimeoutException and InterruptedException
+ */
+ public void put(E msg) throws InterruptedException, TimeoutException {
+ // Keep track of how many times we're called.
+ mProducerCounter++;
+ boolean timeoutValue = mQueue.offer(msg,
+ TIMEOUT_SECONDS,
+ TimeUnit.SECONDS);
+ if (timeoutValue == false)
+ throw new TimeoutException();
+ }
+
+ /**
+ * Remove msg from the head of the queue.
+ *
+ * @throws TimeoutException
+ * , InterruptedException
+ */
+ public E take() throws InterruptedException, TimeoutException {
+ // Keep track of how many times we're called.
+ mConsumerCounter++;
+ E rValue = mQueue.poll(TIMEOUT_SECONDS,
+ TimeUnit.SECONDS);
+
+ if (rValue == null)
+ throw new TimeoutException();
+
+ return rValue;
+ }
+ }
+
+ /**
+ * Adapter object used to test different BlockingQueue
+ * implementations.
+ */
+ private static QueueAdapter mQueue = null;
+
+ /**
+ * This runnable loops for mMaxIterations and calls put() on
+ * mQueue to insert the iteration number into the queue.
+ */
+ static Runnable producerRunnable = new Runnable() {
+ public void run() {
+ for (int i = 0; i < mMaxIterations; i++)
+ try {
+ mQueue.put(i);
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ } catch (InterruptedException e) {
+ System.out.println("Thread properly interrupted by "
+ + e.toString() + " in producerRunnable");
+ // This isn't an error - it just means that
+ // we've been interrupted by the main Thread.
+ return;
+ } catch (TimeoutException e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in producerRunnable");
+ // Indicate a timeout.
+ mProducerCounter = TIMEOUT_OCCURRED;
+ return;
+ } catch (Exception e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in producerRunnable");
+ // Indicate a failure.
+ mProducerCounter = FAILURE_OCCURRED;
+ return;
+ }
+ }
+ };
+
+ /**
+ * This runnable loops for mMaxIterations and calls take() on mQueue to
+ * remove the iteration from the queue.
+ */
+ static Runnable consumerRunnable = new Runnable() {
+ public void run() {
+ for (int i = 0; i < mMaxIterations; i++)
+ try {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+ Integer result = (Integer) mQueue.take();
+
+ System.out.println("iteration = " + result);
+ } catch (InterruptedException e) {
+ System.out.println("Thread properly interrupted by "
+ + e.toString() + " in consumerRunnable");
+ // This isn't an error - it just means that
+ // we've been interrupted by the main Thread.
+ return;
+ } catch (TimeoutException e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in consumerRunnable");
+ // Indicate a timeout.
+ mConsumerCounter = TIMEOUT_OCCURRED;
+ return;
+ } catch (Exception e) {
+ System.out.println("Exception " + e.toString()
+ + " occurred in consumerRunnable");
+ // Indicate a failure.
+ mConsumerCounter = FAILURE_OCCURRED;
+ return;
+ }
+ }
+ };
+
+ /**
+ * Number of iterations to test (the actual test shouldn't run
+ * this many iterations since the Threads ought to be interrupted
+ * long before it gets this far).
+ */
+ public static int mMaxIterations = 1000000;
+
+ /**
+ * Run the test for the queue parameter.
+ */
+ public static SynchronizedQueueResult testQueue(QueueAdapter queue) {
+ try {
+ mQueue = queue;
+
+ // Please make sure to keep all the "TODO" comments in the
+ // code below to make it easy for peer reviewers to find
+ // them.
+
+ // TODO - you fill in here to replace the null
+ // initialization below to create two Java Threads, one
+ // that's passed the producerRunnable and the other that's
+ // passed the consumerRunnable.
+ Thread consumer = null;
+ Thread producer = null;
+
+ // TODO - you fill in here to start the threads. More
+ // interesting results will occur if you start the
+ // consumer first.
+
+ // Give the Threads a chance to run before interrupting
+ // them.
+ Thread.sleep(100);
+
+ // TODO - you fill in here to interrupt the threads.
+
+ // TODO - you fill in here to wait for the threads to
+ // exit.
+
+ // Do some sanity checking to see if the Threads work as
+ // expected.
+ if (consumer == null
+ || producer == null)
+ return SynchronizedQueueResult.THREADS_NEVER_CREATED;
+ else if (consumer.isAlive()
+ || producer.isAlive())
+ return SynchronizedQueueResult.JOIN_NEVER_CALLED;
+ else if (mConsumerCounter == 0
+ || mProducerCounter == 0)
+ return SynchronizedQueueResult.THREADS_NEVER_RAN;
+ else if (mConsumerCounter == mMaxIterations
+ || mProducerCounter == mMaxIterations)
+ return SynchronizedQueueResult.THREADS_NEVER_INTERUPTED;
+ else if (mConsumerCounter == FAILURE_OCCURRED
+ || mProducerCounter == FAILURE_OCCURRED)
+ return SynchronizedQueueResult.THREADS_THREW_EXCEPTION;
+ else if (mConsumerCounter == TIMEOUT_OCCURRED
+ || mProducerCounter == TIMEOUT_OCCURRED)
+ return SynchronizedQueueResult.THREADS_TIMEDOUT;
+ else
+ return SynchronizedQueueResult.RAN_PROPERLY;
+ } catch (Exception e) {
+ return SynchronizedQueueResult.TESTING_LOGIC_THREW_EXCEPTION;
+ }
+ }
+}
From 2a6a4fd9294e0528f81f238df67d113a45e4e6a4 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 21 May 2014 14:31:07 -0500
Subject: [PATCH 023/202] Cleaned things up a bit.
---
.../Assignment-Description.txt | 29 +++++++++++--------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index 1a9d94c75..d29f6e031 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -1,22 +1,27 @@
-Programming Assignment 0.5
+Week 3: Programming Assignment 2
+
+Released Monday, May 26th, 2014
+Due Monday, June 9th, 2014
In this assignment, you will use a Java ReentrantLock and Java
ConditionObject to implement a subset of the Java
java.util.concurrent.Semaphore class, which we call SimpleSemaphore.
This assignment also reuses the SimpleAtomicLock you implemented for
-Assignment 0, so make sure it's working properly before attempting
-this assignment! The goal of this assignment is to use the
-SimpleSemaphore to correctly implement a resource manager that limits
-the number of Beings from Middle-Earth who can concurrently gaze into
-a Palantir (if you're not a Lord of the Ring's fan see
+Assignment 0, so make sure it's compiling and running properly before
+attempting this assignment!
+
+The goal of this assignment is to use the SimpleSemaphore to correctly
+implement a resource manager that limits the number of Beings from
+Middle-Earth who can concurrently gaze into a Palantir. Please see
http://en.wikipedia.org/wiki/Palantir for more information on
-Palantir).
+Palantirs if you're not yet a fan of Tolkein's Lord of the Ring's.
The PalantirManagerTest.java program creates three Palantiri and five
Threads (one for each Palantir user) that concurrently attempt to
acquire a Palantir and gaze into it for a certain amount of time. If
the SimpleSemaphore and SimpleAtomicLock are implemented properly the
-test should succeed without throwing any exceptions.
+test should succeed without throwing any exceptions, as described
+further below.
In this directory you'll find a number of files, all of which you
should read. However, the only two files you need to modify are
@@ -29,7 +34,7 @@ fill in here" portions!!!
In particular, you'll need to do the following:
. Implement the SimpleAtomicLong class, which you should replace with
- your working solution to assignment0.
+ your working solution to week-2-assignment-1.
. Implement the SimpleSemaphore class using a Java ConditionObject and
Java ReentrantLock, which are covered in these videos:
@@ -199,7 +204,7 @@ mFairnessChecker.addNewThread() and then yield to another thread which
again calls mFairnessChecker.addNewThread() and then goes on without
interruption to call mPalantirManager.acquirePalantir(), which will
fool the fairness checker into wrongly thinking the acquisition wasn't
-fair. we'll just give a warning (rather than an error) if it looks
-like the semaphore acquire() method isn't "fair". The key is not to
-have runtime exceptions in your output!
+fair. We therefore just give a warning (rather than an error) if it
+looks like the semaphore acquire() method isn't "fair". The key is
+not to have runtime exceptions in your output!
From 596ab7e5bfdb92582c9310c24edf5697ce8e1cc0 Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 03:35:32 -0500
Subject: [PATCH 024/202] moved souce files to non-default package
---
.../src/{ => edu/vuum/mocca}/FairnessChecker.java | 0
.../week-3-assignment-2/src/{ => edu/vuum/mocca}/Palantir.java | 0
.../src/{ => edu/vuum/mocca}/PalantirManager.java | 0
.../src/{ => edu/vuum/mocca}/PalantirManagerTest.java | 0
.../src/{ => edu/vuum/mocca}/SimpleAtomicLong.java | 0
.../src/{ => edu/vuum/mocca}/SimpleSemaphore.java | 0
6 files changed, 0 insertions(+), 0 deletions(-)
rename assignments/week-3-assignment-2/src/{ => edu/vuum/mocca}/FairnessChecker.java (100%)
rename assignments/week-3-assignment-2/src/{ => edu/vuum/mocca}/Palantir.java (100%)
rename assignments/week-3-assignment-2/src/{ => edu/vuum/mocca}/PalantirManager.java (100%)
rename assignments/week-3-assignment-2/src/{ => edu/vuum/mocca}/PalantirManagerTest.java (100%)
rename assignments/week-3-assignment-2/src/{ => edu/vuum/mocca}/SimpleAtomicLong.java (100%)
rename assignments/week-3-assignment-2/src/{ => edu/vuum/mocca}/SimpleSemaphore.java (100%)
diff --git a/assignments/week-3-assignment-2/src/FairnessChecker.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/FairnessChecker.java
rename to assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java
diff --git a/assignments/week-3-assignment-2/src/Palantir.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/Palantir.java
rename to assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java
diff --git a/assignments/week-3-assignment-2/src/PalantirManager.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/PalantirManager.java
rename to assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java
diff --git a/assignments/week-3-assignment-2/src/PalantirManagerTest.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/PalantirManagerTest.java
rename to assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java
diff --git a/assignments/week-3-assignment-2/src/SimpleAtomicLong.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/SimpleAtomicLong.java
rename to assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
diff --git a/assignments/week-3-assignment-2/src/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/SimpleSemaphore.java
rename to assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
From 3001a2818228bd91ed6da05f00db7ad4a0c9babc Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 03:38:28 -0500
Subject: [PATCH 025/202] added package declaration in each file
---
.../week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java | 2 ++
.../week-3-assignment-2/src/edu/vuum/mocca/Palantir.java | 2 ++
.../week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java | 2 ++
.../src/edu/vuum/mocca/PalantirManagerTest.java | 2 ++
.../src/edu/vuum/mocca/SimpleAtomicLong.java | 2 ++
.../week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java | 2 ++
6 files changed, 12 insertions(+)
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java
index cf688c746..264c857e3 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java
@@ -1,3 +1,5 @@
+package edu.vuum.mocca;
+
import java.util.List;
import java.util.ArrayList;
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java
index 023abad56..1ecd8d2bd 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java
@@ -1,3 +1,4 @@
+package edu.vuum.mocca;
/**
* @class Palantir
*
@@ -5,6 +6,7 @@
* Essentially plays the role of a "command" in the Command
* pattern.
*/
+
interface Palantir {
/**
* Gaze into the Palantir (and go into a tranc ;-)).
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java
index 5f7486f45..e74f2eb11 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java
@@ -1,3 +1,5 @@
+package edu.vuum.mocca;
+
import java.util.List;
/**
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java
index f4e5c485c..e4eb62d75 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java
@@ -1,3 +1,5 @@
+package edu.vuum.mocca;
+
import java.util.List;
import java.util.ListIterator;
import java.util.ArrayList;
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
index 17dab3db1..37f4d7fb4 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
@@ -1,5 +1,7 @@
// Import the necessary Java synchronization and scheduling classes.
+package edu.vuum.mocca;
+
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.Lock;
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
index fe3f65404..e586b2da8 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
@@ -1,3 +1,5 @@
+package edu.vuum.mocca;
+
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
From a2c5a8a0a8d3de085bb07a61cef048389c597715 Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 03:44:53 -0500
Subject: [PATCH 026/202] Added JUnit 4 and ./test/ to classpath and first
JUnit test case
---
assignments/week-3-assignment-2/.classpath | 2 +
.../edu/vuum/mocca/SimpleSemaphoreTest.java | 49 +++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreTest.java
diff --git a/assignments/week-3-assignment-2/.classpath b/assignments/week-3-assignment-2/.classpath
index 18d70f02c..b0e3db7ba 100644
--- a/assignments/week-3-assignment-2/.classpath
+++ b/assignments/week-3-assignment-2/.classpath
@@ -1,6 +1,8 @@
+
+
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreTest.java
new file mode 100644
index 000000000..4d0e2e7db
--- /dev/null
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreTest.java
@@ -0,0 +1,49 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SimpleSemaphoreTest {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testSimpleSemaphore() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testAcquire() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testAcquireUninterruptibly() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testRelease() {
+ fail("Not yet implemented");
+ }
+
+}
From 7b0ed0cf8a8552ab0a08b11136ae23d4a146936b Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 03:57:07 -0500
Subject: [PATCH 027/202] Renamed unit test files to avoid conflict with
previous files
---
.../vuum/mocca/PalantirManagerUnitTest.java | 54 +++++++++++++++++
.../vuum/mocca/SimpleAtomicLongUnitTest.java | 59 +++++++++++++++++++
...Test.java => SimpleSemaphoreUnitTest.java} | 2 +-
3 files changed, 114 insertions(+), 1 deletion(-)
create mode 100644 assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
create mode 100644 assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
rename assignments/week-3-assignment-2/test/edu/vuum/mocca/{SimpleSemaphoreTest.java => SimpleSemaphoreUnitTest.java} (95%)
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
new file mode 100644
index 000000000..e6c9672ab
--- /dev/null
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
@@ -0,0 +1,54 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class PalantirManagerUnitTest {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testPalantirManager() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testAcquirePalantir() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testReleasePalantir() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testGetNextAvailablePalantir() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testMarkAsUnused() {
+ fail("Not yet implemented");
+ }
+
+}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
new file mode 100644
index 000000000..20bea50d7
--- /dev/null
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
@@ -0,0 +1,59 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SimpleAtomicLongUnitTest {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testSimpleAtomicLong() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testGet() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testDecrementAndGet() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testGetAndIncrement() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testGetAndDecrement() {
+ fail("Not yet implemented");
+ }
+
+ @Test
+ public void testIncrementAndGet() {
+ fail("Not yet implemented");
+ }
+
+}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
similarity index 95%
rename from assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreTest.java
rename to assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
index 4d0e2e7db..a4bed51dc 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
@@ -8,7 +8,7 @@
import org.junit.BeforeClass;
import org.junit.Test;
-public class SimpleSemaphoreTest {
+public class SimpleSemaphoreUnitTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
From ab3b651269732d6b67a91d065e0ce564bfa97ecd Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 13:17:22 -0500
Subject: [PATCH 028/202] Updated the Unit Tests to have a 'AllTests' suite,
and finished up the unit tests for Semaphore & the PalantirManager
---
...st.java => PalantirManagerTestDriver.java} | 2 +-
.../test/edu/vuum/mocca/AllTests.java | 12 +
.../vuum/mocca/PalantirManagerUnitTest.java | 213 +++++++++++++++---
.../vuum/mocca/SimpleAtomicLongUnitTest.java | 92 +++++---
.../vuum/mocca/SimpleSemaphoreUnitTest.java | 37 ++-
5 files changed, 284 insertions(+), 72 deletions(-)
rename assignments/week-3-assignment-2/src/edu/vuum/mocca/{PalantirManagerTest.java => PalantirManagerTestDriver.java} (99%)
create mode 100644 assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTestDriver.java
similarity index 99%
rename from assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java
rename to assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTestDriver.java
index e4eb62d75..afa6a6aaf 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTest.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTestDriver.java
@@ -15,7 +15,7 @@
* Ring's fan see http://en.wikipedia.org/wiki/Palantir for more
* information on Palantir).
*/
-class PalantirManagerTest
+class PalantirManagerTestDriver
{
/**
* Total number of times each Palantir user gets to gaze into a
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
new file mode 100644
index 000000000..f7714f785
--- /dev/null
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
@@ -0,0 +1,12 @@
+package edu.vuum.mocca;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({PalantirManagerUnitTest.class, SimpleAtomicLongUnitTest.class,
+ SimpleSemaphoreUnitTest.class})
+public class AllTests {
+
+}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
index e6c9672ab..3c881eed4 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
@@ -1,54 +1,201 @@
package edu.vuum.mocca;
-import static org.junit.Assert.*;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
public class PalantirManagerUnitTest {
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- }
+ /**
+ * Total number of times each Palantir user gets to gaze into a Palantir.
+ */
+ final static int mMaxPalantirSessions = 5;
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- }
+ static volatile long mMaxActiveThreads = 0;
- @Before
- public void setUp() throws Exception {
- }
+ static SimpleAtomicLong mActiveThreads = new SimpleAtomicLong(0);
+
+ /**
+ * Resource Manager that controls access to the available Palantiri.
+ */
+ static PalantirManager mPalantirManager = null;
+
+ /**
+ * Object that attempts to check whether the Semaphore implementation is
+ * "fair".
+ */
+ static FairnessChecker mFairnessChecker = null;
+
+ /* Runnable passed to each Thread that uses a Palantir. */
+ static Runnable usePalantir = new Runnable() {
+ /**
+ * This is the main loop run by each Being of Middle-Earth who wants to
+ * gaze into a Palantir.
+ */
+ public void run() {
+ // Bound the total number of times that each user can
+ // gaze into a Palantir.
+ for (int i = 0; i < mMaxPalantirSessions; ++i) {
+ // System.out.println(Thread.currentThread().getName()
+ // + " is acquiring the palantir");
+
+ // Used to check for Semaphore fairness.
+ mFairnessChecker.addNewThread(Thread.currentThread().getName());
+
+ // Get access to a Palantir, which will block if
+ // all the available Palantiri are in use.
+ Palantir palantir = mPalantirManager.acquirePalantir();
+
+ // There's a race condition here since it's
+ // possible for one thread to call
+ // mFairnessChecker.addNewThread() and then yield
+ // to another thread which again calls
+ // mFairnessChecker.addNewThread() and then goes
+ // on without interruption to call
+ // mPalantirManager.acquirePalantir(), which will
+ // fool the fairness checker into wrongly thinking
+ // the acquisition wasn't fair. we'll just give a
+ // warning (rather than an error) if it looks like
+ // the semaphore acquire() method isn't "fair".
+ if (!mFairnessChecker.checkOrder(Thread.currentThread()
+ .getName())) {
+ // System.out.println(Thread.currentThread().getName()
+ // + ": warning, semaphore acquire may not be fair");
+ }
+
+ // Ensure that the Semaphore implementation is
+ // correctly limiting the number of Palantir
+ // gazers.
+ long activeThreads = mActiveThreads.getAndIncrement();
+ if (mMaxActiveThreads < activeThreads) {
+ System.out.println("too many threads = " + activeThreads);
+ throw new RuntimeException();
+ }
+ // System.out.println(Thread.currentThread().getName()
+ // + " is starting to gaze at the " + palantir.name()
+ // + " palantir");
+
+ // Gaze at the Palantir for the time alloted in
+ // the command.
+ palantir.gaze();
+
+ // Indicate this Being is no longer using the
+ // Palantir.
+ mActiveThreads.decrementAndGet();
+
+ // System.out.println(Thread.currentThread().getName()
+ // + " is finished gazing at the " + palantir.name()
+ // + " palantir");
+
+ // Return the Palantir back to the shared pool so
+ // other Beings can gaze at it.
+ mPalantirManager.releasePalantir(palantir);
+
+ // System.out.println(Thread.currentThread().getName()
+ // + " is releasing the " + palantir.name() + " palantir");
+ }
- @After
- public void tearDown() throws Exception {
+ }
+ };
+
+ /**
+ * This factory creates a list of Palantiri.
+ */
+ static List makePalantiri() {
+ List palantiri = new ArrayList();
+
+ // MinasTirith Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ }
+ public String name() {
+ return "MinasTirith";
+ }
+ });
+ // Orthanc Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ Thread.sleep(150);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public String name() {
+ return "Orthanc";
+ }
+ });
+ // Barad-dur Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ // The unblinking eye gazes for a long time
+ // ;-)
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ public String name() {
+ return "Barad-dur";
+ }
+ });
+
+ return palantiri;
}
@Test
public void testPalantirManager() {
- fail("Not yet implemented");
- }
+ try {
+ // System.out.println("Starting PalantirManagerTest");
- @Test
- public void testAcquirePalantir() {
- fail("Not yet implemented");
- }
+ // Get the list of available Palantiri.
+ List palantiri = PalantirManagerTestDriver.makePalantiri();
- @Test
- public void testReleasePalantir() {
- fail("Not yet implemented");
- }
+ // Limit the number of users (threads) that can gaze into
+ // the available Palantiri.
+ mMaxActiveThreads = palantiri.size();
- @Test
- public void testGetNextAvailablePalantir() {
- fail("Not yet implemented");
- }
+ // Create a resource manager that control access to the
+ // available Palantiri.
+ mPalantirManager = new PalantirManager(palantiri);
- @Test
- public void testMarkAsUnused() {
- fail("Not yet implemented");
+ // Create a list of Middle-Earth Beings who want to use
+ // the Palantir.
+ List palantirUsers = new ArrayList();
+ palantirUsers.add(new Thread(usePalantir, "Pippen"));
+ palantirUsers.add(new Thread(usePalantir, "Aragorn"));
+ palantirUsers.add(new Thread(usePalantir, "Denathor"));
+ palantirUsers.add(new Thread(usePalantir, "Sauron"));
+ palantirUsers.add(new Thread(usePalantir, "Saruman"));
+
+ // Create an object that attempts to check whether the
+ // Semaphore implementation is "fair".
+ mFairnessChecker = new FairnessChecker(palantirUsers.size());
+
+ // Start all the Threads that Middle-Earth Beings use to
+ // gaze into the Palantir.
+ for (ListIterator iterator = palantirUsers.listIterator(); iterator
+ .hasNext();)
+ iterator.next().start();
+
+ // Barrier synchronization that waits for all the Threads
+ // to exit.
+ for (ListIterator iterator = palantirUsers.listIterator(); iterator
+ .hasNext();)
+ iterator.next().join();
+
+ // System.out.println("Finishing PalantirManagerTest");
+ } catch (Exception e) {
+ fail("An Exception was thrown.");
+ }
}
}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
index 20bea50d7..94dffd83c 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
@@ -1,59 +1,89 @@
package edu.vuum.mocca;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
public class SimpleAtomicLongUnitTest {
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- }
-
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- }
-
- @Before
- public void setUp() throws Exception {
- }
-
- @After
- public void tearDown() throws Exception {
- }
-
@Test
public void testSimpleAtomicLong() {
- fail("Not yet implemented");
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertNotNull(testLong);
}
@Test
public void testGet() {
- fail("Not yet implemented");
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.get(), 0);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.get(), 100);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.get(), -100);
}
@Test
public void testDecrementAndGet() {
- fail("Not yet implemented");
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.decrementAndGet(), -1);
+ assertEquals(testLong.get(), -1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.decrementAndGet(), 99);
+ assertEquals(testLong2.get(), 99);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.decrementAndGet(), -101);
+ assertEquals(testLong3.get(), -101);
}
@Test
- public void testGetAndIncrement() {
- fail("Not yet implemented");
+ public void testIncrementAndGet() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.incrementAndGet(), 1);
+ assertEquals(testLong.get(), 1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.incrementAndGet(), 101);
+ assertEquals(testLong2.get(), 101);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.incrementAndGet(), -99);
+ assertEquals(testLong3.get(), -99);
}
-
+
@Test
- public void testGetAndDecrement() {
- fail("Not yet implemented");
+ public void testGetAndIncrement() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.getAndIncrement(), 0);
+ assertEquals(testLong.get(), 1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.getAndIncrement(), 100);
+ assertEquals(testLong2.get(), 101);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.getAndIncrement(), -100);
+ assertEquals(testLong3.get(), -99);
}
@Test
- public void testIncrementAndGet() {
- fail("Not yet implemented");
+ public void testGetAndDecrement() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.getAndDecrement(), 0);
+ assertEquals(testLong.get(), -1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.getAndDecrement(), 100);
+ assertEquals(testLong2.get(), 99);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.getAndDecrement(), -100);
+ assertEquals(testLong3.get(), -101);
}
+
}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
index a4bed51dc..6c64a8641 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
@@ -28,22 +28,45 @@ public void tearDown() throws Exception {
@Test
public void testSimpleSemaphore() {
- fail("Not yet implemented");
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertNotNull(simpleSemaphore);
}
@Test
- public void testAcquire() {
- fail("Not yet implemented");
+ public void testAcquire() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.mAvailablePermits, 1);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.mAvailablePermits, 0);
}
@Test
- public void testAcquireUninterruptibly() {
- fail("Not yet implemented");
+ public void testAcquireUninterruptibly() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ simpleSemaphore.acquireUninterruptibly();
+ assertEquals(simpleSemaphore.mAvailablePermits, 1);
+ simpleSemaphore.acquireUninterruptibly();
+ assertEquals(simpleSemaphore.mAvailablePermits, 0);
}
@Test
- public void testRelease() {
- fail("Not yet implemented");
+ public void testRelease() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.mAvailablePermits, 1);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.mAvailablePermits, 0);
+ simpleSemaphore.release();
+ assertEquals(simpleSemaphore.mAvailablePermits, 1);
+ simpleSemaphore.release();
+ assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ // Test to see if release allows you to go 'above' resource count
+ simpleSemaphore.release();
+ assertEquals(simpleSemaphore.mAvailablePermits, 2);
}
}
From 2287e1f358aeebaace6cbbe5fde5095f17b742ae Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 14:31:51 -0500
Subject: [PATCH 029/202] Updated SemaphoreUnitTest to use availablePermits()
---
.../Assignment-Description.txt | 18 +++++++++++++----
.../vuum/mocca/SimpleSemaphoreUnitTest.java | 20 +++++++++----------
2 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index 1a9d94c75..cb6252c42 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -12,7 +12,7 @@ a Palantir (if you're not a Lord of the Ring's fan see
http://en.wikipedia.org/wiki/Palantir for more information on
Palantir).
-The PalantirManagerTest.java program creates three Palantiri and five
+The PalantirManagerTestDriver.java program creates three Palantiri and five
Threads (one for each Palantir user) that concurrently attempt to
acquire a Palantir and gaze into it for a certain amount of time. If
the SimpleSemaphore and SimpleAtomicLock are implemented properly the
@@ -20,7 +20,7 @@ test should succeed without throwing any exceptions.
In this directory you'll find a number of files, all of which you
should read. However, the only two files you need to modify are
-SimpleAtomicLong.java class and SimpleSemaphore, which contains the
+SimpleAtomicLong.java and SimpleSemaphore.java, which contains the
skeleton Java code that you'll implement by completing the "TODO - You
fill in here" comments to provide a working solution. DO NOT CHANGE
THE OVERALL STRUCTURE OF THE SKELETON - just fill in the "TODO - You
@@ -75,14 +75,24 @@ in item #38 at the POSA MOOC FAQ available from
http://www.courera.org/course/posa
To compile this code you can either use the provided Eclipse project
-or go into the src directory and simply type
+or manually compile and run the code yourself (described below)
+
+
+There are 3 Unit test files and 1 Unit test suite that will run the 3 test
+files for you at once. These are included in the test/ directory.
+
+Right click on the test suite (AllTests.java) or an individual *_UnitTest.java file in
+Eclipse and select 'Run As' -> 'JUnit Test'. When the assignment is complete, 12 of 12
+tests should complete successfully.
+
+To manually compile the code go into the src directory and simply type
% javac FairnessChecker.java Palantir.java PalantirManager.java
PalantirManagerTest.java SimpleAtomicLong.java SimpleSemaphore.java
on the command-line and then run the resulting class file by typing
-% java PalantirManagerTest
+% java PalantirManagerTestDriver
The output for a correct solution should look something this:
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
index 6c64a8641..b4c736ce7 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
@@ -1,6 +1,9 @@
package edu.vuum.mocca;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.concurrent.Semaphore;
import org.junit.After;
import org.junit.AfterClass;
@@ -54,19 +57,16 @@ public void testAcquireUninterruptibly() throws InterruptedException {
@Test
public void testRelease() throws InterruptedException {
- SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ Semaphore simpleSemaphore = new Semaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.mAvailablePermits, 1);
+ assertEquals(simpleSemaphore.availablePermits(), 1);
simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.mAvailablePermits, 0);
+ assertEquals(simpleSemaphore.availablePermits(), 0);
simpleSemaphore.release();
- assertEquals(simpleSemaphore.mAvailablePermits, 1);
- simpleSemaphore.release();
- assertEquals(simpleSemaphore.mAvailablePermits, 2);
- // Test to see if release allows you to go 'above' resource count
+ assertEquals(simpleSemaphore.availablePermits(), 1);
simpleSemaphore.release();
- assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
}
}
From 933dac1cd280bf976802b38978d09e390be14469 Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 14:32:52 -0500
Subject: [PATCH 030/202] Added AvailablePermits Test
---
.../vuum/mocca/SimpleSemaphoreUnitTest.java | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
index b4c736ce7..ab38b70a3 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
@@ -38,26 +38,26 @@ public void testSimpleSemaphore() {
@Test
public void testAcquire() throws InterruptedException {
SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.mAvailablePermits, 1);
+ assertEquals(simpleSemaphore.availablePermits(), 1);
simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.mAvailablePermits, 0);
+ assertEquals(simpleSemaphore.availablePermits(), 0);
}
@Test
public void testAcquireUninterruptibly() throws InterruptedException {
SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertEquals(simpleSemaphore.mAvailablePermits, 2);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
simpleSemaphore.acquireUninterruptibly();
- assertEquals(simpleSemaphore.mAvailablePermits, 1);
+ assertEquals(simpleSemaphore.availablePermits(), 1);
simpleSemaphore.acquireUninterruptibly();
- assertEquals(simpleSemaphore.mAvailablePermits, 0);
+ assertEquals(simpleSemaphore.availablePermits(), 0);
}
@Test
public void testRelease() throws InterruptedException {
- Semaphore simpleSemaphore = new Semaphore(2, true);
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
assertEquals(simpleSemaphore.availablePermits(), 2);
simpleSemaphore.acquire();
assertEquals(simpleSemaphore.availablePermits(), 1);
@@ -68,5 +68,13 @@ public void testRelease() throws InterruptedException {
simpleSemaphore.release();
assertEquals(simpleSemaphore.availablePermits(), 2);
}
+
+ @Test
+ public void testAvailablePermits() throws InterruptedException{
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ }
}
From d4f795b6d7653204878592d9780c9c4d13e949ac Mon Sep 17 00:00:00 2001
From: "Michael A. Walker"
Date: Thu, 22 May 2014 14:51:31 -0500
Subject: [PATCH 031/202] Added in availablePermits() method to better match
Semaphore API
---
.../src/edu/vuum/mocca/SimpleSemaphore.java | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
index e586b2da8..9bfefed73 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
@@ -44,7 +44,15 @@ public void acquireUninterruptibly() {
void release() {
// TODO - you fill in here
}
-
+
+ /**
+ * Return the number of permits available.
+ */
+ public int availablePermits(){
+ // TODO - you fill in here
+ return 0; // You will change this value.
+ }
+
/**
* Define a ReentrantLock to protect the critical section.
*/
From 2dfc9bc907a2862fc04970c75829e966d754d968 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 22 May 2014 15:26:00 -0500
Subject: [PATCH 032/202] Added JUnit tests for week-3-assignment-2.
---
.../Assignment-Description.txt | 6 +-
.../Assignment-Description.txt | 2 +-
.../Assignment-Description.txt | 174 ++------
.../vuum/mocca/PalantirManagerTestDriver.java | 213 ---------
.../test/edu/vuum/mocca/AllTests.java | 6 +-
.../edu/vuum/mocca/FairnessChecker.java | 0
.../edu/vuum/mocca/Palantir.java | 0
.../edu/vuum/mocca/PalantirManager.java | 0
.../vuum/mocca/PalantirManagerUnitTest.java | 414 ++++++++++--------
.../vuum/mocca/SimpleAtomicLongUnitTest.java | 132 +++---
.../vuum/mocca/SimpleSemaphoreUnitTest.java | 110 +++--
11 files changed, 383 insertions(+), 674 deletions(-)
delete mode 100644 assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTestDriver.java
rename assignments/week-3-assignment-2/{src => test}/edu/vuum/mocca/FairnessChecker.java (100%)
rename assignments/week-3-assignment-2/{src => test}/edu/vuum/mocca/Palantir.java (100%)
rename assignments/week-3-assignment-2/{src => test}/edu/vuum/mocca/PalantirManager.java (100%)
diff --git a/assignments/week-1-assignment-0-v2/Assignment-Description.txt b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
index 3550b2ed8..42d3583a3 100644
--- a/assignments/week-1-assignment-0-v2/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0-v2/Assignment-Description.txt
@@ -41,8 +41,8 @@ In particular, you'll need to do the following:
(which is done for you by the testQueue() template method in the
SynchronizedQueue.java file).
-. If you'd like to enable verbose debugging output please set the
- diagnosticsEnabled flag in SynchronizedQueueImpl to true (it
+. If you'd like to enable verbose debugging output please set the
+ diagnosticsEnabled flag in SynchronizedQueueImpl.java to true (it
defaults to false).
All the information needed to write this code is described in these
@@ -62,7 +62,7 @@ We'll also discuss this assignment specification (and later its
solution) in the POSA MOOC "Virtual Office Hours", which are described
in item #38 at the POSA MOOC FAQ available from
-http://www.courera.org/course/posa
+http://www.coursera.org/course/posa
The SynchronizerQueueTest.java file uses JUnit to run the tests. We
do this to automate the testing process and leverage the integration
diff --git a/assignments/week-1-assignment-0/Assignment-Description.txt b/assignments/week-1-assignment-0/Assignment-Description.txt
index ea5578535..76af1a687 100644
--- a/assignments/week-1-assignment-0/Assignment-Description.txt
+++ b/assignments/week-1-assignment-0/Assignment-Description.txt
@@ -50,7 +50,7 @@ We'll also discuss this assignment specification (and later its
solution) in the POSA MOOC "Virtual Office Hours", which are described
in item #38 at the POSA MOOC FAQ available from
-http://www.courera.org/course/posa
+http://www.coursera.org/course/posa
The SynchronizerQueueTest.java file uses JUnit to run the tests. We
do this to automate the testing process and leverage the integration
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index e760aedff..661531edd 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -16,8 +16,8 @@ Middle-Earth who can concurrently gaze into a Palantir. Please see
http://en.wikipedia.org/wiki/Palantir for more information on
Palantirs if you're not yet a fan of Tolkein's Lord of the Ring's.
-The PalantirManagerTestDriver.java program creates three Palantiri and five
-Threads (one for each Palantir user) that concurrently attempt to
+The PalantirManagerUnitTest.java program creates three Palantiri and
+five Threads (one for each Palantir user) that concurrently attempt to
acquire a Palantir and gaze into it for a certain amount of time. If
the SimpleSemaphore and SimpleAtomicLock are implemented properly the
test should succeed without throwing any exceptions, as described
@@ -63,13 +63,7 @@ In particular, you'll need to do the following:
Section 1: Module 2: Part 1: Overview of Java Threads (Part 1)
Section 1: Module 2: Part 2: Overview of Java Threads (Part 2)
-At the moment, all these videos are available in the YouTube playlist
-at
-
-https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4tbiFYip6tDNIEBRUDyPQK
-
-When the 2014 POSA MOOC officially starts these videos will be
-available at
+These videos are available at
https://class.coursera.org/posa-002/lecture
@@ -77,144 +71,38 @@ We'll also discuss this assignment specification (and later its
solution) in the POSA MOOC "Virtual Office Hours", which are described
in item #38 at the POSA MOOC FAQ available from
-http://www.courera.org/course/posa
-
-To compile this code you can either use the provided Eclipse project
-or manually compile and run the code yourself (described below)
-
-
-There are 3 Unit test files and 1 Unit test suite that will run the 3 test
-files for you at once. These are included in the test/ directory.
-
-Right click on the test suite (AllTests.java) or an individual *_UnitTest.java file in
-Eclipse and select 'Run As' -> 'JUnit Test'. When the assignment is complete, 12 of 12
-tests should complete successfully.
-
-To manually compile the code go into the src directory and simply type
-
-% javac FairnessChecker.java Palantir.java PalantirManager.java
- PalantirManagerTest.java SimpleAtomicLong.java SimpleSemaphore.java
-
-on the command-line and then run the resulting class file by typing
-
-% java PalantirManagerTestDriver
-
-The output for a correct solution should look something this:
-
-----------------------------------------
-Starting PalantirManagerTest
-Pippen is acquiring the palantir
-Pippen is starting to gaze at the MinisTirith palantir
-Aragorn is acquiring the palantir
-Aragorn is starting to gaze at the Orthanc palantir
-Denathor is acquiring the palantir
-Denathor is starting to gaze at the Barad-dur palantir
-Sauron is acquiring the palantir
-Saruman is acquiring the palantir
-Pippen is finished gazing at the MinisTirith palantir
-Pippen is releasing the MinisTirith palantir
-Pippen is acquiring the palantir
-Sauron is starting to gaze at the MinisTirith palantir
-Sauron is finished gazing at the MinisTirith palantir
-Sauron is releasing the MinisTirith palantir
-Sauron is acquiring the palantir
-Saruman is starting to gaze at the MinisTirith palantir
-Saruman is finished gazing at the MinisTirith palantir
-Pippen is starting to gaze at the MinisTirith palantir
-Saruman is releasing the MinisTirith palantir
-Saruman is acquiring the palantir
-Pippen is finished gazing at the MinisTirith palantir
-Pippen is releasing the MinisTirith palantir
-Pippen is acquiring the palantir
-Sauron is starting to gaze at the MinisTirith palantir
-Sauron is finished gazing at the MinisTirith palantir
-Sauron is releasing the MinisTirith palantir
-Sauron is acquiring the palantir
-Saruman is starting to gaze at the MinisTirith palantir
-Saruman is finished gazing at the MinisTirith palantir
-Pippen is starting to gaze at the MinisTirith palantir
-Saruman is releasing the MinisTirith palantir
-Saruman is acquiring the palantir
-Pippen is finished gazing at the MinisTirith palantir
-Pippen is releasing the MinisTirith palantir
-Pippen is acquiring the palantir
-Sauron is starting to gaze at the MinisTirith palantir
-Sauron is finished gazing at the MinisTirith palantir
-Sauron is releasing the MinisTirith palantir
-Sauron is acquiring the palantir
-Saruman is starting to gaze at the MinisTirith palantir
-Saruman is finished gazing at the MinisTirith palantir
-Pippen is starting to gaze at the MinisTirith palantir
-Saruman is releasing the MinisTirith palantir
-Saruman is acquiring the palantir
-Denathor is finished gazing at the Barad-dur palantir
-Denathor is releasing the Barad-dur palantir
-Denathor is acquiring the palantir
-Sauron is starting to gaze at the Barad-dur palantir
-Pippen is finished gazing at the MinisTirith palantir
-Pippen is releasing the MinisTirith palantir
-Pippen is acquiring the palantir
-Saruman is starting to gaze at the MinisTirith palantir
-Saruman is finished gazing at the MinisTirith palantir
-Denathor is starting to gaze at the MinisTirith palantir
-Saruman is releasing the MinisTirith palantir
-Saruman is acquiring the palantir
-Denathor is finished gazing at the MinisTirith palantir
-Denathor is releasing the MinisTirith palantir
-Denathor is acquiring the palantir
-Pippen is starting to gaze at the MinisTirith palantir
-Pippen is finished gazing at the MinisTirith palantir
-Pippen is releasing the MinisTirith palantir
-Saruman is starting to gaze at the MinisTirith palantir
-Saruman is finished gazing at the MinisTirith palantir
-Denathor is starting to gaze at the MinisTirith palantir
-Saruman is releasing the MinisTirith palantir
-Aragorn is finished gazing at the Orthanc palantir
-Aragorn is releasing the Orthanc palantir
-Aragorn is acquiring the palantir
-Aragorn is starting to gaze at the Orthanc palantir
-Denathor is finished gazing at the MinisTirith palantir
-Denathor is releasing the MinisTirith palantir
-Denathor is acquiring the palantir
-Denathor is starting to gaze at the MinisTirith palantir
-Denathor is finished gazing at the MinisTirith palantir
-Denathor is releasing the MinisTirith palantir
-Denathor is acquiring the palantir
-Denathor is starting to gaze at the MinisTirith palantir
-Denathor is finished gazing at the MinisTirith palantir
-Denathor is releasing the MinisTirith palantir
-Sauron is finished gazing at the Barad-dur palantir
-Sauron is releasing the Barad-dur palantir
-Sauron is acquiring the palantir
-Sauron is starting to gaze at the MinisTirith palantir
-Sauron is finished gazing at the MinisTirith palantir
-Sauron is releasing the MinisTirith palantir
-Aragorn is finished gazing at the Orthanc palantir
-Aragorn is releasing the Orthanc palantir
-Aragorn is acquiring the palantir
-Aragorn is starting to gaze at the MinisTirith palantir
-Aragorn is finished gazing at the MinisTirith palantir
-Aragorn is releasing the MinisTirith palantir
-Aragorn is acquiring the palantir
-Aragorn is starting to gaze at the MinisTirith palantir
-Aragorn is finished gazing at the MinisTirith palantir
-Aragorn is releasing the MinisTirith palantir
-Aragorn is acquiring the palantir
-Aragorn is starting to gaze at the MinisTirith palantir
-Aragorn is finished gazing at the MinisTirith palantir
-Aragorn is releasing the MinisTirith palantir
-Finishing PalantirManagerTest
-----------------------------------------
-
-Don't worry if your output occurs in a different order - that's to be
-expected in multi-threaded programs and OS/JVM platforms. Also, don't
-worry about "warnings" since there's an intentional race condition in
-the test since it's possible for one thread to call
+http://www.coursera.org/course/posa
+
+To compile this code you need to use the provided Eclipse project.
+There is a Unit Test Suite that will run all three Unit test files
+included in the test/ directory for you at once. When you first open
+the project in Eclipse, you might see compile errors if JUnit is not
+included in your build path. To fix these errors, open
+SynchronizedQueueTest.java, hover over "org.junit," and click "Fix
+project setup." Make sure "Add JUnit 4 library to the build path" is
+selected and then click "OK." At this point, the compile errors
+should disappear!
+
+Right click on the test suite (AllTests.java) or an individual
+*_UnitTest.java file in Eclipse and select 'Run As' -> 'JUnit
+Test'. When the assignment is complete, 12 of 12 tests should complete
+successfully. If a test passes a green-check mark will appear next to
+the test in the JUnit view. As long as this JUnit test "passes"
+successfully your program will be be consider "correct" for the
+purposes of assessing this assignment.
+
+If you'd like to enable verbose debugging output please set the
+diagnosticsEnabled flag in PlanantirManagerUnitTest.java to true (it
+defaults to false). However, this will generate a lot of output and
+you'll need to look at it carefully to understand what it's doing. If
+you do this, don't worry about "warnings" since there's an intentional
+race condition in the test since it's possible for one thread to call
mFairnessChecker.addNewThread() and then yield to another thread which
again calls mFairnessChecker.addNewThread() and then goes on without
interruption to call mPalantirManager.acquirePalantir(), which will
fool the fairness checker into wrongly thinking the acquisition wasn't
fair. We therefore just give a warning (rather than an error) if it
looks like the semaphore acquire() method isn't "fair". The key is
-not to have runtime exceptions in your output!
+not to have runtime exceptions, i.e., you want only "green-check
+marks" in the JUnit view output!
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTestDriver.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTestDriver.java
deleted file mode 100644
index afa6a6aaf..000000000
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManagerTestDriver.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package edu.vuum.mocca;
-
-import java.util.List;
-import java.util.ListIterator;
-import java.util.ArrayList;
-
-/**
- * @class PalantirManagerTest
- *
- * @brief This program tests student implementations of
- * SimpleSimpleAtomicLong and SimpleSemaphore, which are used
- * to correctly implement a resource manager that
- * limits the number of Beings from Middle-Earth who
- * can concurrently gaze into a Palantir (if you're not a Lord of the
- * Ring's fan see http://en.wikipedia.org/wiki/Palantir for more
- * information on Palantir).
- */
-class PalantirManagerTestDriver
-{
- /**
- * Total number of times each Palantir user gets to gaze into a
- * Palantir.
- */
- final static int mMaxPalantirSessions = 5;
-
- static volatile long mMaxActiveThreads = 0;
-
- static SimpleAtomicLong mActiveThreads = new SimpleAtomicLong(0);
-
- /**
- * Resource Manager that controls access to the available
- * Palantiri.
- */
- static PalantirManager mPalantirManager = null;
-
- /**
- * Object that attempts to check whether the Semaphore
- * implementation is "fair".
- */
- static FairnessChecker mFairnessChecker = null;
-
- /* Runnable passed to each Thread that uses a Palantir. */
- static Runnable usePalantir = new Runnable() {
- /**
- * This is the main loop run by each Being of Middle-Earth
- * who wants to gaze into a Palantir.
- */
- public void run() {
- // Bound the total number of times that each user can
- // gaze into a Palantir.
- for (int i = 0; i < mMaxPalantirSessions; ++i) {
- System.out.println(Thread.currentThread().getName()
- + " is acquiring the palantir");
-
- // Used to check for Semaphore fairness.
- mFairnessChecker.addNewThread(Thread.currentThread().getName());
-
- // Get access to a Palantir, which will block if
- // all the available Palantiri are in use.
- Palantir palantir = mPalantirManager.acquirePalantir();
-
- // There's a race condition here since it's
- // possible for one thread to call
- // mFairnessChecker.addNewThread() and then yield
- // to another thread which again calls
- // mFairnessChecker.addNewThread() and then goes
- // on without interruption to call
- // mPalantirManager.acquirePalantir(), which will
- // fool the fairness checker into wrongly thinking
- // the acquisition wasn't fair. we'll just give a
- // warning (rather than an error) if it looks like
- // the semaphore acquire() method isn't "fair".
- if (!mFairnessChecker.checkOrder(Thread.currentThread().getName()))
- System.out.println(Thread.currentThread().getName()
- + ": warning, semaphore acquire may not be fair");
-
- // Ensure that the Semaphore implementation is
- // correctly limiting the number of Palantir
- // gazers.
- long activeThreads = mActiveThreads.getAndIncrement();
- if (mMaxActiveThreads < activeThreads)
- {
- System.out.println("too many threads = "
- + activeThreads);
- throw new RuntimeException();
- }
- System.out.println(Thread.currentThread().getName()
- + " is starting to gaze at the "
- + palantir.name()
- + " palantir");
-
- // Gaze at the Palantir for the time alloted in
- // the command.
- palantir.gaze();
-
- // Indicate this Being is no longer using the
- // Palantir.
- mActiveThreads.decrementAndGet();
-
- System.out.println(Thread.currentThread().getName()
- + " is finished gazing at the "
- + palantir.name()
- + " palantir");
-
- // Return the Palantir back to the shared pool so
- // other Beings can gaze at it.
- mPalantirManager.releasePalantir(palantir);
-
- System.out.println(Thread.currentThread().getName()
- + " is releasing the "
- + palantir.name() +
- " palantir");
- }
-
- }
- };
-
- /**
- * This factory creates a list of Palantiri.
- */
- static List makePalantiri() {
- List palantiri = new ArrayList();
-
- // MinasTirith Palantir
- palantiri.add (new Palantir() {
- public void gaze() {
- try {
- Thread.sleep(10);
- }
- catch (InterruptedException e) {}
- }
- public String name() {return "MinasTirith";}
- });
- // Orthanc Palantir
- palantiri.add (new Palantir() {
- public void gaze() {
- try {
- Thread.sleep(150);
- }
- catch (InterruptedException e) {}
- }
-
- public String name() {return "Orthanc";}
- });
- // Barad-dur Palantir
- palantiri.add (new Palantir() {
- public void gaze()
- {
- try {
- // The unblinking eye gazes for a long time
- // ;-)
- Thread.sleep(100);
- }
- catch (InterruptedException e) {}
- }
- public String name() {return "Barad-dur";}
- });
-
- return palantiri;
- }
- /**
- * Main entry point method that runs the test.
- */
- public static void main(String[] args) {
- try {
- System.out.println("Starting PalantirManagerTest");
-
- // Get the list of available Palantiri.
- List palantiri = makePalantiri();
-
- // Limit the number of users (threads) that can gaze into
- // the available Palantiri.
- mMaxActiveThreads = palantiri.size();
-
- // Create a resource manager that control access to the
- // available Palantiri.
- mPalantirManager = new PalantirManager(palantiri);
-
- // Create a list of Middle-Earth Beings who want to use
- // the Palantir.
- List palantirUsers = new ArrayList();
- palantirUsers.add(new Thread(usePalantir, "Pippen"));
- palantirUsers.add(new Thread(usePalantir, "Aragorn"));
- palantirUsers.add(new Thread(usePalantir, "Denathor"));
- palantirUsers.add(new Thread(usePalantir, "Sauron"));
- palantirUsers.add(new Thread(usePalantir, "Saruman"));
-
- // Create an object that attempts to check whether the
- // Semaphore implementation is "fair".
- mFairnessChecker = new FairnessChecker(palantirUsers.size());
-
- // Start all the Threads that Middle-Earth Beings use to
- // gaze into the Palantir.
- for (ListIterator iterator = palantirUsers.listIterator();
- iterator.hasNext();
- )
- iterator.next().start();
-
- // Barrier synchronization that waits for all the Threads
- // to exit.
- for (ListIterator iterator = palantirUsers.listIterator();
- iterator.hasNext();
- )
- iterator.next().join();
-
- System.out.println("Finishing PalantirManagerTest");
- }
- catch (Exception e) {
- System.out.println("Something went wrong");
- }
- }
-
-}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
index f7714f785..325a23f41 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
@@ -5,8 +5,8 @@
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
-@SuiteClasses({PalantirManagerUnitTest.class, SimpleAtomicLongUnitTest.class,
- SimpleSemaphoreUnitTest.class})
+@SuiteClasses({PalantirManagerUnitTest.class,
+ SimpleAtomicLongUnitTest.class,
+ SimpleSemaphoreUnitTest.class})
public class AllTests {
-
}
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/edu/vuum/mocca/FairnessChecker.java
rename to assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/Palantir.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/edu/vuum/mocca/Palantir.java
rename to assignments/week-3-assignment-2/test/edu/vuum/mocca/Palantir.java
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
similarity index 100%
rename from assignments/week-3-assignment-2/src/edu/vuum/mocca/PalantirManager.java
rename to assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
index 3c881eed4..3a43eac3e 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
@@ -8,194 +8,236 @@
import org.junit.Test;
-public class PalantirManagerUnitTest {
- /**
- * Total number of times each Palantir user gets to gaze into a Palantir.
- */
- final static int mMaxPalantirSessions = 5;
-
- static volatile long mMaxActiveThreads = 0;
-
- static SimpleAtomicLong mActiveThreads = new SimpleAtomicLong(0);
-
- /**
- * Resource Manager that controls access to the available Palantiri.
- */
- static PalantirManager mPalantirManager = null;
-
- /**
- * Object that attempts to check whether the Semaphore implementation is
- * "fair".
- */
- static FairnessChecker mFairnessChecker = null;
-
- /* Runnable passed to each Thread that uses a Palantir. */
- static Runnable usePalantir = new Runnable() {
- /**
- * This is the main loop run by each Being of Middle-Earth who wants to
- * gaze into a Palantir.
- */
- public void run() {
- // Bound the total number of times that each user can
- // gaze into a Palantir.
- for (int i = 0; i < mMaxPalantirSessions; ++i) {
- // System.out.println(Thread.currentThread().getName()
- // + " is acquiring the palantir");
-
- // Used to check for Semaphore fairness.
- mFairnessChecker.addNewThread(Thread.currentThread().getName());
-
- // Get access to a Palantir, which will block if
- // all the available Palantiri are in use.
- Palantir palantir = mPalantirManager.acquirePalantir();
-
- // There's a race condition here since it's
- // possible for one thread to call
- // mFairnessChecker.addNewThread() and then yield
- // to another thread which again calls
- // mFairnessChecker.addNewThread() and then goes
- // on without interruption to call
- // mPalantirManager.acquirePalantir(), which will
- // fool the fairness checker into wrongly thinking
- // the acquisition wasn't fair. we'll just give a
- // warning (rather than an error) if it looks like
- // the semaphore acquire() method isn't "fair".
- if (!mFairnessChecker.checkOrder(Thread.currentThread()
- .getName())) {
- // System.out.println(Thread.currentThread().getName()
- // + ": warning, semaphore acquire may not be fair");
- }
-
- // Ensure that the Semaphore implementation is
- // correctly limiting the number of Palantir
- // gazers.
- long activeThreads = mActiveThreads.getAndIncrement();
- if (mMaxActiveThreads < activeThreads) {
- System.out.println("too many threads = " + activeThreads);
- throw new RuntimeException();
- }
- // System.out.println(Thread.currentThread().getName()
- // + " is starting to gaze at the " + palantir.name()
- // + " palantir");
-
- // Gaze at the Palantir for the time alloted in
- // the command.
- palantir.gaze();
-
- // Indicate this Being is no longer using the
- // Palantir.
- mActiveThreads.decrementAndGet();
-
- // System.out.println(Thread.currentThread().getName()
- // + " is finished gazing at the " + palantir.name()
- // + " palantir");
-
- // Return the Palantir back to the shared pool so
- // other Beings can gaze at it.
- mPalantirManager.releasePalantir(palantir);
-
- // System.out.println(Thread.currentThread().getName()
- // + " is releasing the " + palantir.name() + " palantir");
- }
-
- }
+/**
+ * @class PalantirManagerUnitTest
+ *
+ * @brief This program tests that student implementations of
+ * SimpleAtomicLong and SimpleSemaphore correctly implement a
+ * resource manager that limits the number of Beings from
+ * Middle-Earth who can concurrently gaze into a Palantir (see
+ * http://en.wikipedia.org/wiki/Palantir for more information
+ * on Palantirs if you're not a Lord of the Ring's fan yet
+ * ;-)).
+ */
+public class PalantirManagerUnitTest {
+ /**
+ * If this is set to true in SynchronizedQueueImpl.java then lots
+ * of debugging output will be generated.
+ */
+ public static boolean diagnosticsEnabled = false;
+
+ /**
+ * Total number of times each Palantir user gets to gaze into a
+ * Palantir.
+ */
+ final static int mMaxPalantirSessions = 5;
+
+ /**
+ * Total number of active Threads.
+ */
+ static volatile long mMaxActiveThreads = 0;
+
+ /**
+ * Count of the number of Active Threads.
+ */
+ static SimpleAtomicLong mActiveThreads = new SimpleAtomicLong(0);
+
+ /**
+ * Resource Manager that controls access to the available
+ * Palantiri.
+ */
+ static PalantirManager mPalantirManager = null;
+
+ /**
+ * Object that attempts to check whether the Semaphore
+ * implementation is "fair".
+ */
+ static FairnessChecker mFairnessChecker = null;
+
+ /**
+ * Runnable passed to each Thread that uses a Palantir.
+ */
+ static Runnable usePalantir = new Runnable() {
+ /**
+ * This is the main loop run by each Being of Middle-Earth
+ * who wants to gaze into a Palantir.
+ */
+ public void run() {
+ // Bound the total number of times that each user can
+ // gaze into a Palantir.
+ for (int i = 0; i < mMaxPalantirSessions; ++i) {
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is acquiring the palantir");
+
+ // Used to check for Semaphore fairness.
+ mFairnessChecker.addNewThread(Thread.currentThread().getName());
+
+ // Get access to a Palantir, which will block if
+ // all the available Palantiri are in use.
+ Palantir palantir = mPalantirManager.acquirePalantir();
+
+ // There's a race condition here since it's
+ // possible for one thread to call
+ // mFairnessChecker.addNewThread() and then yield
+ // to another thread which again calls
+ // mFairnessChecker.addNewThread() and then goes
+ // on without interruption to call
+ // mPalantirManager.acquirePalantir(), which will
+ // fool the fairness checker into wrongly thinking
+ // the acquisition wasn't fair. we'll just give a
+ // warning (rather than an error) if it looks like
+ // the semaphore acquire() method isn't "fair".
+ if (!mFairnessChecker.checkOrder(Thread.currentThread()
+ .getName())) {
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + ": warning, semaphore acquire may not be fair");
+ }
+
+ // Ensure that the Semaphore implementation is
+ // correctly limiting the number of Palantir
+ // gazers.
+ long activeThreads = mActiveThreads.getAndIncrement();
+ if (mMaxActiveThreads < activeThreads) {
+ System.out.println("too many threads = "
+ + activeThreads);
+ throw new RuntimeException();
+ }
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is starting to gaze at the "
+ + palantir.name()
+ + " palantir");
+
+ // Gaze at the Palantir for the time alloted in
+ // the command.
+ palantir.gaze();
+
+ // Indicate this Being is no longer using the
+ // Palantir.
+ mActiveThreads.decrementAndGet();
+
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is finished gazing at the "
+ + palantir.name()
+ + " palantir");
+
+ // Return the Palantir back to the shared pool so
+ // other Beings can gaze at it.
+ mPalantirManager.releasePalantir(palantir);
+
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is releasing the "
+ + palantir.name()
+ + " palantir");
+ }
+
+ }
};
- /**
- * This factory creates a list of Palantiri.
- */
- static List makePalantiri() {
- List palantiri = new ArrayList();
-
- // MinasTirith Palantir
- palantiri.add(new Palantir() {
- public void gaze() {
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- }
- }
- public String name() {
- return "MinasTirith";
- }
- });
- // Orthanc Palantir
- palantiri.add(new Palantir() {
- public void gaze() {
- try {
- Thread.sleep(150);
- } catch (InterruptedException e) {
- }
- }
-
- public String name() {
- return "Orthanc";
- }
- });
- // Barad-dur Palantir
- palantiri.add(new Palantir() {
- public void gaze() {
- try {
- // The unblinking eye gazes for a long time
- // ;-)
- Thread.sleep(100);
- } catch (InterruptedException e) {
- }
- }
- public String name() {
- return "Barad-dur";
- }
- });
-
- return palantiri;
- }
-
- @Test
- public void testPalantirManager() {
- try {
- // System.out.println("Starting PalantirManagerTest");
-
- // Get the list of available Palantiri.
- List palantiri = PalantirManagerTestDriver.makePalantiri();
-
- // Limit the number of users (threads) that can gaze into
- // the available Palantiri.
- mMaxActiveThreads = palantiri.size();
-
- // Create a resource manager that control access to the
- // available Palantiri.
- mPalantirManager = new PalantirManager(palantiri);
-
- // Create a list of Middle-Earth Beings who want to use
- // the Palantir.
- List palantirUsers = new ArrayList();
- palantirUsers.add(new Thread(usePalantir, "Pippen"));
- palantirUsers.add(new Thread(usePalantir, "Aragorn"));
- palantirUsers.add(new Thread(usePalantir, "Denathor"));
- palantirUsers.add(new Thread(usePalantir, "Sauron"));
- palantirUsers.add(new Thread(usePalantir, "Saruman"));
-
- // Create an object that attempts to check whether the
- // Semaphore implementation is "fair".
- mFairnessChecker = new FairnessChecker(palantirUsers.size());
-
- // Start all the Threads that Middle-Earth Beings use to
- // gaze into the Palantir.
- for (ListIterator iterator = palantirUsers.listIterator(); iterator
- .hasNext();)
- iterator.next().start();
-
- // Barrier synchronization that waits for all the Threads
- // to exit.
- for (ListIterator iterator = palantirUsers.listIterator(); iterator
- .hasNext();)
- iterator.next().join();
-
- // System.out.println("Finishing PalantirManagerTest");
- } catch (Exception e) {
- fail("An Exception was thrown.");
- }
- }
+ /**
+ * This factory creates a list of Palantiri.
+ */
+ static List makePalantiri() {
+ List palantiri = new ArrayList();
+
+ // MinasTirith Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ }
+ public String name() {
+ return "MinasTirith";
+ }
+ });
+ // Orthanc Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ Thread.sleep(150);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public String name() {
+ return "Orthanc";
+ }
+ });
+ // Barad-dur Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ // The unblinking eye gazes for a long time
+ // ;-)
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ public String name() {
+ return "Barad-dur";
+ }
+ });
+
+ return palantiri;
+ }
+
+ @Test
+ public void testPalantirManager() {
+ try {
+ if (diagnosticsEnabled)
+ System.out.println("Starting PalantirManagerTest");
+
+ // Get the list of available Palantiri.
+ List palantiri =
+ PalantirManagerUnitTest.makePalantiri();
+
+ // Limit the number of users (threads) that can gaze into
+ // the available Palantiri.
+ mMaxActiveThreads = palantiri.size();
+
+ // Create a resource manager that control access to the
+ // available Palantiri.
+ mPalantirManager = new PalantirManager(palantiri);
+
+ // Create a list of Middle-Earth Beings who want to use
+ // the Palantir.
+ List palantirUsers = new ArrayList();
+ palantirUsers.add(new Thread(usePalantir, "Pippen"));
+ palantirUsers.add(new Thread(usePalantir, "Aragorn"));
+ palantirUsers.add(new Thread(usePalantir, "Denathor"));
+ palantirUsers.add(new Thread(usePalantir, "Sauron"));
+ palantirUsers.add(new Thread(usePalantir, "Saruman"));
+
+ // Create an object that attempts to check whether the
+ // Semaphore implementation is "fair".
+ mFairnessChecker = new FairnessChecker(palantirUsers.size());
+
+ // Start all the Threads that Middle-Earth Beings use to
+ // gaze into the Palantir.
+ for (ListIterator iterator = palantirUsers.listIterator();
+ iterator.hasNext();)
+ iterator.next().start();
+
+ // Barrier synchronization that waits for all the Threads
+ // to exit.
+ for (ListIterator iterator = palantirUsers.listIterator(); iterator
+ .hasNext();)
+ iterator.next().join();
+
+ if (diagnosticsEnabled)
+ System.out.println("Finishing PalantirManagerTest");
+ } catch (Exception e) {
+ fail("The Exception "
+ + e.getMessage()
+ + " was thrown");
+ }
+ }
}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
index 94dffd83c..66d01c104 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
@@ -5,85 +5,89 @@
import org.junit.Test;
+/**
+ * @class SimpleAtomicLongUnitTest
+ *
+ * @brief Simple unit test for the SimpleAtomicLong clas that ensures
+ * the version submitted for this assignment works properly.
+ */
public class SimpleAtomicLongUnitTest {
+ @Test
+ public void testSimpleAtomicLong() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertNotNull(testLong);
+ }
- @Test
- public void testSimpleAtomicLong() {
- SimpleAtomicLong testLong = new SimpleAtomicLong(0);
- assertNotNull(testLong);
- }
-
- @Test
- public void testGet() {
- SimpleAtomicLong testLong = new SimpleAtomicLong(0);
- assertEquals(testLong.get(), 0);
+ @Test
+ public void testGet() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.get(), 0);
- SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
- assertEquals(testLong2.get(), 100);
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.get(), 100);
- SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
- assertEquals(testLong3.get(), -100);
- }
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.get(), -100);
+ }
- @Test
- public void testDecrementAndGet() {
- SimpleAtomicLong testLong = new SimpleAtomicLong(0);
- assertEquals(testLong.decrementAndGet(), -1);
- assertEquals(testLong.get(), -1);
+ @Test
+ public void testDecrementAndGet() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.decrementAndGet(), -1);
+ assertEquals(testLong.get(), -1);
- SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
- assertEquals(testLong2.decrementAndGet(), 99);
- assertEquals(testLong2.get(), 99);
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.decrementAndGet(), 99);
+ assertEquals(testLong2.get(), 99);
- SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
- assertEquals(testLong3.decrementAndGet(), -101);
- assertEquals(testLong3.get(), -101);
- }
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.decrementAndGet(), -101);
+ assertEquals(testLong3.get(), -101);
+ }
- @Test
- public void testIncrementAndGet() {
- SimpleAtomicLong testLong = new SimpleAtomicLong(0);
- assertEquals(testLong.incrementAndGet(), 1);
- assertEquals(testLong.get(), 1);
+ @Test
+ public void testIncrementAndGet() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.incrementAndGet(), 1);
+ assertEquals(testLong.get(), 1);
- SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
- assertEquals(testLong2.incrementAndGet(), 101);
- assertEquals(testLong2.get(), 101);
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.incrementAndGet(), 101);
+ assertEquals(testLong2.get(), 101);
- SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
- assertEquals(testLong3.incrementAndGet(), -99);
- assertEquals(testLong3.get(), -99);
- }
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.incrementAndGet(), -99);
+ assertEquals(testLong3.get(), -99);
+ }
- @Test
- public void testGetAndIncrement() {
- SimpleAtomicLong testLong = new SimpleAtomicLong(0);
- assertEquals(testLong.getAndIncrement(), 0);
- assertEquals(testLong.get(), 1);
+ @Test
+ public void testGetAndIncrement() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.getAndIncrement(), 0);
+ assertEquals(testLong.get(), 1);
- SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
- assertEquals(testLong2.getAndIncrement(), 100);
- assertEquals(testLong2.get(), 101);
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.getAndIncrement(), 100);
+ assertEquals(testLong2.get(), 101);
- SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
- assertEquals(testLong3.getAndIncrement(), -100);
- assertEquals(testLong3.get(), -99);
- }
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.getAndIncrement(), -100);
+ assertEquals(testLong3.get(), -99);
+ }
- @Test
- public void testGetAndDecrement() {
- SimpleAtomicLong testLong = new SimpleAtomicLong(0);
- assertEquals(testLong.getAndDecrement(), 0);
- assertEquals(testLong.get(), -1);
+ @Test
+ public void testGetAndDecrement() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.getAndDecrement(), 0);
+ assertEquals(testLong.get(), -1);
- SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
- assertEquals(testLong2.getAndDecrement(), 100);
- assertEquals(testLong2.get(), 99);
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.getAndDecrement(), 100);
+ assertEquals(testLong2.get(), 99);
- SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
- assertEquals(testLong3.getAndDecrement(), -100);
- assertEquals(testLong3.get(), -101);
- }
-
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.getAndDecrement(), -100);
+ assertEquals(testLong3.get(), -101);
+ }
}
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
index ab38b70a3..8cdd59390 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
@@ -11,70 +11,58 @@
import org.junit.BeforeClass;
import org.junit.Test;
+/**
+ * @class SimpleSemaphoreUnitTest
+ *
+ * @brief Simple unit test for the SimpleSemaphore that just tests
+ * single-threaded logic.
+ */
public class SimpleSemaphoreUnitTest {
+ @Test
+ public void testSimpleSemaphore() {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertNotNull(simpleSemaphore);
+ }
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- }
+ @Test
+ public void testAcquire() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 0);
+ }
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- }
+ @Test
+ public void testAcquireUninterruptibly() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquireUninterruptibly();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.acquireUninterruptibly();
+ assertEquals(simpleSemaphore.availablePermits(), 0);
+ }
- @Before
- public void setUp() throws Exception {
- }
-
- @After
- public void tearDown() throws Exception {
- }
-
- @Test
- public void testSimpleSemaphore() {
- SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertNotNull(simpleSemaphore);
- }
-
- @Test
- public void testAcquire() throws InterruptedException {
- SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertEquals(simpleSemaphore.availablePermits(), 2);
- simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.availablePermits(), 1);
- simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.availablePermits(), 0);
- }
-
- @Test
- public void testAcquireUninterruptibly() throws InterruptedException {
- SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertEquals(simpleSemaphore.availablePermits(), 2);
- simpleSemaphore.acquireUninterruptibly();
- assertEquals(simpleSemaphore.availablePermits(), 1);
- simpleSemaphore.acquireUninterruptibly();
- assertEquals(simpleSemaphore.availablePermits(), 0);
- }
-
- @Test
- public void testRelease() throws InterruptedException {
- SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertEquals(simpleSemaphore.availablePermits(), 2);
- simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.availablePermits(), 1);
- simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.availablePermits(), 0);
- simpleSemaphore.release();
- assertEquals(simpleSemaphore.availablePermits(), 1);
- simpleSemaphore.release();
- assertEquals(simpleSemaphore.availablePermits(), 2);
- }
+ @Test
+ public void testRelease() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 0);
+ simpleSemaphore.release();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.release();
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ }
- @Test
- public void testAvailablePermits() throws InterruptedException{
- SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
- assertEquals(simpleSemaphore.availablePermits(), 2);
- simpleSemaphore.acquire();
- assertEquals(simpleSemaphore.availablePermits(), 1);
- }
-
+ @Test
+ public void testAvailablePermits() throws InterruptedException{
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ }
}
From f5fe5680c76ead45166ae908867683c2e194fcec Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 22 May 2014 19:48:02 -0500
Subject: [PATCH 033/202] Added the POSA MOOC FAQ here.
---
POSA-FAQ.html | 1304 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1304 insertions(+)
create mode 100644 POSA-FAQ.html
diff --git a/POSA-FAQ.html b/POSA-FAQ.html
new file mode 100644
index 000000000..1a183c55e
--- /dev/null
+++ b/POSA-FAQ.html
@@ -0,0 +1,1304 @@
+
+
+ - What are the course objectives?
+
+
Upon completing this course, students should be able to:
+
+ Recognize the inherent and accidental
+ complexities involved with developing concurrent software that
+ communicates securely between processes and
+ threads.
+ Understand how pattern-oriented software
+ architecture and framework techniques can and cannot help to
+ alleviate these complexities.
+ Apply patterns and
+ frameworks to develop reusable and resilient concurrent
+ applications and services using the Java object-oriented
+ programming language and Android middleware.
+ Know
+ where to find additional sources of information on how to
+ program mobile applications and services on Android handheld
+ systems.
+
+
+
+ How does this MOOC compare/contrast with courses at
+ Vanderbilt?
+
+ This MOOC is heavily based on senior-level
+ undergraduate courses we teach at Vanderbilt, such as the
+ course Systems Programming for Android (CS
+ 282). CS 282 focuses on teaching mobile software
+ development at both a conceptual level (e.g., an understanding
+ of software patterns, object-oriented design, and frameworks)
+ and a practical level (e.g., experience programming Android
+ services and applications using Java and Eclipse). Students in
+ this course are expected to be familiar with Java and Eclipse
+ and are capable of learning new material without significant
+ hand-holding by the teachers and course staff. The lecture
+ material in CS 282 is similar to the material for this MOOC
+ (in fact, you can watch earlier versions of this material that
+ I presented live in CS 282 via this a YouTube
+ channel). The quizzes, programming assignments, and level
+ of feedback for the Vanderbilt courses are different, however,
+ since the courses at Vanderbilt have many fewer students, so
+ there's significantly more personalized guidance from the
+ professor and TAs that can't (yet) be replicated via a
+ MOOC.
+
+
+ What are your assumptions about--and expectations
+ for--students taking this MOOC?
+
+ As mentioned above, this MOOC is based on material we teach to
+ senior-level undergraduate students at Vanderbilt. The lecture
+ material is therefore intended for self-motivated students who
+ already know Java and Eclipse (or can learn them quickly on
+ their own) and who want to understand both the concepts and
+ practice of mobile software development. Moreover, this material
+ is targeted at students who want to know (1) how to program
+ mobile software applications and services and (2) how the
+ Android software stack is designed and implemented. Therefore,
+ students who are looking for vocational training (e.g., having
+ an instructor provide solutions directly or simply walk through
+ application code projects step-by-step in the Android
+ development environment) may not find this MOOC suitable for
+ their needs since our goal is to help students learn how to find
+ a solution, not simply provide a solution. Moveover, this MOOC
+ covers a wide range of topics (especially patterns and
+ frameworks) associated with quality mobile software
+ development. For students who just want training we recommend
+ others sources, such as
+ the Android
+ Application Development Tutorials on
+ YouTube.
+
+
+ What is the most effective way to learn material covered
+ in the course and to successfully complete the programming
+ assignments?
+
+ We recommend watching the videos multiple times, looking for
+ different levels of meaning in the diagrams and the
+ examples. It's particularly important to carefully watch all the
+ videos referenced in the programming assignment descriptions
+ since they provide many relevant tips and insights. Likewise, we
+ recommend reading the material pointed to by links in the
+ slides, as well as material from the (optional) recommended
+ reading. Naturally, participating in the online discussion forum
+ (and ideally, a meetup group if one is available in your area)
+ will help make the course material more engaging and
+ personalized. Additional discussions of the programming
+ assignment goals, requirements, and (ultimately) their solutions
+ will be covered in "Virtual Office Hours" (see the FAQ entry on
+ this topic below).
+
+
+ Can students take this course if they have no prior
+ experience programming Android and/or Java in Eclipse?
+
+ Our course assumes that students are comfortable programming
+ in Java and have some experience programming Android apps in
+ Eclipse. If you don't have any Java programming background you
+ might consider taking the course Java for Complete
+ Beginners. Likewise, you might also benefit from the Creative,
+ Serious and Playful Science of Android Apps MOOC, which is
+ a novice-friendly introduction to computer science and
+ programming Android-apps for smart-phones and tablets. No
+ prior programming knowledge is necessary for that MOOC. We
+ also recommend that you take Professor Adam Porter's MOOC Programming
+ Mobile Applications for Android Handheld Systems since his
+ course provides important coverage of Android app programming
+ that will be useful in our course. We encourage you to apply
+ the Lazy
+ Acquisition pattern in these MOOCs, i.e., watch the
+ videos, keep track of what you know understand, and then use
+ the resources available to you (e.g., via the web and the
+ discussion forums) to fill in the gaps in your knowledge. One
+ of the best things about MOOCs is that you can go through this
+ material at your own pace, and there's really no penalty for
+ retaking a MOOC if you struggle with it the first time
+ through!
+
+
+
+ Why are there so many URL links embedded at the bottom of
+ the slides?
+
+ Many of the topics (especially concurrency,
+ inter-process communication, and application security) we
+ cover in this MOOC are very technically deep. Given our
+ limited time and resource constraints, we can't possibly
+ address all this material in a single MOOC. Yet many students
+ may benefit from learning more about these topics, either
+ during or after the MOOC. Therefore, when there's additional
+ pertinent information on a topic that we can't cover in our
+ videos, we provide links in the PDF versions of the slides
+ that students can download from the Video
+ Lectures page or from the 2014 POSA MOOC wiki
+ maintained by students. These links point to material on the
+ web so that students can read as their interests and time
+ permits. Following up on all the links is a rewarding, albeit
+ time consuming task. In fact, we term these videos "Lembas
+ Lectures" since a small dose of them can keep a student
+ nourished (intellectually) for hours! However, none of the
+ quizzes will involve questions related to this material, so
+ students can read them at their leisure. The videos in Section
+ 0 are largely introductory, so feel free to watch them at an
+ accelerated rate of speed if you're willing to read all this
+ FAQ instead.
+
+
+ What is the course staff policy for moderating and
+ answering discussion forum threads and questions?
+
+ The course staff will endeavor to reply to thoughtful
+ technical questions or constructive suggestions for improving
+ the course. Often, the responses will point to other resources
+ (such as this FAQ or to video lectures) so that students can
+ learn the details of the solutions on their own, which is more
+ effective pedagogically. Rants and flames (such as "Android
+ sucks," "Language X is better than Java," "Patterns are bad,"
+ or "I hate these lectures") will be ignored and/or removed
+ since they generate much more heat than light and disrupt the
+ learning process. Questions posted anonymously will also
+ receive less attention since we want to get to know the
+ students in the MOOC so the learning environment will be more
+ like a face-to-face course. Due to extremely limited course
+ staffing resources, questions about installing or using
+ Eclipse, the Android emulator, debugger, etc. will be
+ addressed by the community of other students taking this
+ MOOC. Step-by-step instructions on how to setup an Android
+ development environment using Eclipse and Java are
+ available here.
+
+
+
+ How many and what types of programming assignments will
+ there be in this MOOC?
+
+ We'll have a half-dozen or so
+ programming assignments in this MOOC. The first several
+ assignments will give students experience applying and
+ developing concurrency mechanisms (e.g., implement a simple
+ AtomicLong and a simple Semaphore using Java
+ ReentrantReadWriteLock, ReentrantLock, and
+ ConditionObject classes using the Java
+ console environment). The next several assignments will
+ involve applying and developing frameworks and
+ applications that use these frameworks (e.g., a multi-threaded
+ ping/pong Android application that will apply various GoF
+ patterns to develop a framework that will make it easy to port
+ the application between Android and console configurations in
+ Eclipse). The final assignment will be an integrated project
+ that will give students experience applying pattern-oriented
+ concurrency mechanisms & Android concurrency frameworks
+ (e.g., AsyncTask and Handles, Runnables, and Messages) to the
+ iRemember application that was introduced in
+ Professor Porter's MOOC on Programming Mobile
+ Applications for Android Handheld Systems. All the source
+ code examples and skeletons for the programming
+ assignments will be available in this GitHub
+ repository once the Coursera POSA MOOC officially
+ starts.
+
+
+
+ How can students understand and learn the material in the
+ videos most effectively?
+
+ There is no one rate of speaking that's appropriate for all
+ students. For students whose native language is not
+ English--or for any students who find the rate at which the
+ material is presented in the videos too fast to comprehend--we
+ recommend that you decrease the rate at which you play the
+ videos to 0.8x or slower (naturally, for material that you're
+ already familiar with, you might want to increase the rate at
+ which the video plays!). If you need instructions on how to
+ change the rate of playback speed for YouTube videos please do
+ a google search for information about the browser that you're
+ using. Once the POSA MOOC officially starts you'll also be
+ able to download the videos and use the media player on your
+ computer to obtain fine-grained control over the playback
+ speed. The Coursera platform also provides English subtitles
+ for all the videos based on the scripts we used to record them
+ originally. Likewise, you can enable "captions" via the
+ YouTube player to view subtitles at my YouTube
+ playlist. In addition, downloading PDF versions of the
+ slides and reviewing them prior to watching the videos may aid
+ with comprehension. Finally, students might also consider
+ watching the videos multiple times, focusing on different
+ aspects of the material each time (e.g., listening to the
+ voice track, looking at the code and diagrams on the slides,
+ etc.). If you have time, you might also want to read the
+ material referenced by the links provided at the bottom of
+ many slides, which are listed on the 2014 POSA MOOC wiki
+ maintained by students.
+
+
+
+ Will there be a Statement of Accomplishment for students
+ who complete this class?
+
+ Yes. Students who successfully complete the quizzes and
+ assignments in this class prior to the completion of the
+ MOOC will receive a Statement of Accomplishment signed by
+ the instructor. There will be two levels of Statements of
+ Accomplishment: Normal Track and Distinction Track. The
+ difference between the work performed in each of these tracks
+ is covered at the Coursera website here. You
+ needn't be in the Signature Track to get a Statement of
+ Accomplishment with Distinction, though you do need to be in
+ the Signature Track if you want to be eligible to take the
+ Capstone project course, as described in the next FAQ entry
+ below.
+
+
+
+ Who is eligible to take the Capstone project course?
+
+ Like all Coursera Specializations, the Capstone project
+ course is only available to students who take the Signature
+ Track for the preceding three MOOCs in the
+ Specialization. Moreover, for this first offering of the
+ Mobile Cloud Computing with Android (MoCCA) Specialization
+ only students in the Signature Track who receive a "Verified
+ Certificate with Distinction" in all preceding MOOCs are
+ eligible to enroll in the Capstone project course. We may
+ remove this restriction in future offerings of the MoCCA
+ Specialization, after we have a better understanding of what's
+ required to successfully complete the Capstone project
+ course. Even if you didn't attain a Verified Certificate with
+ Distinction in Professor Porter's 1st MOOC in the
+ Specialization, you are still welcome to attempt a Verified
+ Certificate with Distinction in the 2nd and 3rd MOOCs in the
+ Specialization. If you succeed in attaining the Verified
+ Certificates with Distintion in these two MOOC all you'll need
+ to do is take Professor Porter's 1st MOOC when it's offered
+ next, at which point you'll be eligible to take the next
+ offering of the Capstone project course (i.e., not the one
+ that's starts in October 2014, but the next one after that)
+ once you'll successfully attain a Verified Certificate with
+ Distinction in all three MOOCs.
+
+
+
+ What is a "trans-institutional MOOC Specialization"?
+
+ This MOOC and two other MOOCs (Programming Mobile
+ Applications for Android Handheld Systems taught by Professor Adam
+ Porter from the University of Maryland and Programming Cloud
+ Services for Android Handheld Systems taught by Jules
+ White from Vanderbilt University) have been designed to
+ complement each other as part of the Coursera Specialization
+ on Mobile
+ Cloud Computing with Android. In particular, the
+ programming assignments and the course project for all the
+ courses will be coordinated. Additional information on our
+ trans-institutional MOOC Specialization is available here.
+
+
+
+ Is it necessary to take Prof. Adam Porter MOOC prior to
+ the POSA MOOC or can students take the POSA MOOC without
+ taking his course?
+
+ It's not required to have taken Prof. Porter's MOOC on Programming
+ Mobile Applications for Android Handheld Systems. If you
+ just want to take some of the courses in this sequence--or
+ take them all in different order--you're certainly welcome to
+ do so, and you'll still learn a lot. You do need to be
+ familiar with the core Java and Android topics he covered in
+ his MOOC or you'll be lost (see FAQ item #5 about for
+ suggestions on what you'll need to know and how to learn
+ it). However, you needn't have done the integrative iRemember
+ application in his MOOC since the POSA MOOC will provide a
+ skeleton implementation of the iRemember project that focuses
+ on different aspects of the application (e.g., concurrency and
+ security features of Android), which won't require knowledge
+ of what was done in Prof. Porter's MOOC (which focuses on
+ user-facing features of Android). Naturally, if you take all
+ the courses in this sequence in the order presented you'll
+ gain a deeper, end-to-end understanding of handheld systems,
+ their applications and services, as well as their integration
+ into the cloud.
+
+
+
+ When will the course material be made available each
+ week?
+
+ All the course material (e.g., video lectures, quizzes,
+ programming assignments, etc.), for each week will be made
+ available three days early (i.e., by Fridays) by 9am eastern
+ time (2pm UTC/GMT) so that students can watch and read the
+ material over the weekend prior to the beginning of the next
+ week.
+
+
+
+
+ Is there a required textbook?
+
+ There is no required textbook, per se. There's lots of
+ information available in the videos, slides, and the URLs
+ mentioned in the slides that will help you learn the material
+ we cover in this class. For deeper mastery of the material,
+ however, please see the list of "recommended reading" on the
+ POSA course
+ webpage for a list of books that are closely related to
+ the topics of the course.
+
+
+
+ Where can students learn about how to configure their
+ Android and Java environment to run the examples and complete
+ the programming assignments?
+
+ The POSA MOOC will use the same Eclipse-based Android
+ development environment as Dr. Porter's earlier MOOC in this
+ Specialization on Programming
+ Mobile Applications for Android Handheld Systems,
+ Step-by-step instructions on how to setup an Android
+ development environment using Eclipse and Java are available
+ here.
+ If you're using a non-Eclipse development environment (such as
+ Intellij
+ IDEA or Android
+ Studio) or want to use a different build tool (such as Maven)
+ you'll need to enlist the help of other students on the online
+ discussion forum and/or the POSA MOOC Wiki. Mavenized
+ versions of all the programming assignments are available here.
+
+
+
+ Where can students learn more about patterns and
+ frameworks?
+
+ Many videos about patterns and frameworks appeared in Section
+ 2 and the Appendix of the Spring
+ 2013 offering of the POSA MOOC. You can find links to all
+ these videos here,
+ though you may need to register first at this
+ link. If you're a Safari online book club member you
+ should check out the Design
+ Patterns in Java video training series that covers the
+ "Gang-of-Four" patterns.
+
+
+
+ Which web browsers are recommended
+
+ Coursera recommends using the Chrome and Firefox
+ browsers. There's also a mobile
+ app for Coursera MOOC, as well.
+
+
+
+ Can students use programming language [X] for the
+ course?
+
+ The programming assignments in the Android portion of this
+ course are designed for the Java programming language. The
+ cloud computing portion may provide more flexibility, but it
+ will also focus largely on Java, as well. Although you're
+ welcome to use other languages on Android for your personal
+ edification, if you stray from Java you'll have more work to
+ do to map what we're covering in the videos and projects to
+ the languages you want to use. You may also find it hard to
+ get feedback on your work via the Coursera peer-grading
+ system .
+
+
+
+ Where can students download the slides and source code
+ that are presented in the videos and the skeletons that are
+ provided for the programming assignments?
+
+ PDF versions of the slides will be available for download
+ after the videos are released onto the Coursera POSA MOOC
+ website each week. These versions of the slides will have
+ clickable links to make it easy to navigate to the
+ supplemental material referenced in the slides. All the
+ source code examples and skeletons for the programming
+ assignments will be available in this GitHub
+ repository once the Coursera POSA MOOC officially
+ starts. Step-by-step instructions for using GitHub are
+ available here
+ and a video explaining the basics of Git and GitHub is
+ available here.
+
+
+
+ How will the 2014 version of the POSA MOOC differ from the
+ 2013 version?
+
+ Alhough the 2014 POSA MOOC will cover many of the same
+ patterns (plus new ones), it will be radically different than
+ the 2013 version in almost every other respect. The 2014 POSA
+ MOOC won't cover some of the more "abstract" topics we
+ discussed in the 2013 POSA MOOC. For example, we won't have
+ (new) videos on pattern relationships (e.g., pattern
+ sequences, pattern languages, etc.), general discussions of
+ frameworks, design dimensions of concurrency and networking,
+ overview of middleware stacks, etc., since (1) that's outside
+ the scope of Android and (2) we already have those videos
+ available in the 2013 POSA
+ archives, so you can rewatch the older videos for more
+ information on the themes of object-oriented software
+ patterns, frameworks, and design dimensions. the 2014 POSA
+ MOOC will cover many POSA2 and GoF patterns addressed in
+ Section 3 of the 2013 POSA MOOC, though they'll be presented
+ in the context of Java and Android instead of C++ and
+ ACE.
+
+
+
+ Where is the material from the 2013 POSA MOOC available
+ online?
+
+ All the video lectures, assignments, quizzes, and discussion
+ forum postings from the 2013 offering of the POSA MOOC is
+ available here,
+ though you may need to register first at this
+ link. A summary of the 2013 POSA MOOC is also available here.
+
+
+
+ Why does this MOOC's name start with "Pattern-Oriented
+ Software Architecture?
+
+ All MOOCs Douglas
+ C. Schmidt teaches on Coursera have a focus on pattern-oriented
+ software architecture. The details of what sorts of
+ patterns--and what applications of patterns we'll
+ cover--differ from MOOC-to-MOOC, but the patterns focus is
+ consistent - hence the common prefix for the names.
+
+
+
+ What is the schedule for the course?
+
+ This MOOC, like all Coursera MOOCs, uses pre-recorded videos
+ for all the lecture material. As a result, there's no set time
+ when the class occurs, e.g., you can watch the videos at a
+ time and a pace that is most convenient for you. There will be
+ periodic programming assignments that will have a deadline,
+ which will be clearly marked on the POSA MOOC
+ website in the course
+ calendar by clicking on the calendar icon next to the
+ "Upcoming Deadlines" label. This calendar is automatically
+ updated as the material is released. Each week for the first
+ eight weeks (starting with Week 1) a programming assignment
+ will be released on Monday (see the POSA MOOC GitHub
+ repository for the assignments). It will be due exactly
+ two weeks from when it is released. Likewise, there will be
+ weekly quizzes, released by the middle of each week, though
+ their due dates will all be the last day of class so you can
+ take them as time permits (naturally, there won't be any "late
+ dates" for quizzes since they are due the last day of
+ class). Finally, we'll have periodic "virtual office hours,"
+ where I'll answer questions from students and lead impromptu
+ discussions with students live via Google Hangout and
+ YouTube. All these virtual office hours will also be recorded
+ and uploaded to the Coursera website so you can watch them at
+ your convenience.
+
+
+
+ What are the plans for
+ offering the MoCCA Specialization again in the future?
+
+ We are planning to re-offer the MoCCA Specialization starting
+ with Prof. Porter's MOOC on Programming
+ Mobile Applications for Android Handheld Systems in the
+ Fall of 2014. As soon as these plans are finalized we'll post
+ an announcement with the start date and schedule. For those
+ students who haven't yet achieved a Verified Certificate with
+ Distinction in Prof. Porter's MOOC, this will be your next
+ chance to become eligible for the next Capstone project course
+ (see FAQ item #11)
+
+
+
+ How long will the course material be available online
+ after the MOOC ends?
+
+ We plan to keep the videos, presentations, discussion forum
+ postings and responses, etc. available indefinitely.
+
+
+
+ Where is the source code that corresponds to the pathnames
+ embedded in the slides shown in the videos?
+
+ All the Android source code referenced by the pathnames in
+ the slides shown in the videos is available from here (likewise, just the
+ relevant parts of the Android 4.0 code that we'll be using are
+ available from https://class.coursera.org/posa-002/wiki/Source_Code_By_Week). If
+ you download this source code to your computer the pathnames
+ will be relative to the top-level source directory and
+ typically start with the bionic, dalvik, frameworks, libcore,
+ or packages pathname prefixes. The source code shown for more
+ examples is based on Android 4.0, which is the so-called "Ice
+ Cream Sandwich" release. The code we examine, however, should
+ be largely the same in later versions of Android, as well.
+
+
+
+ Will there be much flexibility in the schedule of deadlines
+ for programming assignments in the POSA MOOC?
+
+ It will be hard to add flexibility into the schedule since
+ this causes chaos with the peer grading system and greatly
+ increases the load on the course staff. The "course staff" is
+ very small (just Doug Schmidt and Jules White), so we're
+ unlikely to have enough spare time to keep track of flexible
+ deadlines. Students who unable to do all the assignments in
+ the allotted time frame should consider "auditing" the POSA
+ MOOC for this offering and then take it again if/when it's
+ offered again in the future. Please see item #25 in the FAQ at
+ http://www.coursera.org/course/posa
+ for more thoughts on if/when these MOOCs may be offered again.
+
+
+
+ How closely aligned will the
+ programming assignments be between MOOCs in the MoCCA
+ Specialization?
+
+ The final project for each MOOC in the
+ MoCCA Specialization will involve adding capabilities to the
+ iRemember app. The instructors for all the MOOCs are working
+ together to ensure the iRemember project is properly aligned,
+ though it won't be necessary to have completed the previous
+ iRemember project(s) in a given MOOC. Moreover, the other
+ programming assignments in their MOOCs will reflect the focus
+ of their respective MOOCs since (1) the topics are largely
+ different in each MOOC and (2) there's no requirement that
+ students must take the MOOCs in a particular sequence, so
+ inter-MOOC dependencies will be minimized.
+
+
+
+ How will the programming assignments be submitted and
+ assessed?
+
+ Each week for the first eight weeks (starting with Week 1) a
+ programming assignment will be released on Monday (assignments
+ will only be available from GitHub). It
+ will be due exactly two weeks from when it is released. Since
+ we don't have the time or staffing resources to create
+ entirely auto-graded programming assignments, we'll use the
+ following hybrid assessment method for most of the
+ assignments:
+
+
+
+ Auto-assessments, which will be performed via automated
+ JUnit regression tests supplied with each programming
+ assignment. Students can run these regression tests locally on
+ their computers to ensure their solutions work correctly prior
+ to submitting them.
+
+ Peer assessment, which will
+ involve having five other students in the MOOC compile/run the
+ automated JUnit regression tests on the submitted solutions to
+ ensure that the solution actually produces the expected
+ output.
+
+
+ The final project will involve adding
+ capabilities to the iRemember app started in Dr. Porter's
+ MOOC; it will likely be entirely peer-graded unless we get
+ volunteers to develop suitable JUnit regression tests for it.
+ As the assignments are released (and prior to their due date)
+ we'll use the Coursera Peer
+ Assessment mechanism to do the actual submissions.
+ Previews of the programming assignments are available at this
+ GitHub
+ repository, though there may be some changes to the
+ assignments and skeleton code before they are officially
+ released through the Peer Assignment page each week.
+
+
+
+ Will the links in the MOOC lecture videos be made clickable
+ and/or consolidated into a single convenient location?
+
+ Students in the POSA MOOC are crowd-sourcing the links from
+ all the lecture slides and adding them to the POSA
+ wiki, so please contribute to this effort. All the lecture
+ slides will be available in PDF form after the videos have
+ been uploaded to the Coursera POSA MOOC
+ website each week, so you can also access the links that
+ way. Note that the "Introduction" videos have no associated
+ PDF files.
+
+
+
+ Where are good sources of tutorials and
+ examples for Java and Android concurrency
+ mechanisms?
+
+ Concurrency is not an easy topic to master, so students
+ should leverage multiple sources of learning. Nearly every
+ video in Section 1 (and beyond) has code fragments straight
+ out of Android, all of which is available from source.android.com or just the
+ relevant parts of the Android 4.0 code we use are available
+ from here. The
+ Java code from the java.util.concurrent
+ package in libcore/luni/src/main/java/java/util/concurrent is
+ an excellent way to see how Java concurrency mechanisms
+ covered in the POSA MOOC videos are developed and used in
+ practice. We've developed complete example programs for the
+ MOOC that are available here. There's
+ also example code in the assignments available here,
+ though you'll need to fill in the "TODO" comments to get them
+ to work. In addition, useful tutorials on Java concurrency
+ mechanisms appear here
+ and here. Finally,
+ consider reading the books listed in the "Suggested Readings"
+ Section of the POSA MOOC
+ page.
+
+
+
+ How can students help improve the
+ form and content of the video lectures?
+
+ Please leave your constructive comments and suggestions for
+ improving the content of the video lectures in the discussion
+ forum entitled Suggestions
+ for Improving the Video Lectures. The most useful
+ suggestions are ones that help us improve the technical
+ accuracy and quality of the material, rather than just
+ commenting on the presentation format and style. Although
+ there may not be time to address these comments for this
+ offering of the POSA MOOC, we'll consider them for future
+ offerings. In addition, these suggestions will help to improve
+ the LiveLessons versions of these lectures that will be
+ created during the summer of 2014. Please see this
+ link for more information about the LiveLessons series,
+ including the first set of videos on Design
+ Patterns with Java. Also, if you spot any typos or
+ problems with subtitles for the videos please note them here
+ so we can fix them.
+
+
+
+ How can students keep
+ informed about important due dates for assignments?
+
+ Once the 2014 POSA MOOC has officially begun (in mid-May),
+ there will be a calendar of events listing the due dates,
+ etc. Likewise, reminders will be posted periodically to the
+ Announcements page (and thus disseminated via email to all
+ enrolled students). Ultimately, however, students are
+ responsible for keeping track of the deadlines and procedures
+ related to properly submitting the MOOC assignments. Given
+ the large number of students enrolled in the MOOC, there will
+ be little/no support for individual extensions or special
+ handling of late or improperly submitted solutions to the
+ assignments.
+
+
+
+ How many hours per week will be required for the POSA
+ MOOC?
+
+ There's no 100% accurate way to estimate how long any given
+ student will require to watch the videos and complete the
+ quizzes and assignments each week since each person has
+ different background, aptitude, motivation, learning style,
+ etc. Moreover, some students are doing the "normal track" and
+ others are doing the "distinction track". With that caveat in
+ mind, please see this
+ link for rough estimates of how much time may be
+ required, depending on which track a student is
+ doing. Concurrency is not an easy topic to master, however, so
+ if doing the material assigned for the "distinction track"
+ consumes an excessive amount of time please consider switching
+ to the "normal track",l which requires much less work since
+ there are no programming assignments.
+
+
+
+ What are some consequences of the "massiveness" of a MOOC?
+
+ The massive number of students in the POSA MOOC (50,000+)
+ impacts some aspects of the course that differentiate it from
+ a traditional face-to-face courses, such as the courses the
+ instructors teach at Vanderbilt and the University of
+ Maryland. In particular:
+
+
+
+ The POSA MOOC course staff will not be able to provide
+ individual feedback on student assignments, though we will
+ present our solutions to the assignments in the weekly
+ "virtual office hours" (see this
+ paper for more information on virtual office hours). If
+ you run into problems feel free to post your buggy code to the
+ appropriate assignment
+ discussion forum so that other students can provide you
+ tips on fixing your bugs. Please don't post working solutions
+ to the discussion forum, however, since that violates the
+ Coursera Code of Conduct.
+
+ Some things will inevitably go awry, e.g., peer graders
+ will undoubtedly not follow the rubric correctly, unit tests
+ will need to change, students will forget to add their source
+ code when they submit their solutions, important deadlines
+ will be missed due to unforeseen circumstances, assignments
+ will be modified after they are released, etc.
Due
+ to the massive number of students--coupled with the very
+ limited course staff--it's unfortunately sometimes the case
+ that the instructors won't be able to "make it right" in a
+ manner that makes everyone happy. In these situations, our
+ goal is to maximize the opportunity for as many students as
+ possible to gain access to a world-class education. Other
+ considerations (such as consistency, fairness, and
+ accountability) are also relevant, but our first priority is
+ to help empower students with an education that will improve
+ their lives.
+
+
+
+ How do the CS 282 videos relate to the 2014 POSA MOOC
+ videos?
+
+ The ~20 hours videos from the Vanderbilt course CS 282:
+ Systems Programming with Android available on the YouTube
+ playlist at http://www.youtube.com/watch?v=lHbIwoevePE&list=PLZ9NgFYEMxp50tvT8806xllaCbd31DpDy
+ overlap with some of the concurrency-related material
+ presented in the 2014 POSA MOOC. However, these YouTube videos
+ are not a substitute for the 2014 POSA MOOC videos, which will
+ be aligned with the programming assignments and topics covered
+ in the MOOC (and which are also much higher quality and more
+ technically accurate). The CS 282 videos are still a valuable
+ resource to supplement the MOOC videos since they cover some
+ topics, such as the Android Development Environment,
+ Activities, certain local Inter-Process Communication (IPC)
+ mechanisms, etc., that don't appear in the 2014 POSA
+ MOOC.
+
+
+
+ What are "Virtual Office Hours"?
+
+ "Virtual Office Hours" provide an opportunity for instructors
+ to interact in real-time with students once a week on
+ questions about material covered in the video lectures,
+ quizzes, and programming assignments. Google Hangout on the
+ Air and YouTube (see the Virtual
+ Office Hours videos from the 2013 POSA MOOC) are used as
+ the means to engage with students. Google Handout
+ automatically records the office hour discussions, which are
+ then uploaded to the POSA MOOC website so students can view
+ them offline if they can't make it to the live
+ events. Likewise, any questions post to the discussion forum
+ on Virtual
+ Office Hours will be answered during the session.
+
+
+
+ How much of the Android software stack is covered by the
+ MoCCA Specialization?
+
+ The MOOCs that comprise the MoCCA
+ Specialization cover a wide range of Android and Cloud
+ Computing middleware and application topics, as summarized in
+ this
+ overview video. However, this Specialization does not
+ (yet) cover the full
+ stack of Android and Cloud Computing software. In
+ particular, the Android Linux kernel, user-level device
+ drivers, native development kit, Dalvik virtual machine, and
+ C/C++-based library and service layers are not covered.in
+ detail. Likewise, certain Android middleware topics (such as
+ local inter-process communication mechanisms, network
+ programming, Bound and Unbound Services, and Content
+ Providers) are only touched upon briefly. Future offering of
+ the MoCCA Specialization will (hopefully) provide more
+ coverage of these topics, as time and resources permit.
+
+
+
+ What's the best way to watch the videos to avoid being
+ distracted by the presenter's style and/or call-outs to
+ embedded URLs?
+
+ The particular style for the video lectures was choose to (1)
+ mimic the experience of a face-to-face lecture class and (2)
+ minimize the amount of time spent post-producing the
+ videos. The frequent call-outs to embedded URLs is motivated
+ by the reasons outlined in FAQ item #6 above and to simplify
+ the post-production process (for which we have very limited
+ resources). However, some students find this style distracting
+ during the videos. The easiest way to resolve the presenter
+ distraction is to simply move the media player window so that
+ only the slides are visible. Ultimately, better solution will
+ materialize in the LiveLessons version of this material that
+ we'll create during the summer of 2014, which will be
+ professionally edited by Pearson, so if you're a Safari online
+ book club member you'll be able to watch this material without
+ distractions. More information (and examples of the
+ presentation format) are available at the Design
+ Patterns with Java website..
+
+
+
+ Can students use public source code repositories to store
+ their solutions to the programming assignments?
+
+ Please do not use public source code repositories (e.g., the
+ freely available GitHub accounts) to store your solutions to
+ the programming assignments. Publically available repositories
+ encourage students to copy each others work, which is a
+ violation fo the Coursera code of conduct that does not allow
+ students to share work unless explicitly instructed by course
+ policies.
+
+
+
+ What are some good techniques,
+ tools, and methods for visualizing, analyzing, and debugging
+ concurrent Java programs.
+
+ Debugging concurrent programs is hard due to a variety of
+ accidental and inherent complexities discussed in the Section
+ 1: Module 1 of the video
+ lectures. There are many resources available to help
+ students debug their concurrent programs, some of which are
+ free, some of which aren't, and some are a mixture of free and
+ non-free.The Thread
+ Scheduling Visualizer (TSV) is a set of tools that provide
+ an easy way to record and visualize thread scheduling. The Fluid
+ project provides a set of Eclipse tools for programmers to
+ analyze, assure, and evolve multi-threaded Java programs. Some
+ tips on debugging multi-threaded program are available here.
+
+
+
+ Where is the source code for examples and assignment
+ solutions from the Vanderbilt?
+
+ CS
+ 282: Systems Programming for Android and CS
+ 251: Intermediate Software Design
+ courses?
The source
+ code for the Java variant of the CS 251 "expression tree
+ processing application" is available as part of the
+ supplemental material for the Pearson LiveLessons courses on
+ Design
+ Patterns with Java. The ThreadedDownloads application
+ example from Section 1: Module 3 is available in GitHub
+ as part of the 2014 POSA MOOC. Other assignment solutions are
+ not available since they form part of the work expected from
+ Vanderbilt students who take these courses.
+
+
+
+ How much of a focus on patterns and frameworks will there
+ be in this MOOC?
+
+ Patterns and framework provide the foundation for much of the
+ material in this course. There is a short introduction to
+ patterns and frameworks in Section 0 and several modules in
+ Section 1 will focus on POSA and GoF patterns and frameworks
+ applied in Android. Many other videos and other resources
+ related to patterns and frameworks are also available here.
+
+
+
+ How can we convince our colleagues and management of the
+ value of patterns and frameworks in practice?
+
+ As with most issues associated with IT, there's no single
+ "silver bullet" that will convince managers and executives of
+ the "return on investment" (ROI) value of software techniques,
+ tools, and methods (TTMs). Instead, what's required is a
+ long-term commitment (at both the individual and
+ organizational levels) to invest in TTMs that provide tangible
+ payoffs wrt things that matter to managers/executives and
+ (arguably more importantly) to customers/sponsors). The
+ pattern-oriented and framework-oriented TTMs presented through
+ this MOOC are a step in the right direction -- after all,
+ these TTMs underlie much of Android and Java, which would not
+ be as powerful and pervasive without these TTMs. Ultimately,
+ each individual and organization needs to devise a strategy
+ for demonstrating the tangible benefits of patterns and
+ frameworks to the powers-that-be in terms of ROI that they
+ value, such as reducing software defect rates, enhancing
+ productivity across the lifecycle (rather than just "hacking
+ it up and shipping it out"), and increasing the resilience
+ (e.g., to failures and cyber-attacks).
+
+
+
+ Why do the assignments start with 0, but the weeks start
+ with 1?
+
+ The assignments use Java/C/C++ range semantics, whereas the
+ weeks use calendar range semantics. If this distinction
+ doesn't make sense, you may be a recovering Pascal or Ada
+ programmer ;-)
+
+
+
+ Why are there lecture
+ videos on YouTube and on the POSA Coursera website?
+
+ The videos on YouTube and the videos on the Coursera site
+ should be identical, but all videos must be approved by
+ Vanderbilt before they can be uploaded and published on the
+ POSA Coursera website. We therefore release them first on
+ YouTube as we complete them so that interested students can
+ preview them and provide feedback so that any mistakes can be
+ fixed before they are released to the POSA Coursera website.
+
+
+
+ How can we fix the warning "There are no JREs installed in
+ the workspace that are strictly compatible with this
+ environment"?
+
+ First, check what version of JRE you have installed or you
+ have set as an environment variable JAVA_HOME or JAVA_JRE. If
+ you find out that you have installed java version 7 then you
+ right click on the project folder in Eclipse. Then
+ Properties->Java Build Path -> Libraries. You click on
+ JRE System Library and then the button Edit where you select
+ Execution Environment similar to the one you have installed on
+ your PC. Although you are welcome to use whatever version of
+ Java you'd like for your programming assignments, you need to
+ make sure that whatever you submit to be graded works with
+ Java version 6 since otherwise your solution may not work and
+ the grader will deduct many points.
+
+
+
+ The introductory assignments are too easy - are there other
+ programs we can write to get experience with more advanced
+ Android concurrency and communication mechansisms?
+
+ If you get bored with these introductory assignments and want
+ to try writing more interesting programs, please see the CS
+ 282 programming assignments available here. We'll
+ cover some of these topics later in the MOOC, but you're
+ welcome to check this stuff out now.
+
+
+
+ Since many of the assignments have been posted to GitHub
+ can we work on them prior to their official release?
+
+ You're welcome to work ahead on these assignments, which is
+ one of the reasons why we've put manhy of them out early.
+ However, some things are likely to change based on a number of
+ factors, such as feedback from students, improved JUnit tests,
+ bug fixes, etc. Although it's unlikely you'll need to do a
+ wholesale rewrite of your solution (mostly the JUnit tests
+ should get more thorough) until the assignment is officially
+ posted via the "Programming Assignments and Assessments" tab
+ you'll need to be prepare for some changes.
+
+
+
+ Where is more information available on Android
+ internals?
+
+ It's worthwhile watching videos on Android's anatomy
+ and physiology and Dalvik
+ Virtual Machine. Although these are from 2008 they provide
+ a good overview of how Android works internally.
+
+
+
+ How can I prepare in advance for the upcoming
+ Programming Cloud Services for Android Handheld Systems
+ course?
+
+ The course will cover a number of topics on HTTP
+ communication in Android and HTTP-based cloud services with
+ the Java Spring Framework. Before you start preparing for the
+ cloud course, ensure that you understand the concurrency
+ material from the POSA course, particularly AsyncTasks and
+ Handlers. Some helpful resources to get a jumpstart on the
+ cloud course are:
+
+
+
+
+ What resources can be used for the weekly quizzes?
+
+ You are welcome to use videos or presentation material when
+ answering the weekly quiz questions.
+
+
+
+ Why are there two versions of week-1-assignment-0?
+
+ The official version is the one at https://github.com/douglascraigschmidt/POSA-14/tree/master/assignments/week-1-assignment-0
+ is the "official" version that will be used for peer
+ assessments. The one at https://github.com/douglascraigschmidt/POSA-14/tree/master/assignments/week-1-assignment-0-v2
+ provides better diagnostics and has a cleaner design that uses
+ the Template Method pattern to decouple the test
+ infrastructure from the student-supplied code. However, it's
+ not the official version that will be peer graded and is
+ provided solely as a way for students to understand better how
+ concurrency and Java Threads work.
+
+
+
+ Can I take Programming Cloud Services for Android Handheld
+ Systems without taking Programming Mobile Services for Android
+ Handheld Systems?
+
+ It is possible to take the cloud course without the mobile
+ services course. However, the cloud course uses the
+ concurrency concepts that are introduced in the mobile
+ services course. If you take both courses, you will have a
+ much stronger understanding of the material and be far less
+ likely to have trouble in the cloud course. We highly
+ encourage students to take both courses.
+
+
+
+ Which videos have in-video quizzes?
+
+ All "non-introductory" videos have in-video quizzes, which
+ pop up periodically (typically prior to the "Summary"
+ segments) and ask students questions about what they've been
+ watching. All of Section 0 and the intros to each Section or
+ Module are considered "introductory" videos. In-quiz videos
+ only appear if you stream the videos from the Coursera server,
+ but don't appear if you download the videos to your local
+ computer first.
+
+
+
+ What are some examples of Android applications and services
+ developed using the concurrency and communication mechanisms
+ covered in this MOOC?
+
+ Watch the videos that are available at https://class.coursera.org/posa-002/lecture
+ as well as the previews of forthcoming videos that are
+ available at https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4tbiFYip6tDNIEBRUDyPQK
+ for many example concurrent applications and services from the
+ Android source code itself, as well as sample applications we
+ developed for this MOOC. Moreover, if you download the Android
+ source code from http://source.android.com and
+ look in the packages/apps/ directory you'll see dozens more
+ Android applications, most of which use the concurrency and
+ communication frameworks and mechanisms discussed in this
+ MOOC.
+
+
+
+ What is the difference between the "assignments" and the
+ "grading-drivers" directories on GitHub?
+
+ The "assignments" directory on GitHub (at https://github.com/douglascraigschmidt/POSA-14/tree/master/assignments)
+ contains the skeletons that are used by students who complete
+ the skeletons and submit their solutions for peer
+ assessment. The "grading-drivers" directory on GitHub (at https://github.com/douglascraigschmidt/POSA-14/tree/master/grading-drivers)
+ is used by peer assessors to evaluate the submissions. This
+ separation enables us to improve the JUnit tests used for
+ evaluating submissions without changing the skeletons used by
+ students to write their solutions.
+
+
+
+ What can we do if the audio is out of sync with the video
+ stream when viewed from the course website on Coursera?
+
+ You might try playing the videos at a lower resolution if
+ your browser supports this or downloading the to your computer
+ and watching them locally. Apparently, the videos on my YouTube
+ playlist are synchronized better, so you might try watching
+ them (they are identical to what's on the Coursera website). If
+ all else fails, consider applying the suggestions in FAQ item
+ #40 above.
+
+
+
+ What is an "Optional Lecture"?
+
+ Certain lectures are not directly related to the topics of
+ concurrency, communication, and security, but provide
+ additional information that may be useful to readers who want
+ to know more about topics like frameworks, patterns, and
+ software product lines. These lectures are marked optional,
+ which means that they don't "quizzified" and questions
+ pertaining to them won't appear on a weekly quiz. Feel free
+ to watch them if you're interested and skip them if you're
+ not.
+
+
+
+
From 10a635c9bcef902e23285c3322b2447823eba625 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Thu, 22 May 2014 21:21:20 -0500
Subject: [PATCH 034/202] Removed the FAQ since it doesn't belong here.
---
POSA-FAQ.html | 1304 -------------------------------------------------
1 file changed, 1304 deletions(-)
delete mode 100644 POSA-FAQ.html
diff --git a/POSA-FAQ.html b/POSA-FAQ.html
deleted file mode 100644
index 1a183c55e..000000000
--- a/POSA-FAQ.html
+++ /dev/null
@@ -1,1304 +0,0 @@
-
-
- - What are the course objectives?
-
-
Upon completing this course, students should be able to:
-
- Recognize the inherent and accidental
- complexities involved with developing concurrent software that
- communicates securely between processes and
- threads.
- Understand how pattern-oriented software
- architecture and framework techniques can and cannot help to
- alleviate these complexities.
- Apply patterns and
- frameworks to develop reusable and resilient concurrent
- applications and services using the Java object-oriented
- programming language and Android middleware.
- Know
- where to find additional sources of information on how to
- program mobile applications and services on Android handheld
- systems.
-
-
-
- - How does this MOOC compare/contrast with courses at
- Vanderbilt?
-
-
This MOOC is heavily based on senior-level
- undergraduate courses we teach at Vanderbilt, such as the
- course Systems Programming for Android (CS
- 282). CS 282 focuses on teaching mobile software
- development at both a conceptual level (e.g., an understanding
- of software patterns, object-oriented design, and frameworks)
- and a practical level (e.g., experience programming Android
- services and applications using Java and Eclipse). Students in
- this course are expected to be familiar with Java and Eclipse
- and are capable of learning new material without significant
- hand-holding by the teachers and course staff. The lecture
- material in CS 282 is similar to the material for this MOOC
- (in fact, you can watch earlier versions of this material that
- I presented live in CS 282 via this a YouTube
- channel). The quizzes, programming assignments, and level
- of feedback for the Vanderbilt courses are different, however,
- since the courses at Vanderbilt have many fewer students, so
- there's significantly more personalized guidance from the
- professor and TAs that can't (yet) be replicated via a
- MOOC.
-
-
- - What are your assumptions about--and expectations
- for--students taking this MOOC?
-
-
As mentioned above, this MOOC is based on material we teach to
- senior-level undergraduate students at Vanderbilt. The lecture
- material is therefore intended for self-motivated students who
- already know Java and Eclipse (or can learn them quickly on
- their own) and who want to understand both the concepts and
- practice of mobile software development. Moreover, this material
- is targeted at students who want to know (1) how to program
- mobile software applications and services and (2) how the
- Android software stack is designed and implemented. Therefore,
- students who are looking for vocational training (e.g., having
- an instructor provide solutions directly or simply walk through
- application code projects step-by-step in the Android
- development environment) may not find this MOOC suitable for
- their needs since our goal is to help students learn how to find
- a solution, not simply provide a solution. Moveover, this MOOC
- covers a wide range of topics (especially patterns and
- frameworks) associated with quality mobile software
- development. For students who just want training we recommend
- others sources, such as
- the Android
- Application Development Tutorials on
- YouTube.
-
-
- - What is the most effective way to learn material covered
- in the course and to successfully complete the programming
- assignments?
-
-
We recommend watching the videos multiple times, looking for
- different levels of meaning in the diagrams and the
- examples. It's particularly important to carefully watch all the
- videos referenced in the programming assignment descriptions
- since they provide many relevant tips and insights. Likewise, we
- recommend reading the material pointed to by links in the
- slides, as well as material from the (optional) recommended
- reading. Naturally, participating in the online discussion forum
- (and ideally, a meetup group if one is available in your area)
- will help make the course material more engaging and
- personalized. Additional discussions of the programming
- assignment goals, requirements, and (ultimately) their solutions
- will be covered in "Virtual Office Hours" (see the FAQ entry on
- this topic below).
-
-
- - Can students take this course if they have no prior
- experience programming Android and/or Java in Eclipse?
-
-
Our course assumes that students are comfortable programming
- in Java and have some experience programming Android apps in
- Eclipse. If you don't have any Java programming background you
- might consider taking the course Java for Complete
- Beginners. Likewise, you might also benefit from the Creative,
- Serious and Playful Science of Android Apps MOOC, which is
- a novice-friendly introduction to computer science and
- programming Android-apps for smart-phones and tablets. No
- prior programming knowledge is necessary for that MOOC. We
- also recommend that you take Professor Adam Porter's MOOC Programming
- Mobile Applications for Android Handheld Systems since his
- course provides important coverage of Android app programming
- that will be useful in our course. We encourage you to apply
- the Lazy
- Acquisition pattern in these MOOCs, i.e., watch the
- videos, keep track of what you know understand, and then use
- the resources available to you (e.g., via the web and the
- discussion forums) to fill in the gaps in your knowledge. One
- of the best things about MOOCs is that you can go through this
- material at your own pace, and there's really no penalty for
- retaking a MOOC if you struggle with it the first time
- through!
-
-
-
- - Why are there so many URL links embedded at the bottom of
- the slides?
-
-
Many of the topics (especially concurrency,
- inter-process communication, and application security) we
- cover in this MOOC are very technically deep. Given our
- limited time and resource constraints, we can't possibly
- address all this material in a single MOOC. Yet many students
- may benefit from learning more about these topics, either
- during or after the MOOC. Therefore, when there's additional
- pertinent information on a topic that we can't cover in our
- videos, we provide links in the PDF versions of the slides
- that students can download from the Video
- Lectures page or from the 2014 POSA MOOC wiki
- maintained by students. These links point to material on the
- web so that students can read as their interests and time
- permits. Following up on all the links is a rewarding, albeit
- time consuming task. In fact, we term these videos "Lembas
- Lectures" since a small dose of them can keep a student
- nourished (intellectually) for hours! However, none of the
- quizzes will involve questions related to this material, so
- students can read them at their leisure. The videos in Section
- 0 are largely introductory, so feel free to watch them at an
- accelerated rate of speed if you're willing to read all this
- FAQ instead.
-
-
- - What is the course staff policy for moderating and
- answering discussion forum threads and questions?
-
-
The course staff will endeavor to reply to thoughtful
- technical questions or constructive suggestions for improving
- the course. Often, the responses will point to other resources
- (such as this FAQ or to video lectures) so that students can
- learn the details of the solutions on their own, which is more
- effective pedagogically. Rants and flames (such as "Android
- sucks," "Language X is better than Java," "Patterns are bad,"
- or "I hate these lectures") will be ignored and/or removed
- since they generate much more heat than light and disrupt the
- learning process. Questions posted anonymously will also
- receive less attention since we want to get to know the
- students in the MOOC so the learning environment will be more
- like a face-to-face course. Due to extremely limited course
- staffing resources, questions about installing or using
- Eclipse, the Android emulator, debugger, etc. will be
- addressed by the community of other students taking this
- MOOC. Step-by-step instructions on how to setup an Android
- development environment using Eclipse and Java are
- available here.
-
-
-
- - How many and what types of programming assignments will
- there be in this MOOC?
-
-
We'll have a half-dozen or so
- programming assignments in this MOOC. The first several
- assignments will give students experience applying and
- developing concurrency mechanisms (e.g., implement a simple
- AtomicLong and a simple Semaphore using Java
- ReentrantReadWriteLock, ReentrantLock, and
- ConditionObject classes using the Java
- console environment). The next several assignments will
- involve applying and developing frameworks and
- applications that use these frameworks (e.g., a multi-threaded
- ping/pong Android application that will apply various GoF
- patterns to develop a framework that will make it easy to port
- the application between Android and console configurations in
- Eclipse). The final assignment will be an integrated project
- that will give students experience applying pattern-oriented
- concurrency mechanisms & Android concurrency frameworks
- (e.g., AsyncTask and Handles, Runnables, and Messages) to the
- iRemember application that was introduced in
- Professor Porter's MOOC on Programming Mobile
- Applications for Android Handheld Systems. All the source
- code examples and skeletons for the programming
- assignments will be available in this GitHub
- repository once the Coursera POSA MOOC officially
- starts.
-
-
-
- - How can students understand and learn the material in the
- videos most effectively?
-
-
There is no one rate of speaking that's appropriate for all
- students. For students whose native language is not
- English--or for any students who find the rate at which the
- material is presented in the videos too fast to comprehend--we
- recommend that you decrease the rate at which you play the
- videos to 0.8x or slower (naturally, for material that you're
- already familiar with, you might want to increase the rate at
- which the video plays!). If you need instructions on how to
- change the rate of playback speed for YouTube videos please do
- a google search for information about the browser that you're
- using. Once the POSA MOOC officially starts you'll also be
- able to download the videos and use the media player on your
- computer to obtain fine-grained control over the playback
- speed. The Coursera platform also provides English subtitles
- for all the videos based on the scripts we used to record them
- originally. Likewise, you can enable "captions" via the
- YouTube player to view subtitles at my YouTube
- playlist. In addition, downloading PDF versions of the
- slides and reviewing them prior to watching the videos may aid
- with comprehension. Finally, students might also consider
- watching the videos multiple times, focusing on different
- aspects of the material each time (e.g., listening to the
- voice track, looking at the code and diagrams on the slides,
- etc.). If you have time, you might also want to read the
- material referenced by the links provided at the bottom of
- many slides, which are listed on the 2014 POSA MOOC wiki
- maintained by students.
-
-
-
- - Will there be a Statement of Accomplishment for students
- who complete this class?
-
-
Yes. Students who successfully complete the quizzes and
- assignments in this class prior to the completion of the
- MOOC will receive a Statement of Accomplishment signed by
- the instructor. There will be two levels of Statements of
- Accomplishment: Normal Track and Distinction Track. The
- difference between the work performed in each of these tracks
- is covered at the Coursera website here. You
- needn't be in the Signature Track to get a Statement of
- Accomplishment with Distinction, though you do need to be in
- the Signature Track if you want to be eligible to take the
- Capstone project course, as described in the next FAQ entry
- below.
-
-
-
- - Who is eligible to take the Capstone project course?
-
-
Like all Coursera Specializations, the Capstone project
- course is only available to students who take the Signature
- Track for the preceding three MOOCs in the
- Specialization. Moreover, for this first offering of the
- Mobile Cloud Computing with Android (MoCCA) Specialization
- only students in the Signature Track who receive a "Verified
- Certificate with Distinction" in all preceding MOOCs are
- eligible to enroll in the Capstone project course. We may
- remove this restriction in future offerings of the MoCCA
- Specialization, after we have a better understanding of what's
- required to successfully complete the Capstone project
- course. Even if you didn't attain a Verified Certificate with
- Distinction in Professor Porter's 1st MOOC in the
- Specialization, you are still welcome to attempt a Verified
- Certificate with Distinction in the 2nd and 3rd MOOCs in the
- Specialization. If you succeed in attaining the Verified
- Certificates with Distintion in these two MOOC all you'll need
- to do is take Professor Porter's 1st MOOC when it's offered
- next, at which point you'll be eligible to take the next
- offering of the Capstone project course (i.e., not the one
- that's starts in October 2014, but the next one after that)
- once you'll successfully attain a Verified Certificate with
- Distinction in all three MOOCs.
-
-
-
- - What is a "trans-institutional MOOC Specialization"?
-
-
This MOOC and two other MOOCs (Programming Mobile
- Applications for Android Handheld Systems taught by Professor Adam
- Porter from the University of Maryland and Programming Cloud
- Services for Android Handheld Systems taught by Jules
- White from Vanderbilt University) have been designed to
- complement each other as part of the Coursera Specialization
- on Mobile
- Cloud Computing with Android. In particular, the
- programming assignments and the course project for all the
- courses will be coordinated. Additional information on our
- trans-institutional MOOC Specialization is available here.
-
-
-
- - Is it necessary to take Prof. Adam Porter MOOC prior to
- the POSA MOOC or can students take the POSA MOOC without
- taking his course?
-
-
It's not required to have taken Prof. Porter's MOOC on Programming
- Mobile Applications for Android Handheld Systems. If you
- just want to take some of the courses in this sequence--or
- take them all in different order--you're certainly welcome to
- do so, and you'll still learn a lot. You do need to be
- familiar with the core Java and Android topics he covered in
- his MOOC or you'll be lost (see FAQ item #5 about for
- suggestions on what you'll need to know and how to learn
- it). However, you needn't have done the integrative iRemember
- application in his MOOC since the POSA MOOC will provide a
- skeleton implementation of the iRemember project that focuses
- on different aspects of the application (e.g., concurrency and
- security features of Android), which won't require knowledge
- of what was done in Prof. Porter's MOOC (which focuses on
- user-facing features of Android). Naturally, if you take all
- the courses in this sequence in the order presented you'll
- gain a deeper, end-to-end understanding of handheld systems,
- their applications and services, as well as their integration
- into the cloud.
-
-
-
- - When will the course material be made available each
- week?
-
-
All the course material (e.g., video lectures, quizzes,
- programming assignments, etc.), for each week will be made
- available three days early (i.e., by Fridays) by 9am eastern
- time (2pm UTC/GMT) so that students can watch and read the
- material over the weekend prior to the beginning of the next
- week.
-
-
-
- -
- Is there a required textbook?
-
-
There is no required textbook, per se. There's lots of
- information available in the videos, slides, and the URLs
- mentioned in the slides that will help you learn the material
- we cover in this class. For deeper mastery of the material,
- however, please see the list of "recommended reading" on the
- POSA course
- webpage for a list of books that are closely related to
- the topics of the course.
-
-
-
- - Where can students learn about how to configure their
- Android and Java environment to run the examples and complete
- the programming assignments?
-
-
The POSA MOOC will use the same Eclipse-based Android
- development environment as Dr. Porter's earlier MOOC in this
- Specialization on Programming
- Mobile Applications for Android Handheld Systems,
- Step-by-step instructions on how to setup an Android
- development environment using Eclipse and Java are available
- here.
- If you're using a non-Eclipse development environment (such as
- Intellij
- IDEA or Android
- Studio) or want to use a different build tool (such as Maven)
- you'll need to enlist the help of other students on the online
- discussion forum and/or the POSA MOOC Wiki. Mavenized
- versions of all the programming assignments are available here.
-
-
-
- - Where can students learn more about patterns and
- frameworks?
-
-
Many videos about patterns and frameworks appeared in Section
- 2 and the Appendix of the Spring
- 2013 offering of the POSA MOOC. You can find links to all
- these videos here,
- though you may need to register first at this
- link. If you're a Safari online book club member you
- should check out the Design
- Patterns in Java video training series that covers the
- "Gang-of-Four" patterns.
-
-
-
- - Which web browsers are recommended
-
-
Coursera recommends using the Chrome and Firefox
- browsers. There's also a mobile
- app for Coursera MOOC, as well.
-
-
-
- - Can students use programming language [X] for the
- course?
-
-
The programming assignments in the Android portion of this
- course are designed for the Java programming language. The
- cloud computing portion may provide more flexibility, but it
- will also focus largely on Java, as well. Although you're
- welcome to use other languages on Android for your personal
- edification, if you stray from Java you'll have more work to
- do to map what we're covering in the videos and projects to
- the languages you want to use. You may also find it hard to
- get feedback on your work via the Coursera peer-grading
- system .
-
-
-
- - Where can students download the slides and source code
- that are presented in the videos and the skeletons that are
- provided for the programming assignments?
-
-
PDF versions of the slides will be available for download
- after the videos are released onto the Coursera POSA MOOC
- website each week. These versions of the slides will have
- clickable links to make it easy to navigate to the
- supplemental material referenced in the slides. All the
- source code examples and skeletons for the programming
- assignments will be available in this GitHub
- repository once the Coursera POSA MOOC officially
- starts. Step-by-step instructions for using GitHub are
- available here
- and a video explaining the basics of Git and GitHub is
- available here.
-
-
-
- - How will the 2014 version of the POSA MOOC differ from the
- 2013 version?
-
-
Alhough the 2014 POSA MOOC will cover many of the same
- patterns (plus new ones), it will be radically different than
- the 2013 version in almost every other respect. The 2014 POSA
- MOOC won't cover some of the more "abstract" topics we
- discussed in the 2013 POSA MOOC. For example, we won't have
- (new) videos on pattern relationships (e.g., pattern
- sequences, pattern languages, etc.), general discussions of
- frameworks, design dimensions of concurrency and networking,
- overview of middleware stacks, etc., since (1) that's outside
- the scope of Android and (2) we already have those videos
- available in the 2013 POSA
- archives, so you can rewatch the older videos for more
- information on the themes of object-oriented software
- patterns, frameworks, and design dimensions. the 2014 POSA
- MOOC will cover many POSA2 and GoF patterns addressed in
- Section 3 of the 2013 POSA MOOC, though they'll be presented
- in the context of Java and Android instead of C++ and
- ACE.
-
-
-
- - Where is the material from the 2013 POSA MOOC available
- online?
-
-
All the video lectures, assignments, quizzes, and discussion
- forum postings from the 2013 offering of the POSA MOOC is
- available here,
- though you may need to register first at this
- link. A summary of the 2013 POSA MOOC is also available here.
-
-
-
- - Why does this MOOC's name start with "Pattern-Oriented
- Software Architecture?
-
-
All MOOCs Douglas
- C. Schmidt teaches on Coursera have a focus on pattern-oriented
- software architecture. The details of what sorts of
- patterns--and what applications of patterns we'll
- cover--differ from MOOC-to-MOOC, but the patterns focus is
- consistent - hence the common prefix for the names.
-
-
-
- - What is the schedule for the course?
-
-
This MOOC, like all Coursera MOOCs, uses pre-recorded videos
- for all the lecture material. As a result, there's no set time
- when the class occurs, e.g., you can watch the videos at a
- time and a pace that is most convenient for you. There will be
- periodic programming assignments that will have a deadline,
- which will be clearly marked on the POSA MOOC
- website in the course
- calendar by clicking on the calendar icon next to the
- "Upcoming Deadlines" label. This calendar is automatically
- updated as the material is released. Each week for the first
- eight weeks (starting with Week 1) a programming assignment
- will be released on Monday (see the POSA MOOC GitHub
- repository for the assignments). It will be due exactly
- two weeks from when it is released. Likewise, there will be
- weekly quizzes, released by the middle of each week, though
- their due dates will all be the last day of class so you can
- take them as time permits (naturally, there won't be any "late
- dates" for quizzes since they are due the last day of
- class). Finally, we'll have periodic "virtual office hours,"
- where I'll answer questions from students and lead impromptu
- discussions with students live via Google Hangout and
- YouTube. All these virtual office hours will also be recorded
- and uploaded to the Coursera website so you can watch them at
- your convenience.
-
-
-
- - What are the plans for
- offering the MoCCA Specialization again in the future?
-
-
We are planning to re-offer the MoCCA Specialization starting
- with Prof. Porter's MOOC on Programming
- Mobile Applications for Android Handheld Systems in the
- Fall of 2014. As soon as these plans are finalized we'll post
- an announcement with the start date and schedule. For those
- students who haven't yet achieved a Verified Certificate with
- Distinction in Prof. Porter's MOOC, this will be your next
- chance to become eligible for the next Capstone project course
- (see FAQ item #11)
-
-
-
- - How long will the course material be available online
- after the MOOC ends?
-
-
We plan to keep the videos, presentations, discussion forum
- postings and responses, etc. available indefinitely.
-
-
-
- - Where is the source code that corresponds to the pathnames
- embedded in the slides shown in the videos?
-
-
All the Android source code referenced by the pathnames in
- the slides shown in the videos is available from here (likewise, just the
- relevant parts of the Android 4.0 code that we'll be using are
- available from https://class.coursera.org/posa-002/wiki/Source_Code_By_Week). If
- you download this source code to your computer the pathnames
- will be relative to the top-level source directory and
- typically start with the bionic, dalvik, frameworks, libcore,
- or packages pathname prefixes. The source code shown for more
- examples is based on Android 4.0, which is the so-called "Ice
- Cream Sandwich" release. The code we examine, however, should
- be largely the same in later versions of Android, as well.
-
-
-
- - Will there be much flexibility in the schedule of deadlines
- for programming assignments in the POSA MOOC?
-
-
It will be hard to add flexibility into the schedule since
- this causes chaos with the peer grading system and greatly
- increases the load on the course staff. The "course staff" is
- very small (just Doug Schmidt and Jules White), so we're
- unlikely to have enough spare time to keep track of flexible
- deadlines. Students who unable to do all the assignments in
- the allotted time frame should consider "auditing" the POSA
- MOOC for this offering and then take it again if/when it's
- offered again in the future. Please see item #25 in the FAQ at
- http://www.coursera.org/course/posa
- for more thoughts on if/when these MOOCs may be offered again.
-
-
-
- - How closely aligned will the
- programming assignments be between MOOCs in the MoCCA
- Specialization?
-
-
The final project for each MOOC in the
- MoCCA Specialization will involve adding capabilities to the
- iRemember app. The instructors for all the MOOCs are working
- together to ensure the iRemember project is properly aligned,
- though it won't be necessary to have completed the previous
- iRemember project(s) in a given MOOC. Moreover, the other
- programming assignments in their MOOCs will reflect the focus
- of their respective MOOCs since (1) the topics are largely
- different in each MOOC and (2) there's no requirement that
- students must take the MOOCs in a particular sequence, so
- inter-MOOC dependencies will be minimized.
-
-
-
- - How will the programming assignments be submitted and
- assessed?
-
-
Each week for the first eight weeks (starting with Week 1) a
- programming assignment will be released on Monday (assignments
- will only be available from GitHub). It
- will be due exactly two weeks from when it is released. Since
- we don't have the time or staffing resources to create
- entirely auto-graded programming assignments, we'll use the
- following hybrid assessment method for most of the
- assignments:
-
-
-
- Auto-assessments, which will be performed via automated
- JUnit regression tests supplied with each programming
- assignment. Students can run these regression tests locally on
- their computers to ensure their solutions work correctly prior
- to submitting them.
-
- Peer assessment, which will
- involve having five other students in the MOOC compile/run the
- automated JUnit regression tests on the submitted solutions to
- ensure that the solution actually produces the expected
- output.
-
-
- The final project will involve adding
- capabilities to the iRemember app started in Dr. Porter's
- MOOC; it will likely be entirely peer-graded unless we get
- volunteers to develop suitable JUnit regression tests for it.
- As the assignments are released (and prior to their due date)
- we'll use the Coursera Peer
- Assessment mechanism to do the actual submissions.
- Previews of the programming assignments are available at this
- GitHub
- repository, though there may be some changes to the
- assignments and skeleton code before they are officially
- released through the Peer Assignment page each week.
-
-
-
- - Will the links in the MOOC lecture videos be made clickable
- and/or consolidated into a single convenient location?
-
-
Students in the POSA MOOC are crowd-sourcing the links from
- all the lecture slides and adding them to the POSA
- wiki, so please contribute to this effort. All the lecture
- slides will be available in PDF form after the videos have
- been uploaded to the Coursera POSA MOOC
- website each week, so you can also access the links that
- way. Note that the "Introduction" videos have no associated
- PDF files.
-
-
-
- - Where are good sources of tutorials and
- examples for Java and Android concurrency
- mechanisms?
-
-
Concurrency is not an easy topic to master, so students
- should leverage multiple sources of learning. Nearly every
- video in Section 1 (and beyond) has code fragments straight
- out of Android, all of which is available from source.android.com or just the
- relevant parts of the Android 4.0 code we use are available
- from here. The
- Java code from the java.util.concurrent
- package in libcore/luni/src/main/java/java/util/concurrent is
- an excellent way to see how Java concurrency mechanisms
- covered in the POSA MOOC videos are developed and used in
- practice. We've developed complete example programs for the
- MOOC that are available here. There's
- also example code in the assignments available here,
- though you'll need to fill in the "TODO" comments to get them
- to work. In addition, useful tutorials on Java concurrency
- mechanisms appear here
- and here. Finally,
- consider reading the books listed in the "Suggested Readings"
- Section of the POSA MOOC
- page.
-
-
-
- - How can students help improve the
- form and content of the video lectures?
-
-
Please leave your constructive comments and suggestions for
- improving the content of the video lectures in the discussion
- forum entitled Suggestions
- for Improving the Video Lectures. The most useful
- suggestions are ones that help us improve the technical
- accuracy and quality of the material, rather than just
- commenting on the presentation format and style. Although
- there may not be time to address these comments for this
- offering of the POSA MOOC, we'll consider them for future
- offerings. In addition, these suggestions will help to improve
- the LiveLessons versions of these lectures that will be
- created during the summer of 2014. Please see this
- link for more information about the LiveLessons series,
- including the first set of videos on Design
- Patterns with Java. Also, if you spot any typos or
- problems with subtitles for the videos please note them here
- so we can fix them.
-
-
-
- - How can students keep
- informed about important due dates for assignments?
-
-
Once the 2014 POSA MOOC has officially begun (in mid-May),
- there will be a calendar of events listing the due dates,
- etc. Likewise, reminders will be posted periodically to the
- Announcements page (and thus disseminated via email to all
- enrolled students). Ultimately, however, students are
- responsible for keeping track of the deadlines and procedures
- related to properly submitting the MOOC assignments. Given
- the large number of students enrolled in the MOOC, there will
- be little/no support for individual extensions or special
- handling of late or improperly submitted solutions to the
- assignments.
-
-
-
- - How many hours per week will be required for the POSA
- MOOC?
-
-
There's no 100% accurate way to estimate how long any given
- student will require to watch the videos and complete the
- quizzes and assignments each week since each person has
- different background, aptitude, motivation, learning style,
- etc. Moreover, some students are doing the "normal track" and
- others are doing the "distinction track". With that caveat in
- mind, please see this
- link for rough estimates of how much time may be
- required, depending on which track a student is
- doing. Concurrency is not an easy topic to master, however, so
- if doing the material assigned for the "distinction track"
- consumes an excessive amount of time please consider switching
- to the "normal track",l which requires much less work since
- there are no programming assignments.
-
-
-
- - What are some consequences of the "massiveness" of a MOOC?
-
-
The massive number of students in the POSA MOOC (50,000+)
- impacts some aspects of the course that differentiate it from
- a traditional face-to-face courses, such as the courses the
- instructors teach at Vanderbilt and the University of
- Maryland. In particular:
-
-
-
- The POSA MOOC course staff will not be able to provide
- individual feedback on student assignments, though we will
- present our solutions to the assignments in the weekly
- "virtual office hours" (see this
- paper for more information on virtual office hours). If
- you run into problems feel free to post your buggy code to the
- appropriate assignment
- discussion forum so that other students can provide you
- tips on fixing your bugs. Please don't post working solutions
- to the discussion forum, however, since that violates the
- Coursera Code of Conduct.
-
- Some things will inevitably go awry, e.g., peer graders
- will undoubtedly not follow the rubric correctly, unit tests
- will need to change, students will forget to add their source
- code when they submit their solutions, important deadlines
- will be missed due to unforeseen circumstances, assignments
- will be modified after they are released, etc.
Due
- to the massive number of students--coupled with the very
- limited course staff--it's unfortunately sometimes the case
- that the instructors won't be able to "make it right" in a
- manner that makes everyone happy. In these situations, our
- goal is to maximize the opportunity for as many students as
- possible to gain access to a world-class education. Other
- considerations (such as consistency, fairness, and
- accountability) are also relevant, but our first priority is
- to help empower students with an education that will improve
- their lives.
-
-
-
- - How do the CS 282 videos relate to the 2014 POSA MOOC
- videos?
-
-
The ~20 hours videos from the Vanderbilt course CS 282:
- Systems Programming with Android available on the YouTube
- playlist at http://www.youtube.com/watch?v=lHbIwoevePE&list=PLZ9NgFYEMxp50tvT8806xllaCbd31DpDy
- overlap with some of the concurrency-related material
- presented in the 2014 POSA MOOC. However, these YouTube videos
- are not a substitute for the 2014 POSA MOOC videos, which will
- be aligned with the programming assignments and topics covered
- in the MOOC (and which are also much higher quality and more
- technically accurate). The CS 282 videos are still a valuable
- resource to supplement the MOOC videos since they cover some
- topics, such as the Android Development Environment,
- Activities, certain local Inter-Process Communication (IPC)
- mechanisms, etc., that don't appear in the 2014 POSA
- MOOC.
-
-
-
- - What are "Virtual Office Hours"?
-
-
"Virtual Office Hours" provide an opportunity for instructors
- to interact in real-time with students once a week on
- questions about material covered in the video lectures,
- quizzes, and programming assignments. Google Hangout on the
- Air and YouTube (see the Virtual
- Office Hours videos from the 2013 POSA MOOC) are used as
- the means to engage with students. Google Handout
- automatically records the office hour discussions, which are
- then uploaded to the POSA MOOC website so students can view
- them offline if they can't make it to the live
- events. Likewise, any questions post to the discussion forum
- on Virtual
- Office Hours will be answered during the session.
-
-
-
- - How much of the Android software stack is covered by the
- MoCCA Specialization?
-
-
The MOOCs that comprise the MoCCA
- Specialization cover a wide range of Android and Cloud
- Computing middleware and application topics, as summarized in
- this
- overview video. However, this Specialization does not
- (yet) cover the full
- stack of Android and Cloud Computing software. In
- particular, the Android Linux kernel, user-level device
- drivers, native development kit, Dalvik virtual machine, and
- C/C++-based library and service layers are not covered.in
- detail. Likewise, certain Android middleware topics (such as
- local inter-process communication mechanisms, network
- programming, Bound and Unbound Services, and Content
- Providers) are only touched upon briefly. Future offering of
- the MoCCA Specialization will (hopefully) provide more
- coverage of these topics, as time and resources permit.
-
-
-
- - What's the best way to watch the videos to avoid being
- distracted by the presenter's style and/or call-outs to
- embedded URLs?
-
-
The particular style for the video lectures was choose to (1)
- mimic the experience of a face-to-face lecture class and (2)
- minimize the amount of time spent post-producing the
- videos. The frequent call-outs to embedded URLs is motivated
- by the reasons outlined in FAQ item #6 above and to simplify
- the post-production process (for which we have very limited
- resources). However, some students find this style distracting
- during the videos. The easiest way to resolve the presenter
- distraction is to simply move the media player window so that
- only the slides are visible. Ultimately, better solution will
- materialize in the LiveLessons version of this material that
- we'll create during the summer of 2014, which will be
- professionally edited by Pearson, so if you're a Safari online
- book club member you'll be able to watch this material without
- distractions. More information (and examples of the
- presentation format) are available at the Design
- Patterns with Java website..
-
-
-
- - Can students use public source code repositories to store
- their solutions to the programming assignments?
-
-
Please do not use public source code repositories (e.g., the
- freely available GitHub accounts) to store your solutions to
- the programming assignments. Publically available repositories
- encourage students to copy each others work, which is a
- violation fo the Coursera code of conduct that does not allow
- students to share work unless explicitly instructed by course
- policies.
-
-
-
- - What are some good techniques,
- tools, and methods for visualizing, analyzing, and debugging
- concurrent Java programs.
-
-
Debugging concurrent programs is hard due to a variety of
- accidental and inherent complexities discussed in the Section
- 1: Module 1 of the video
- lectures. There are many resources available to help
- students debug their concurrent programs, some of which are
- free, some of which aren't, and some are a mixture of free and
- non-free.The Thread
- Scheduling Visualizer (TSV) is a set of tools that provide
- an easy way to record and visualize thread scheduling. The Fluid
- project provides a set of Eclipse tools for programmers to
- analyze, assure, and evolve multi-threaded Java programs. Some
- tips on debugging multi-threaded program are available here.
-
-
-
- - Where is the source code for examples and assignment
- solutions from the Vanderbilt?
-
-
CS
- 282: Systems Programming for Android and CS
- 251: Intermediate Software Design
- courses?
The source
- code for the Java variant of the CS 251 "expression tree
- processing application" is available as part of the
- supplemental material for the Pearson LiveLessons courses on
- Design
- Patterns with Java. The ThreadedDownloads application
- example from Section 1: Module 3 is available in GitHub
- as part of the 2014 POSA MOOC. Other assignment solutions are
- not available since they form part of the work expected from
- Vanderbilt students who take these courses.
-
-
-
- - How much of a focus on patterns and frameworks will there
- be in this MOOC?
-
-
Patterns and framework provide the foundation for much of the
- material in this course. There is a short introduction to
- patterns and frameworks in Section 0 and several modules in
- Section 1 will focus on POSA and GoF patterns and frameworks
- applied in Android. Many other videos and other resources
- related to patterns and frameworks are also available here.
-
-
-
- - How can we convince our colleagues and management of the
- value of patterns and frameworks in practice?
-
-
As with most issues associated with IT, there's no single
- "silver bullet" that will convince managers and executives of
- the "return on investment" (ROI) value of software techniques,
- tools, and methods (TTMs). Instead, what's required is a
- long-term commitment (at both the individual and
- organizational levels) to invest in TTMs that provide tangible
- payoffs wrt things that matter to managers/executives and
- (arguably more importantly) to customers/sponsors). The
- pattern-oriented and framework-oriented TTMs presented through
- this MOOC are a step in the right direction -- after all,
- these TTMs underlie much of Android and Java, which would not
- be as powerful and pervasive without these TTMs. Ultimately,
- each individual and organization needs to devise a strategy
- for demonstrating the tangible benefits of patterns and
- frameworks to the powers-that-be in terms of ROI that they
- value, such as reducing software defect rates, enhancing
- productivity across the lifecycle (rather than just "hacking
- it up and shipping it out"), and increasing the resilience
- (e.g., to failures and cyber-attacks).
-
-
-
- - Why do the assignments start with 0, but the weeks start
- with 1?
-
-
The assignments use Java/C/C++ range semantics, whereas the
- weeks use calendar range semantics. If this distinction
- doesn't make sense, you may be a recovering Pascal or Ada
- programmer ;-)
-
-
-
- - Why are there lecture
- videos on YouTube and on the POSA Coursera website?
-
-
The videos on YouTube and the videos on the Coursera site
- should be identical, but all videos must be approved by
- Vanderbilt before they can be uploaded and published on the
- POSA Coursera website. We therefore release them first on
- YouTube as we complete them so that interested students can
- preview them and provide feedback so that any mistakes can be
- fixed before they are released to the POSA Coursera website.
-
-
-
- - How can we fix the warning "There are no JREs installed in
- the workspace that are strictly compatible with this
- environment"?
-
-
First, check what version of JRE you have installed or you
- have set as an environment variable JAVA_HOME or JAVA_JRE. If
- you find out that you have installed java version 7 then you
- right click on the project folder in Eclipse. Then
- Properties->Java Build Path -> Libraries. You click on
- JRE System Library and then the button Edit where you select
- Execution Environment similar to the one you have installed on
- your PC. Although you are welcome to use whatever version of
- Java you'd like for your programming assignments, you need to
- make sure that whatever you submit to be graded works with
- Java version 6 since otherwise your solution may not work and
- the grader will deduct many points.
-
-
-
- - The introductory assignments are too easy - are there other
- programs we can write to get experience with more advanced
- Android concurrency and communication mechansisms?
-
-
If you get bored with these introductory assignments and want
- to try writing more interesting programs, please see the CS
- 282 programming assignments available here. We'll
- cover some of these topics later in the MOOC, but you're
- welcome to check this stuff out now.
-
-
-
- - Since many of the assignments have been posted to GitHub
- can we work on them prior to their official release?
-
-
You're welcome to work ahead on these assignments, which is
- one of the reasons why we've put manhy of them out early.
- However, some things are likely to change based on a number of
- factors, such as feedback from students, improved JUnit tests,
- bug fixes, etc. Although it's unlikely you'll need to do a
- wholesale rewrite of your solution (mostly the JUnit tests
- should get more thorough) until the assignment is officially
- posted via the "Programming Assignments and Assessments" tab
- you'll need to be prepare for some changes.
-
-
-
- - Where is more information available on Android
- internals?
-
-
It's worthwhile watching videos on Android's anatomy
- and physiology and Dalvik
- Virtual Machine. Although these are from 2008 they provide
- a good overview of how Android works internally.
-
-
-
- - How can I prepare in advance for the upcoming
- Programming Cloud Services for Android Handheld Systems
- course?
-
-
The course will cover a number of topics on HTTP
- communication in Android and HTTP-based cloud services with
- the Java Spring Framework. Before you start preparing for the
- cloud course, ensure that you understand the concurrency
- material from the POSA course, particularly AsyncTasks and
- Handlers. Some helpful resources to get a jumpstart on the
- cloud course are:
-
-
-
-
- - What resources can be used for the weekly quizzes?
-
-
You are welcome to use videos or presentation material when
- answering the weekly quiz questions.
-
-
-
- - Why are there two versions of week-1-assignment-0?
-
-
The official version is the one at https://github.com/douglascraigschmidt/POSA-14/tree/master/assignments/week-1-assignment-0
- is the "official" version that will be used for peer
- assessments. The one at https://github.com/douglascraigschmidt/POSA-14/tree/master/assignments/week-1-assignment-0-v2
- provides better diagnostics and has a cleaner design that uses
- the Template Method pattern to decouple the test
- infrastructure from the student-supplied code. However, it's
- not the official version that will be peer graded and is
- provided solely as a way for students to understand better how
- concurrency and Java Threads work.
-
-
-
- - Can I take Programming Cloud Services for Android Handheld
- Systems without taking Programming Mobile Services for Android
- Handheld Systems?
-
-
It is possible to take the cloud course without the mobile
- services course. However, the cloud course uses the
- concurrency concepts that are introduced in the mobile
- services course. If you take both courses, you will have a
- much stronger understanding of the material and be far less
- likely to have trouble in the cloud course. We highly
- encourage students to take both courses.
-
-
-
- - Which videos have in-video quizzes?
-
-
All "non-introductory" videos have in-video quizzes, which
- pop up periodically (typically prior to the "Summary"
- segments) and ask students questions about what they've been
- watching. All of Section 0 and the intros to each Section or
- Module are considered "introductory" videos. In-quiz videos
- only appear if you stream the videos from the Coursera server,
- but don't appear if you download the videos to your local
- computer first.
-
-
-
- - What are some examples of Android applications and services
- developed using the concurrency and communication mechanisms
- covered in this MOOC?
-
-
Watch the videos that are available at https://class.coursera.org/posa-002/lecture
- as well as the previews of forthcoming videos that are
- available at https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4tbiFYip6tDNIEBRUDyPQK
- for many example concurrent applications and services from the
- Android source code itself, as well as sample applications we
- developed for this MOOC. Moreover, if you download the Android
- source code from http://source.android.com and
- look in the packages/apps/ directory you'll see dozens more
- Android applications, most of which use the concurrency and
- communication frameworks and mechanisms discussed in this
- MOOC.
-
-
-
- - What is the difference between the "assignments" and the
- "grading-drivers" directories on GitHub?
-
-
The "assignments" directory on GitHub (at https://github.com/douglascraigschmidt/POSA-14/tree/master/assignments)
- contains the skeletons that are used by students who complete
- the skeletons and submit their solutions for peer
- assessment. The "grading-drivers" directory on GitHub (at https://github.com/douglascraigschmidt/POSA-14/tree/master/grading-drivers)
- is used by peer assessors to evaluate the submissions. This
- separation enables us to improve the JUnit tests used for
- evaluating submissions without changing the skeletons used by
- students to write their solutions.
-
-
-
- - What can we do if the audio is out of sync with the video
- stream when viewed from the course website on Coursera?
-
-
You might try playing the videos at a lower resolution if
- your browser supports this or downloading the to your computer
- and watching them locally. Apparently, the videos on my YouTube
- playlist are synchronized better, so you might try watching
- them (they are identical to what's on the Coursera website). If
- all else fails, consider applying the suggestions in FAQ item
- #40 above.
-
-
-
- - What is an "Optional Lecture"?
-
-
Certain lectures are not directly related to the topics of
- concurrency, communication, and security, but provide
- additional information that may be useful to readers who want
- to know more about topics like frameworks, patterns, and
- software product lines. These lectures are marked optional,
- which means that they don't "quizzified" and questions
- pertaining to them won't appear on a weekly quiz. Feel free
- to watch them if you're interested and skip them if you're
- not.
-
-
-
-
From 45d3c5d2f82978aa41f2573eb1cec44743a9a172 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Fri, 23 May 2014 06:52:15 -0500
Subject: [PATCH 035/202] Updated the documentation.
---
assignments/week-3-assignment-2/Assignment-Description.txt | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index 661531edd..dfaec9ca7 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -34,7 +34,10 @@ fill in here" portions!!!
In particular, you'll need to do the following:
. Implement the SimpleAtomicLong class, which you should replace with
- your working solution to week-2-assignment-1.
+ your solution to week-2-assignment-1, after applying any fixes
+ suggested by peer graders. This class is only used by the
+ PalantirManagerUnitTest.java and should not be used by the
+ SimpleSemaphore implementation.
. Implement the SimpleSemaphore class using a Java ConditionObject and
Java ReentrantLock, which are covered in these videos:
From e341610a686ce06e1ae2fa271a39ea2b742e7bc4 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Fri, 23 May 2014 07:06:37 -0500
Subject: [PATCH 036/202] Fixed typo.
---
assignments/week-3-assignment-2/Assignment-Description.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index dfaec9ca7..43ffd7ae4 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -7,8 +7,8 @@ In this assignment, you will use a Java ReentrantLock and Java
ConditionObject to implement a subset of the Java
java.util.concurrent.Semaphore class, which we call SimpleSemaphore.
This assignment also reuses the SimpleAtomicLock you implemented for
-Assignment 0, so make sure it's compiling and running properly before
-attempting this assignment!
+week-2-assignment-1, so make sure it's compiling and running properly
+before attempting this assignment!
The goal of this assignment is to use the SimpleSemaphore to correctly
implement a resource manager that limits the number of Beings from
From a01e93d4c2eec7c521c9d2c829203c66dc48e808 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Fri, 23 May 2014 17:08:24 -0500
Subject: [PATCH 037/202] Added the SimpleAtomicLong.java file back to the
grading driver.
---
.../src/edu/vuum/mocca/SimpleAtomicLong.java | 106 ++++++++++++++++++
1 file changed, 106 insertions(+)
create mode 100644 grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java
diff --git a/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java
new file mode 100644
index 000000000..b8851333a
--- /dev/null
+++ b/grading-drivers/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java
@@ -0,0 +1,106 @@
+package edu.vuum.mocca;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * @class SimpleAtomicLong
+ *
+ * @brief This class implements a subset of the
+ * java.util.concurrent.atomic.SimpleAtomicLong class using a
+ * ReentrantReadWriteLock to illustrate how they work.
+ */
+class SimpleAtomicLong
+{
+ /**
+ * The value that's manipulated atomically via the methods.
+ */
+ private long mValue;
+
+ /**
+ * The ReentrantReadWriteLock used to serialize access to mValue.
+ */
+
+ // TODO -- you fill in here by replacing the null with an
+ // initialization of ReentrantReadWriteLock.
+ private ReentrantReadWriteLock mRWLock = null;
+
+ /**
+ * Creates a new SimpleAtomicLong with the given initial value.
+ */
+ public SimpleAtomicLong(long initialValue)
+ {
+ // TODO -- you fill in here
+ }
+
+ /**
+ * @brief Gets the current value.
+ *
+ * @returns The current value
+ */
+ public long get()
+ {
+ long value;
+
+ // TODO -- you fill in here
+
+ return value;
+ }
+
+ /**
+ * @brief Atomically decrements by one the current value
+ *
+ * @returns the updated value
+ */
+ public long decrementAndGet()
+ {
+ long value = 0;
+
+ // TODO -- you fill in here
+
+ return value;
+ }
+
+ /**
+ * @brief Atomically increments by one the current value
+ *
+ * @returns the previous value
+ */
+ public long getAndIncrement()
+ {
+ long value = 0;
+
+ // TODO -- you fill in here
+
+ return value;
+ }
+
+ /**
+ * @brief Atomically decrements by one the current value
+ *
+ * @returns the previous value
+ */
+ public long getAndDecrement()
+ {
+ long value = 0;
+
+ // TODO -- you fill in here
+
+ return value;
+ }
+
+ /**
+ * @brief Atomically increments by one the current value
+ *
+ * @returns the updated value
+ */
+ public long incrementAndGet()
+ {
+ long value = 0;
+
+ // TODO -- you fill in here
+
+ return value;
+ }
+}
+
From 4fa339d04d6e94f59ca361ade128693fa53c2d31 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 24 May 2014 06:45:48 -0500
Subject: [PATCH 038/202] Added a hint about the type of variable used for
availablePermits.
---
.../src/edu/vuum/mocca/SimpleSemaphore.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
index 9bfefed73..9911231d6 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
@@ -67,6 +67,7 @@ public int availablePermits(){
/**
* Define a count of the number of available permits.
*/
- // TODO - you fill in here
+ // TODO - you fill in here. Make sure that this data member will
+ // ensure its values aren't cached by multiple Threads..
}
From 98cfa93a1497ff072887386de470fdff550cbd0e Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sat, 24 May 2014 21:21:49 -0500
Subject: [PATCH 039/202] Moved the data members to the beginning of the
SimpleSemaphore class to be consistent with the other classes in other
assignments.
---
.../src/edu/vuum/mocca/SimpleSemaphore.java | 34 +++++++++----------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
index 9911231d6..a7a6e8df6 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
@@ -13,6 +13,23 @@
* "NonFair" semaphore semantics, just liked Java Semaphores.
*/
public class SimpleSemaphore {
+ /**
+ * Define a ReentrantLock to protect the critical section.
+ */
+ // TODO - you fill in here
+
+ /**
+ * Define a ConditionObject to wait while the number of
+ * permits is 0.
+ */
+ // TODO - you fill in here
+
+ /**
+ * Define a count of the number of available permits.
+ */
+ // TODO - you fill in here. Make sure that this data member will
+ // ensure its values aren't cached by multiple Threads..
+
/**
* Constructor initialize the data members.
*/
@@ -52,22 +69,5 @@ public int availablePermits(){
// TODO - you fill in here
return 0; // You will change this value.
}
-
- /**
- * Define a ReentrantLock to protect the critical section.
- */
- // TODO - you fill in here
-
- /**
- * Define a ConditionObject to wait while the number of
- * permits is 0.
- */
- // TODO - you fill in here
-
- /**
- * Define a count of the number of available permits.
- */
- // TODO - you fill in here. Make sure that this data member will
- // ensure its values aren't cached by multiple Threads..
}
From 76d298347b6be37ea56e82b198c20162d2fbcf2f Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Sun, 25 May 2014 22:57:02 -0500
Subject: [PATCH 040/202] The assignment is now ready for release!
---
.../Assignment-Description.txt | 15 ++++---
.../src/edu/vuum/mocca/SimpleAtomicLong.java | 45 ++++++-------------
.../src/edu/vuum/mocca/SimpleSemaphore.java | 44 +++++++++---------
.../test/edu/vuum/mocca/FairnessChecker.java | 11 +++--
.../test/edu/vuum/mocca/PalantirManager.java | 6 +--
.../vuum/mocca/PalantirManagerUnitTest.java | 1 -
.../vuum/mocca/SimpleAtomicLongUnitTest.java | 2 +-
7 files changed, 53 insertions(+), 71 deletions(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index 43ffd7ae4..f3fd926c6 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -25,19 +25,20 @@ further below.
In this directory you'll find a number of files, all of which you
should read. However, the only two files you need to modify are
-SimpleAtomicLong.java and SimpleSemaphore.java, which contains the
-skeleton Java code that you'll implement by completing the "TODO - You
-fill in here" comments to provide a working solution. DO NOT CHANGE
-THE OVERALL STRUCTURE OF THE SKELETON - just fill in the "TODO - You
-fill in here" portions!!!
+SimpleAtomicLong.java and SimpleSemaphore.java in the
+src/edu/vuum/mocca directory, which contains the skeleton Java code
+that you'll implement by completing the "TODO - You fill in here"
+comments to provide a working solution. DO NOT CHANGE THE OVERALL
+STRUCTURE OF THE SKELETON - just fill in the "TODO - You fill in here"
+portions!!!
In particular, you'll need to do the following:
. Implement the SimpleAtomicLong class, which you should replace with
your solution to week-2-assignment-1, after applying any fixes
suggested by peer graders. This class is only used by the
- PalantirManagerUnitTest.java and should not be used by the
- SimpleSemaphore implementation.
+ PalantirManagerUnitTest.java and should not be used in the
+ SimpleSemaphore implementation itself.
. Implement the SimpleSemaphore class using a Java ConditionObject and
Java ReentrantLock, which are covered in these videos:
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
index 37f4d7fb4..469593ca1 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
@@ -18,32 +18,27 @@ class SimpleAtomicLong
* The value that's manipulated atomically via the methods.
*/
private long mValue;
-
+
+
/**
* The ReentrantReadWriteLock used to serialize access to mValue.
*/
// TODO - replace the null with the appropriate initialization:
- private ReentrantReadWriteLock mRWLock = null;
/**
* Creates a new SimpleAtomicLong with the given initial value.
*/
- public SimpleAtomicLong(long initialValue)
- {
- long value = 0;
+ public SimpleAtomicLong(long initialValue) {
// TODO - you fill in here
}
/**
- * @brief Gets the current value.
+ * @brief Gets the current value
*
* @returns The current value
*/
- public long get()
- {
- long value = 0;
- // TODO - you fill in here, using a readLock()
- return value;
+ public long get() {
+ // TODO - you fill in here
}
/**
@@ -51,11 +46,8 @@ public long get()
*
* @returns the updated value
*/
- public long decrementAndGet()
- {
- long value = 0;
- // TODO - you fill in here, using a writeLock()
- return value;
+ public long decrementAndGet() {
+ // TODO - you fill in here
}
/**
@@ -63,11 +55,8 @@ public long decrementAndGet()
*
* @returns the previous value
*/
- public long getAndIncrement()
- {
- long value = 0;
- // TODO - you fill in here, using a writeLock()
- return value;
+ public long getAndIncrement() {
+ // TODO - you fill in here
}
/**
@@ -75,11 +64,8 @@ public long getAndIncrement()
*
* @returns the previous value
*/
- public long getAndDecrement()
- {
- long value = 0;
- // TODO - you fill in here, using a writeLock()
- return value;
+ public long getAndDecrement() {
+ // TODO - you fill in here
}
/**
@@ -87,11 +73,8 @@ public long getAndDecrement()
*
* @returns the updated value
*/
- public long incrementAndGet()
- {
- long value = 0;
- // TODO - you fill in here, using a writeLock()
- return value;
+ public long incrementAndGet() {
+ // TODO - you fill in here
}
}
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
index a7a6e8df6..581f2eb99 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
@@ -6,11 +6,10 @@
/**
* @class SimpleSemaphore
- *
- * @brief This class provides a simple counting semaphore
- * implementation using Java a ReentrantLock and a
- * ConditionObject. It must implement both "Fair" and
- * "NonFair" semaphore semantics, just liked Java Semaphores.
+ *
+ * @brief This class provides a simple counting semaphore implementation using
+ * Java a ReentrantLock and a ConditionObject. It must implement both
+ * "Fair" and "NonFair" semaphore semantics, just liked Java Semaphores.
*/
public class SimpleSemaphore {
/**
@@ -30,44 +29,41 @@ public class SimpleSemaphore {
// TODO - you fill in here. Make sure that this data member will
// ensure its values aren't cached by multiple Threads..
- /**
- * Constructor initialize the data members.
- */
- public SimpleSemaphore (int permits,
- boolean fair)
- {
- // TODO - you fill in here
+ public SimpleSemaphore(int permits, boolean fair) {
+ // TODO - you fill in here to initialize the SimpleSemaphore,
+ // making sure to allow both fair and non-fair Semaphore
+ // semantics.
}
/**
- * Acquire one permit from the semaphore in a manner that can
- * be interrupted.
+ * Acquire one permit from the semaphore in a manner that can be
+ * interrupted.
*/
public void acquire() throws InterruptedException {
- // TODO - you fill in here
+ // TODO - you fill in here.
}
/**
- * Acquire one permit from the semaphore in a manner that
- * cannot be interrupted.
+ * Acquire one permit from the semaphore in a manner that cannot be
+ * interrupted.
*/
public void acquireUninterruptibly() {
- // TODO - you fill in here
+ // TODO - you fill in here.
}
/**
* Return one permit to the semaphore.
*/
void release() {
- // TODO - you fill in here
+ // TODO - you fill in here.
}
-
+
/**
* Return the number of permits available.
*/
- public int availablePermits(){
- // TODO - you fill in here
- return 0; // You will change this value.
+ public int availablePermits() {
+ // TODO - you fill in here by changing null to the appropriate
+ // return value.
+ return null;
}
}
-
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
index 264c857e3..2d8e1ff6a 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
@@ -7,7 +7,10 @@
* @class FairnessChecker
*
* @brief Class that attempts to check whether the SimpleSemaphore
- * implementation is "fair".
+ * implementation is "fair". It has inherent limitations, but
+ * to fix these limitations would require obtrusive
+ * instrumentation within the SimpleSemaphore implementation
+ * itself.
*/
public class FairnessChecker {
/**
@@ -19,7 +22,7 @@ public class FairnessChecker {
/**
* Initialize the FairnessChecker
*/
- public FairnessChecker(int totalEntries) {
+ public FairnessChecker(final int totalEntries) {
mEntryList = new ArrayList(totalEntries);
}
@@ -27,7 +30,7 @@ public FairnessChecker(int totalEntries) {
* Add the name of a Thread that's about to acquire the @code
* SimpleSemaphore. Assumes that Thread name are unique.
*/
- public synchronized void addNewThread(String entry) {
+ public synchronized void addNewThread(final String entry) {
mEntryList.add(entry);
}
@@ -35,7 +38,7 @@ public synchronized void addNewThread(String entry) {
* Returns true if the calling Thread's name is the same as the
* first item in the list, else false.
*/
- public synchronized boolean checkOrder(String entry) {
+ public synchronized boolean checkOrder(final String entry) {
String currentEntry = mEntryList.remove(0);
return currentEntry.equals(entry);
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
index e74f2eb11..dedf2454a 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
@@ -36,7 +36,7 @@ public class PalantirManager {
* Create a resource manager for the palantiri passed as a
* parameter.
*/
- PalantirManager(List palantiri) {
+ PalantirManager(final List palantiri) {
mMaxPalantiri = palantiri.size();
mPalantiri = palantiri;
used = new boolean[palantiri.size()];
@@ -60,7 +60,7 @@ public Palantir acquirePalantir() {
* Returns the designated @code palantir so that it's
* available for others to use.
*/
- public void releasePalantir(Palantir palantir) {
+ public void releasePalantir(final Palantir palantir) {
if (markAsUnused(palantir))
mAvailable.release();
}
@@ -83,7 +83,7 @@ protected synchronized Palantir getNextAvailablePalantir() {
/**
* Return the @code palantir back to the resource pool.
*/
- protected synchronized boolean markAsUnused(Palantir palantir) {
+ protected synchronized boolean markAsUnused(final Palantir palantir) {
// Linear search is fine for this simple demo.
for (int i = 0; i < mMaxPalantiri; ++i) {
if (palantir == mPalantiri.get(i)) {
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
index 3a43eac3e..cfc5853a3 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
@@ -8,7 +8,6 @@
import org.junit.Test;
-
/**
* @class PalantirManagerUnitTest
*
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
index 66d01c104..69895b8ac 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
@@ -9,7 +9,7 @@
* @class SimpleAtomicLongUnitTest
*
* @brief Simple unit test for the SimpleAtomicLong clas that ensures
- * the version submitted for this assignment works properly.
+ * the version submitted for this assignment works correctly.
*/
public class SimpleAtomicLongUnitTest {
@Test
From d368cd0b02b888754633118dd6061701f9917fac Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Mon, 26 May 2014 07:46:08 -0500
Subject: [PATCH 041/202] Added the grading-driver.
---
.../week-3-assignment-2/.classpath | 8 +
grading-drivers/week-3-assignment-2/.project | 17 ++
.../Assessment-Description.txt | 56 ++++
.../src/edu/vuum/mocca/SimpleAtomicLong.java | 80 ++++++
.../src/edu/vuum/mocca/SimpleSemaphore.java | 69 +++++
.../test/edu/vuum/mocca/AllTests.java | 12 +
.../test/edu/vuum/mocca/FairnessChecker.java | 47 ++++
.../test/edu/vuum/mocca/Palantir.java | 21 ++
.../test/edu/vuum/mocca/PalantirManager.java | 100 ++++++++
.../vuum/mocca/PalantirManagerUnitTest.java | 242 ++++++++++++++++++
.../vuum/mocca/SimpleAtomicLongUnitTest.java | 93 +++++++
.../vuum/mocca/SimpleSemaphoreUnitTest.java | 68 +++++
12 files changed, 813 insertions(+)
create mode 100644 grading-drivers/week-3-assignment-2/.classpath
create mode 100644 grading-drivers/week-3-assignment-2/.project
create mode 100644 grading-drivers/week-3-assignment-2/Assessment-Description.txt
create mode 100644 grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
create mode 100644 grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
create mode 100644 grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
create mode 100644 grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
create mode 100644 grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/Palantir.java
create mode 100644 grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
create mode 100644 grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
create mode 100644 grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
create mode 100644 grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
diff --git a/grading-drivers/week-3-assignment-2/.classpath b/grading-drivers/week-3-assignment-2/.classpath
new file mode 100644
index 000000000..b0e3db7ba
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/grading-drivers/week-3-assignment-2/.project b/grading-drivers/week-3-assignment-2/.project
new file mode 100644
index 000000000..93858cd16
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/.project
@@ -0,0 +1,17 @@
+
+
+ W3-A2-PalantirManager
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/grading-drivers/week-3-assignment-2/Assessment-Description.txt b/grading-drivers/week-3-assignment-2/Assessment-Description.txt
new file mode 100644
index 000000000..6cf4b3a2a
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/Assessment-Description.txt
@@ -0,0 +1,56 @@
+Week 3: Programming Assignment 2 Peer Assessment Description
+
+Due Monday, June 16th, 2014
+
+You will be asked to evaluate five other student's projects as well as
+do a self assessment of your own project. If you do not assess the
+work of others, then you will receive a 20% penalty for your solution.
+
+As you do your evaluation, please keep an open mind and focus on the
+positive. Our goal is not to find every way to deduct points over
+small deviations from the requirements or for legitimate differences
+in implementation styles, etc. Look for ways to give points when it's
+clear that the submitter has given a good faith effort to do the
+project, and when it's likely that they've succeeded.
+
+Review the submitter's source code. Since you did your own project,
+you know where the changes should be and you have a good idea of the
+kind of method calls and work flows that should be in the submitter's
+code. Remember that they may have done things differently than you
+did. That's fine.
+
+Next, get a copy of the grading driver files from
+
+https://github.com/douglascraigschmidt/POSA-14/tree/master/grading-drivers/week-3-assignment-2
+
+and copy the submitter's SimpleAtomicLong.java and
+SimpleSemaphore.java files into your IDE (which may have been given a
+random, odd name by Coursera, so you'll need to rename it) and store
+it in the src/edu/vuum/mocca/ directory. I recommend scanning the
+submitted code to ensure there are no changes other than adding the
+appropriate code as indicated by the "TODO" comments. A quick way to
+check for this automatically is to run "diff" on the original files
+and the submitted files to make sure all the changes are as expected,
+in the expected places in the code. Then make sure everything compiles
+properly in your environment. Note that the grading drivers are in a
+different location than the original skeletons to ensure that all
+submissions are tested against the "master" regression tests and
+minimize the amount of code that comes from "the wild".
+
+Once you've reviewed the code against the rubric described below
+please try to run it, walking through the steps called out in the
+grading video that we'll create in each week's "VIrtual Office Hours"
+(see item #38 in the POSA MOOC FAQ at
+http://www.coursera.org/course/posa for info on Virtual Office
+Hours). I suggest you make a fresh Eclipse workspace when doing this,
+so that the submitter's code is isolated and easily distinguishable
+from yours. One way you can do that is to select File > Open Workspace
+> Browse > New Folder. This will lead to a new, empty Eclipse
+workspace. Then you can copy that submitter's SimpleAtomicLong.java
+and SimpleSemaphore.java files into this new workspace. Also, it's
+recommended to run the submitted code a virtual machine sandbox to
+further isolate it from causing harm.
+
+And again, remember that most everyone is working very hard and
+putting in a serious effort. When in doubt, err on the side of giving
+too many points, rather than giving too few.
diff --git a/grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java b/grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
new file mode 100644
index 000000000..469593ca1
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java
@@ -0,0 +1,80 @@
+// Import the necessary Java synchronization and scheduling classes.
+
+package edu.vuum.mocca;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * @class SimpleAtomicLong
+ *
+ * @brief This class implements a subset of the
+ * java.util.concurrent.atomic.SimpleAtomicLong class using a
+ * ReentrantReadWriteLock to illustrate how they work.
+ */
+class SimpleAtomicLong
+{
+ /**
+ * The value that's manipulated atomically via the methods.
+ */
+ private long mValue;
+
+
+ /**
+ * The ReentrantReadWriteLock used to serialize access to mValue.
+ */
+ // TODO - replace the null with the appropriate initialization:
+
+ /**
+ * Creates a new SimpleAtomicLong with the given initial value.
+ */
+ public SimpleAtomicLong(long initialValue) {
+ // TODO - you fill in here
+ }
+
+ /**
+ * @brief Gets the current value
+ *
+ * @returns The current value
+ */
+ public long get() {
+ // TODO - you fill in here
+ }
+
+ /**
+ * @brief Atomically decrements by one the current value
+ *
+ * @returns the updated value
+ */
+ public long decrementAndGet() {
+ // TODO - you fill in here
+ }
+
+ /**
+ * @brief Atomically increments by one the current value
+ *
+ * @returns the previous value
+ */
+ public long getAndIncrement() {
+ // TODO - you fill in here
+ }
+
+ /**
+ * @brief Atomically decrements by one the current value
+ *
+ * @returns the previous value
+ */
+ public long getAndDecrement() {
+ // TODO - you fill in here
+ }
+
+ /**
+ * @brief Atomically increments by one the current value
+ *
+ * @returns the updated value
+ */
+ public long incrementAndGet() {
+ // TODO - you fill in here
+ }
+}
+
diff --git a/grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
new file mode 100644
index 000000000..581f2eb99
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
@@ -0,0 +1,69 @@
+package edu.vuum.mocca;
+
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.Condition;
+
+/**
+ * @class SimpleSemaphore
+ *
+ * @brief This class provides a simple counting semaphore implementation using
+ * Java a ReentrantLock and a ConditionObject. It must implement both
+ * "Fair" and "NonFair" semaphore semantics, just liked Java Semaphores.
+ */
+public class SimpleSemaphore {
+ /**
+ * Define a ReentrantLock to protect the critical section.
+ */
+ // TODO - you fill in here
+
+ /**
+ * Define a ConditionObject to wait while the number of
+ * permits is 0.
+ */
+ // TODO - you fill in here
+
+ /**
+ * Define a count of the number of available permits.
+ */
+ // TODO - you fill in here. Make sure that this data member will
+ // ensure its values aren't cached by multiple Threads..
+
+ public SimpleSemaphore(int permits, boolean fair) {
+ // TODO - you fill in here to initialize the SimpleSemaphore,
+ // making sure to allow both fair and non-fair Semaphore
+ // semantics.
+ }
+
+ /**
+ * Acquire one permit from the semaphore in a manner that can be
+ * interrupted.
+ */
+ public void acquire() throws InterruptedException {
+ // TODO - you fill in here.
+ }
+
+ /**
+ * Acquire one permit from the semaphore in a manner that cannot be
+ * interrupted.
+ */
+ public void acquireUninterruptibly() {
+ // TODO - you fill in here.
+ }
+
+ /**
+ * Return one permit to the semaphore.
+ */
+ void release() {
+ // TODO - you fill in here.
+ }
+
+ /**
+ * Return the number of permits available.
+ */
+ public int availablePermits() {
+ // TODO - you fill in here by changing null to the appropriate
+ // return value.
+ return null;
+ }
+}
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
new file mode 100644
index 000000000..325a23f41
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/AllTests.java
@@ -0,0 +1,12 @@
+package edu.vuum.mocca;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({PalantirManagerUnitTest.class,
+ SimpleAtomicLongUnitTest.class,
+ SimpleSemaphoreUnitTest.class})
+public class AllTests {
+}
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
new file mode 100644
index 000000000..2d8e1ff6a
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java
@@ -0,0 +1,47 @@
+package edu.vuum.mocca;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @class FairnessChecker
+ *
+ * @brief Class that attempts to check whether the SimpleSemaphore
+ * implementation is "fair". It has inherent limitations, but
+ * to fix these limitations would require obtrusive
+ * instrumentation within the SimpleSemaphore implementation
+ * itself.
+ */
+public class FairnessChecker {
+ /**
+ * List of the waiting Threads, which are stored in FIFO order to
+ * see if the SimpleSemaphore implementation is "fair".
+ */
+ private List mEntryList;
+
+ /**
+ * Initialize the FairnessChecker
+ */
+ public FairnessChecker(final int totalEntries) {
+ mEntryList = new ArrayList(totalEntries);
+ }
+
+ /**
+ * Add the name of a Thread that's about to acquire the @code
+ * SimpleSemaphore. Assumes that Thread name are unique.
+ */
+ public synchronized void addNewThread(final String entry) {
+ mEntryList.add(entry);
+ }
+
+ /**
+ * Returns true if the calling Thread's name is the same as the
+ * first item in the list, else false.
+ */
+ public synchronized boolean checkOrder(final String entry) {
+ String currentEntry = mEntryList.remove(0);
+
+ return currentEntry.equals(entry);
+ }
+}
+
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/Palantir.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/Palantir.java
new file mode 100644
index 000000000..1ecd8d2bd
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/Palantir.java
@@ -0,0 +1,21 @@
+package edu.vuum.mocca;
+/**
+ * @class Palantir
+ *
+ * @brief Provides an interface for gazing into a Palantir.
+ * Essentially plays the role of a "command" in the Command
+ * pattern.
+ */
+
+interface Palantir {
+ /**
+ * Gaze into the Palantir (and go into a tranc ;-)).
+ */
+ public void gaze();
+
+ /**
+ * Return the name of the Palantir.
+ */
+ public String name();
+}
+
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
new file mode 100644
index 000000000..dedf2454a
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java
@@ -0,0 +1,100 @@
+package edu.vuum.mocca;
+
+import java.util.List;
+
+/**
+ * @class PalantirManager
+ *
+ * @brief Uses a "fair" Semaphore to control access to the
+ * available Palantiri. Implements the "Pooling" pattern
+ * in POSA3.
+ */
+public class PalantirManager {
+ /**
+ * Max number of Palantiri available.
+ */
+ private int mMaxPalantiri = 0;
+
+ /**
+ * Simple implementation of a Semaphore that can be configured
+ * to use the "fair" policy.
+ */
+ private SimpleSemaphore mAvailable = null;
+
+ /**
+ * List of the available Palantiri.
+ */
+ protected List mPalantiri = null;
+
+ /**
+ * Keeps track of the Palantiri that are available for use.
+ * The indices in this array mirror the list of mPanatiri.
+ */
+ protected boolean[] used = null;
+
+ /**
+ * Create a resource manager for the palantiri passed as a
+ * parameter.
+ */
+ PalantirManager(final List palantiri) {
+ mMaxPalantiri = palantiri.size();
+ mPalantiri = palantiri;
+ used = new boolean[palantiri.size()];
+
+ /**
+ * Use the "fair" policy.
+ */
+ mAvailable = new SimpleSemaphore(mMaxPalantiri, true);
+ }
+
+ /**
+ * Get the next available Palantir from the resource pool,
+ * blocking until one is available.
+ */
+ public Palantir acquirePalantir() {
+ mAvailable.acquireUninterruptibly();
+ return getNextAvailablePalantir();
+ }
+
+ /**
+ * Returns the designated @code palantir so that it's
+ * available for others to use.
+ */
+ public void releasePalantir(final Palantir palantir) {
+ if (markAsUnused(palantir))
+ mAvailable.release();
+ }
+
+ /**
+ * Get the next available Palantir from the resource pool.
+ */
+ protected synchronized Palantir getNextAvailablePalantir() {
+ // Linear search is fine for this simple demo.
+ for (int i = 0; i < mMaxPalantiri; ++i) {
+ if (!used[i]) {
+ used[i] = true;
+ return mPalantiri.get(i);
+ }
+ }
+ // Not reached unless something really weird happens..
+ return null;
+ }
+
+ /**
+ * Return the @code palantir back to the resource pool.
+ */
+ protected synchronized boolean markAsUnused(final Palantir palantir) {
+ // Linear search is fine for this simple demo.
+ for (int i = 0; i < mMaxPalantiri; ++i) {
+ if (palantir == mPalantiri.get(i)) {
+ if (used[i]) {
+ used[i] = false;
+ return true;
+ } else
+ return false;
+ }
+ }
+ return false;
+ }
+}
+
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
new file mode 100644
index 000000000..cfc5853a3
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
@@ -0,0 +1,242 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.junit.Test;
+
+/**
+ * @class PalantirManagerUnitTest
+ *
+ * @brief This program tests that student implementations of
+ * SimpleAtomicLong and SimpleSemaphore correctly implement a
+ * resource manager that limits the number of Beings from
+ * Middle-Earth who can concurrently gaze into a Palantir (see
+ * http://en.wikipedia.org/wiki/Palantir for more information
+ * on Palantirs if you're not a Lord of the Ring's fan yet
+ * ;-)).
+ */
+public class PalantirManagerUnitTest {
+ /**
+ * If this is set to true in SynchronizedQueueImpl.java then lots
+ * of debugging output will be generated.
+ */
+ public static boolean diagnosticsEnabled = false;
+
+ /**
+ * Total number of times each Palantir user gets to gaze into a
+ * Palantir.
+ */
+ final static int mMaxPalantirSessions = 5;
+
+ /**
+ * Total number of active Threads.
+ */
+ static volatile long mMaxActiveThreads = 0;
+
+ /**
+ * Count of the number of Active Threads.
+ */
+ static SimpleAtomicLong mActiveThreads = new SimpleAtomicLong(0);
+
+ /**
+ * Resource Manager that controls access to the available
+ * Palantiri.
+ */
+ static PalantirManager mPalantirManager = null;
+
+ /**
+ * Object that attempts to check whether the Semaphore
+ * implementation is "fair".
+ */
+ static FairnessChecker mFairnessChecker = null;
+
+ /**
+ * Runnable passed to each Thread that uses a Palantir.
+ */
+ static Runnable usePalantir = new Runnable() {
+ /**
+ * This is the main loop run by each Being of Middle-Earth
+ * who wants to gaze into a Palantir.
+ */
+ public void run() {
+ // Bound the total number of times that each user can
+ // gaze into a Palantir.
+ for (int i = 0; i < mMaxPalantirSessions; ++i) {
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is acquiring the palantir");
+
+ // Used to check for Semaphore fairness.
+ mFairnessChecker.addNewThread(Thread.currentThread().getName());
+
+ // Get access to a Palantir, which will block if
+ // all the available Palantiri are in use.
+ Palantir palantir = mPalantirManager.acquirePalantir();
+
+ // There's a race condition here since it's
+ // possible for one thread to call
+ // mFairnessChecker.addNewThread() and then yield
+ // to another thread which again calls
+ // mFairnessChecker.addNewThread() and then goes
+ // on without interruption to call
+ // mPalantirManager.acquirePalantir(), which will
+ // fool the fairness checker into wrongly thinking
+ // the acquisition wasn't fair. we'll just give a
+ // warning (rather than an error) if it looks like
+ // the semaphore acquire() method isn't "fair".
+ if (!mFairnessChecker.checkOrder(Thread.currentThread()
+ .getName())) {
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + ": warning, semaphore acquire may not be fair");
+ }
+
+ // Ensure that the Semaphore implementation is
+ // correctly limiting the number of Palantir
+ // gazers.
+ long activeThreads = mActiveThreads.getAndIncrement();
+ if (mMaxActiveThreads < activeThreads) {
+ System.out.println("too many threads = "
+ + activeThreads);
+ throw new RuntimeException();
+ }
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is starting to gaze at the "
+ + palantir.name()
+ + " palantir");
+
+ // Gaze at the Palantir for the time alloted in
+ // the command.
+ palantir.gaze();
+
+ // Indicate this Being is no longer using the
+ // Palantir.
+ mActiveThreads.decrementAndGet();
+
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is finished gazing at the "
+ + palantir.name()
+ + " palantir");
+
+ // Return the Palantir back to the shared pool so
+ // other Beings can gaze at it.
+ mPalantirManager.releasePalantir(palantir);
+
+ if (diagnosticsEnabled)
+ System.out.println(Thread.currentThread().getName()
+ + " is releasing the "
+ + palantir.name()
+ + " palantir");
+ }
+
+ }
+ };
+
+ /**
+ * This factory creates a list of Palantiri.
+ */
+ static List makePalantiri() {
+ List palantiri = new ArrayList();
+
+ // MinasTirith Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ }
+ public String name() {
+ return "MinasTirith";
+ }
+ });
+ // Orthanc Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ Thread.sleep(150);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public String name() {
+ return "Orthanc";
+ }
+ });
+ // Barad-dur Palantir
+ palantiri.add(new Palantir() {
+ public void gaze() {
+ try {
+ // The unblinking eye gazes for a long time
+ // ;-)
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ public String name() {
+ return "Barad-dur";
+ }
+ });
+
+ return palantiri;
+ }
+
+ @Test
+ public void testPalantirManager() {
+ try {
+ if (diagnosticsEnabled)
+ System.out.println("Starting PalantirManagerTest");
+
+ // Get the list of available Palantiri.
+ List palantiri =
+ PalantirManagerUnitTest.makePalantiri();
+
+ // Limit the number of users (threads) that can gaze into
+ // the available Palantiri.
+ mMaxActiveThreads = palantiri.size();
+
+ // Create a resource manager that control access to the
+ // available Palantiri.
+ mPalantirManager = new PalantirManager(palantiri);
+
+ // Create a list of Middle-Earth Beings who want to use
+ // the Palantir.
+ List palantirUsers = new ArrayList();
+ palantirUsers.add(new Thread(usePalantir, "Pippen"));
+ palantirUsers.add(new Thread(usePalantir, "Aragorn"));
+ palantirUsers.add(new Thread(usePalantir, "Denathor"));
+ palantirUsers.add(new Thread(usePalantir, "Sauron"));
+ palantirUsers.add(new Thread(usePalantir, "Saruman"));
+
+ // Create an object that attempts to check whether the
+ // Semaphore implementation is "fair".
+ mFairnessChecker = new FairnessChecker(palantirUsers.size());
+
+ // Start all the Threads that Middle-Earth Beings use to
+ // gaze into the Palantir.
+ for (ListIterator iterator = palantirUsers.listIterator();
+ iterator.hasNext();)
+ iterator.next().start();
+
+ // Barrier synchronization that waits for all the Threads
+ // to exit.
+ for (ListIterator iterator = palantirUsers.listIterator(); iterator
+ .hasNext();)
+ iterator.next().join();
+
+ if (diagnosticsEnabled)
+ System.out.println("Finishing PalantirManagerTest");
+ } catch (Exception e) {
+ fail("The Exception "
+ + e.getMessage()
+ + " was thrown");
+ }
+ }
+
+}
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
new file mode 100644
index 000000000..69895b8ac
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java
@@ -0,0 +1,93 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+
+/**
+ * @class SimpleAtomicLongUnitTest
+ *
+ * @brief Simple unit test for the SimpleAtomicLong clas that ensures
+ * the version submitted for this assignment works correctly.
+ */
+public class SimpleAtomicLongUnitTest {
+ @Test
+ public void testSimpleAtomicLong() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertNotNull(testLong);
+ }
+
+ @Test
+ public void testGet() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.get(), 0);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.get(), 100);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.get(), -100);
+ }
+
+ @Test
+ public void testDecrementAndGet() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.decrementAndGet(), -1);
+ assertEquals(testLong.get(), -1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.decrementAndGet(), 99);
+ assertEquals(testLong2.get(), 99);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.decrementAndGet(), -101);
+ assertEquals(testLong3.get(), -101);
+ }
+
+ @Test
+ public void testIncrementAndGet() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.incrementAndGet(), 1);
+ assertEquals(testLong.get(), 1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.incrementAndGet(), 101);
+ assertEquals(testLong2.get(), 101);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.incrementAndGet(), -99);
+ assertEquals(testLong3.get(), -99);
+ }
+
+ @Test
+ public void testGetAndIncrement() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.getAndIncrement(), 0);
+ assertEquals(testLong.get(), 1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.getAndIncrement(), 100);
+ assertEquals(testLong2.get(), 101);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.getAndIncrement(), -100);
+ assertEquals(testLong3.get(), -99);
+ }
+
+ @Test
+ public void testGetAndDecrement() {
+ SimpleAtomicLong testLong = new SimpleAtomicLong(0);
+ assertEquals(testLong.getAndDecrement(), 0);
+ assertEquals(testLong.get(), -1);
+
+ SimpleAtomicLong testLong2 = new SimpleAtomicLong(100);
+ assertEquals(testLong2.getAndDecrement(), 100);
+ assertEquals(testLong2.get(), 99);
+
+ SimpleAtomicLong testLong3 = new SimpleAtomicLong(-100);
+ assertEquals(testLong3.getAndDecrement(), -100);
+ assertEquals(testLong3.get(), -101);
+ }
+
+}
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
new file mode 100644
index 000000000..8cdd59390
--- /dev/null
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/SimpleSemaphoreUnitTest.java
@@ -0,0 +1,68 @@
+package edu.vuum.mocca;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.concurrent.Semaphore;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @class SimpleSemaphoreUnitTest
+ *
+ * @brief Simple unit test for the SimpleSemaphore that just tests
+ * single-threaded logic.
+ */
+public class SimpleSemaphoreUnitTest {
+ @Test
+ public void testSimpleSemaphore() {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertNotNull(simpleSemaphore);
+ }
+
+ @Test
+ public void testAcquire() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 0);
+ }
+
+ @Test
+ public void testAcquireUninterruptibly() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquireUninterruptibly();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.acquireUninterruptibly();
+ assertEquals(simpleSemaphore.availablePermits(), 0);
+ }
+
+ @Test
+ public void testRelease() throws InterruptedException {
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 0);
+ simpleSemaphore.release();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ simpleSemaphore.release();
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ }
+
+ @Test
+ public void testAvailablePermits() throws InterruptedException{
+ SimpleSemaphore simpleSemaphore = new SimpleSemaphore(2, true);
+ assertEquals(simpleSemaphore.availablePermits(), 2);
+ simpleSemaphore.acquire();
+ assertEquals(simpleSemaphore.availablePermits(), 1);
+ }
+}
From 731a656e4ea8c21e21c6b85c15ee5c867f551d59 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Mon, 26 May 2014 09:47:57 -0500
Subject: [PATCH 042/202] Changed project name.
---
grading-drivers/week-3-assignment-2/.project | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grading-drivers/week-3-assignment-2/.project b/grading-drivers/week-3-assignment-2/.project
index 93858cd16..80621e3a8 100644
--- a/grading-drivers/week-3-assignment-2/.project
+++ b/grading-drivers/week-3-assignment-2/.project
@@ -1,6 +1,6 @@
- W3-A2-PalantirManager
+ W3-A2-PalantirManager-Grading
From dad43a8b8d6e5a2d2135a5901ff4e4db777c952f Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Mon, 26 May 2014 12:43:02 -0500
Subject: [PATCH 043/202] Fixed a mistake.
---
.../test/edu/vuum/mocca/PalantirManagerUnitTest.java | 4 ++--
.../test/edu/vuum/mocca/PalantirManagerUnitTest.java | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
index cfc5853a3..45b65c501 100644
--- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
+++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
@@ -21,8 +21,8 @@
*/
public class PalantirManagerUnitTest {
/**
- * If this is set to true in SynchronizedQueueImpl.java then lots
- * of debugging output will be generated.
+ * If this is set to true in then lots of debugging output will be
+ * generated.
*/
public static boolean diagnosticsEnabled = false;
diff --git a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
index cfc5853a3..1b94ef779 100644
--- a/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
+++ b/grading-drivers/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java
@@ -21,8 +21,8 @@
*/
public class PalantirManagerUnitTest {
/**
- * If this is set to true in SynchronizedQueueImpl.java then lots
- * of debugging output will be generated.
+ * If this is set to true then lots of debugging output will be
+ * generated.
*/
public static boolean diagnosticsEnabled = false;
From 7e1400b02a86eea25347038b8ee11c9c43b68a47 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Mon, 26 May 2014 14:46:16 -0500
Subject: [PATCH 044/202] Fixed typo.
---
assignments/week-3-assignment-2/Assignment-Description.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index f3fd926c6..17ee16d68 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -6,7 +6,7 @@ Due Monday, June 9th, 2014
In this assignment, you will use a Java ReentrantLock and Java
ConditionObject to implement a subset of the Java
java.util.concurrent.Semaphore class, which we call SimpleSemaphore.
-This assignment also reuses the SimpleAtomicLock you implemented for
+This assignment also reuses the SimpleAtomicLong you implemented for
week-2-assignment-1, so make sure it's compiling and running properly
before attempting this assignment!
@@ -19,7 +19,7 @@ Palantirs if you're not yet a fan of Tolkein's Lord of the Ring's.
The PalantirManagerUnitTest.java program creates three Palantiri and
five Threads (one for each Palantir user) that concurrently attempt to
acquire a Palantir and gaze into it for a certain amount of time. If
-the SimpleSemaphore and SimpleAtomicLock are implemented properly the
+the SimpleSemaphore and SimpleAtomicLong are implemented properly the
test should succeed without throwing any exceptions, as described
further below.
From 9fa7366c7c3692536337dd67882c6f34f33788b5 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 28 May 2014 13:38:47 -0500
Subject: [PATCH 045/202] Changed 12 to 24 to reflect the proper number of unit
tests.
---
assignments/week-3-assignment-2/Assignment-Description.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index 17ee16d68..08bf53599 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -89,7 +89,7 @@ should disappear!
Right click on the test suite (AllTests.java) or an individual
*_UnitTest.java file in Eclipse and select 'Run As' -> 'JUnit
-Test'. When the assignment is complete, 12 of 12 tests should complete
+Test'. When the assignment is complete, 24 of 24 tests should complete
successfully. If a test passes a green-check mark will appear next to
the test in the JUnit view. As long as this JUnit test "passes"
successfully your program will be be consider "correct" for the
From 14adb0eed4046746e9847e1ce9fc0af58703a16e Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 28 May 2014 14:02:02 -0500
Subject: [PATCH 046/202] Improved discussion of ConditionObject vs. Condition.
---
.../week-3-assignment-2/Assignment-Description.txt | 5 +++--
.../src/edu/vuum/mocca/SimpleSemaphore.java | 11 ++++++-----
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt
index 08bf53599..f2e68a8f7 100644
--- a/assignments/week-3-assignment-2/Assignment-Description.txt
+++ b/assignments/week-3-assignment-2/Assignment-Description.txt
@@ -40,8 +40,9 @@ In particular, you'll need to do the following:
PalantirManagerUnitTest.java and should not be used in the
SimpleSemaphore implementation itself.
-. Implement the SimpleSemaphore class using a Java ConditionObject and
- Java ReentrantLock, which are covered in these videos:
+. Implement the SimpleSemaphore class using a Java ConditionObject
+ (accessed via a Condition) and Java ReentrantLock, which are covered
+ in these videos:
Section 1: Module 2: Part 5: Java ReentrantLock
Section 1: Module 2: Part 8: Java ConditionObject
diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
index 581f2eb99..4ecaf30c5 100644
--- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
+++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java
@@ -7,9 +7,11 @@
/**
* @class SimpleSemaphore
*
- * @brief This class provides a simple counting semaphore implementation using
- * Java a ReentrantLock and a ConditionObject. It must implement both
- * "Fair" and "NonFair" semaphore semantics, just liked Java Semaphores.
+ * @brief This class provides a simple counting semaphore
+ * implementation using Java a ReentrantLock and a
+ * ConditionObject (which is accessed via a Condition). It must
+ * implement both "Fair" and "NonFair" semaphore semantics,
+ * just liked Java Semaphores.
*/
public class SimpleSemaphore {
/**
@@ -18,8 +20,7 @@ public class SimpleSemaphore {
// TODO - you fill in here
/**
- * Define a ConditionObject to wait while the number of
- * permits is 0.
+ * Define a Condition that waits while the number of permits is 0.
*/
// TODO - you fill in here
From a9caabd71074fabf4274feaf3ff2a0fb763c3826 Mon Sep 17 00:00:00 2001
From: Sigmund Hansen
Date: Thu, 29 May 2014 00:58:51 +0200
Subject: [PATCH 047/202] Make constants final
Constants should be marked as final. Here two constant values are used as enumerations of possible states, but are not declared final. This is bad practice, as it would allow the programmer to do stupid things like change the meaning of the current state, which could lead to errors.
---
.../src/edu/vuum/mocca/PingPongActivity.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PingPongActivity.java b/assignments/week-5-assignment-4/src/edu/vuum/mocca/PingPongActivity.java
index 4296cd074..7b9a0573c 100644
--- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PingPongActivity.java
+++ b/assignments/week-5-assignment-4/src/edu/vuum/mocca/PingPongActivity.java
@@ -20,8 +20,8 @@ public class PingPongActivity extends Activity
private Button mPlayButton;
/** Variables to track state of the game */
- private static int PLAY = 0;
- private static int RESET = 1;
+ private static final int PLAY = 0;
+ private static final int RESET = 1;
private int mGameState = PLAY;
protected void onCreate(Bundle savedInstanceState)
From 45859d45fd963122c68b916c4fa9b406a31d6801 Mon Sep 17 00:00:00 2001
From: douglascraigschmidt
Date: Wed, 28 May 2014 22:16:47 -0500
Subject: [PATCH 048/202] Added the first cut of the DownloadApplication.
---
ex/DownloadApplication/.classpath | 9 +
ex/DownloadApplication/.project | 33 ++
ex/DownloadApplication/AndroidManifest.xml | 34 ++
ex/DownloadApplication/project.properties | 15 +
.../res/drawable-hdpi/default_image.png | Bin 0 -> 160737 bytes
.../res/drawable-hdpi/ic_action_search.png | Bin 0 -> 3120 bytes
.../res/drawable-hdpi/ic_launcher.png | Bin 0 -> 429851 bytes
.../res/drawable-ldpi/ic_icon.png | Bin 0 -> 160737 bytes
.../res/drawable-ldpi/ic_launcher.png | Bin 0 -> 429851 bytes
.../res/drawable-mdpi/default_image.png | Bin 0 -> 160737 bytes
.../res/drawable-mdpi/ic_action_search.png | Bin 0 -> 3030 bytes
.../res/drawable-mdpi/ic_launcher.png | Bin 0 -> 429851 bytes
.../res/drawable-xhdpi/default_image.png | Bin 0 -> 160737 bytes
.../res/drawable-xhdpi/ic_action_search.png | Bin 0 -> 3199 bytes
.../res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 429851 bytes
ex/DownloadApplication/res/layout/main.xml | 56 ++++
ex/DownloadApplication/res/menu/options.xml | 10 +
.../res/values-v11/styles.xml | 5 +
.../res/values-v14/styles.xml | 5 +
ex/DownloadApplication/res/values/strings.xml | 11 +
ex/DownloadApplication/res/values/styles.xml | 5 +
.../src/edu/vuum/mocca/DownloadActivity.java | 253 +++++++++++++++
.../src/edu/vuum/mocca/DownloadService.java | 294 ++++++++++++++++++
.../src/edu/vuum/mocca/ThreadedDownloads.java | 7 +-
24 files changed, 733 insertions(+), 4 deletions(-)
create mode 100644 ex/DownloadApplication/.classpath
create mode 100644 ex/DownloadApplication/.project
create mode 100644 ex/DownloadApplication/AndroidManifest.xml
create mode 100644 ex/DownloadApplication/project.properties
create mode 100644 ex/DownloadApplication/res/drawable-hdpi/default_image.png
create mode 100644 ex/DownloadApplication/res/drawable-hdpi/ic_action_search.png
create mode 100644 ex/DownloadApplication/res/drawable-hdpi/ic_launcher.png
create mode 100644 ex/DownloadApplication/res/drawable-ldpi/ic_icon.png
create mode 100644 ex/DownloadApplication/res/drawable-ldpi/ic_launcher.png
create mode 100644 ex/DownloadApplication/res/drawable-mdpi/default_image.png
create mode 100644 ex/DownloadApplication/res/drawable-mdpi/ic_action_search.png
create mode 100644 ex/DownloadApplication/res/drawable-mdpi/ic_launcher.png
create mode 100644 ex/DownloadApplication/res/drawable-xhdpi/default_image.png
create mode 100644 ex/DownloadApplication/res/drawable-xhdpi/ic_action_search.png
create mode 100644 ex/DownloadApplication/res/drawable-xhdpi/ic_launcher.png
create mode 100644 ex/DownloadApplication/res/layout/main.xml
create mode 100644 ex/DownloadApplication/res/menu/options.xml
create mode 100644 ex/DownloadApplication/res/values-v11/styles.xml
create mode 100644 ex/DownloadApplication/res/values-v14/styles.xml
create mode 100644 ex/DownloadApplication/res/values/strings.xml
create mode 100644 ex/DownloadApplication/res/values/styles.xml
create mode 100644 ex/DownloadApplication/src/edu/vuum/mocca/DownloadActivity.java
create mode 100644 ex/DownloadApplication/src/edu/vuum/mocca/DownloadService.java
diff --git a/ex/DownloadApplication/.classpath b/ex/DownloadApplication/.classpath
new file mode 100644
index 000000000..c06dfcb8e
--- /dev/null
+++ b/ex/DownloadApplication/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/ex/DownloadApplication/.project b/ex/DownloadApplication/.project
new file mode 100644
index 000000000..77a3cfad5
--- /dev/null
+++ b/ex/DownloadApplication/.project
@@ -0,0 +1,33 @@
+
+
+ DownloadApplication
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/ex/DownloadApplication/AndroidManifest.xml b/ex/DownloadApplication/AndroidManifest.xml
new file mode 100644
index 000000000..788813499
--- /dev/null
+++ b/ex/DownloadApplication/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ex/DownloadApplication/project.properties b/ex/DownloadApplication/project.properties
new file mode 100644
index 000000000..4e8c167ac
--- /dev/null
+++ b/ex/DownloadApplication/project.properties
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17
+
diff --git a/ex/DownloadApplication/res/drawable-hdpi/default_image.png b/ex/DownloadApplication/res/drawable-hdpi/default_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..956613eba1f5ddb75004ef4752ce18b5f1e55822
GIT binary patch
literal 160737
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 |