Index: src/Fragmentation/Automation/FragmentScheduler.cpp
===================================================================
--- src/Fragmentation/Automation/FragmentScheduler.cpp	(revision e8f397a97a39bc8a8ad9a4baf1c7c2958cdc74aa)
+++ src/Fragmentation/Automation/FragmentScheduler.cpp	(revision 2344a30f31c0fe3d7ef97b7598871abb375747d2)
@@ -34,4 +34,6 @@
 #include "CodePatterns/Info.hpp"
 #include "CodePatterns/Log.hpp"
+#include "CodePatterns/Observer/Notification.hpp"
+#include "ControllerChoices.hpp"
 #include "Controller/Commands/EnrollInPoolOperation.hpp"
 #include "Jobs/MPQCCommandJob.hpp"
@@ -41,5 +43,5 @@
 #include "FragmentScheduler.hpp"
 
-FragmentJob::ptr FragmentScheduler::WorkerListener_t::NoJob(new SystemCommandJob(std::string("/bin/true"), std::string("dosomething"), JobId::NoJob));
+FragmentJob::ptr FragmentScheduler::NoJob(new SystemCommandJob(std::string(""), std::string(""), JobId::NoJob));
 
 /** Helper function to enforce binding of FragmentWorker to possible derived
@@ -59,21 +61,32 @@
  * \param controllerport port to listen for controller connections.
  */
-FragmentScheduler::FragmentScheduler(boost::asio::io_service& io_service, unsigned short workerport, unsigned short controllerport) :
-    WorkerListener(io_service, workerport, JobsQueue, pool,
+FragmentScheduler::FragmentScheduler(boost::asio::io_service& _io_service, unsigned short workerport, unsigned short controllerport) :
+    Observer("FragmentScheduler"),
+    io_service(_io_service),
+    WorkerListener(_io_service, workerport, JobsQueue, pool,
         boost::bind(&FragmentScheduler::sendJobToWorker, boost::ref(*this), _1, _2)),
-    ControllerListener(io_service, controllerport, JobsQueue,
-        boost::bind(&Listener::initiateSocket, boost::ref(WorkerListener))),
-    connection(io_service),
+    ControllerListener(_io_service, controllerport, JobsQueue,
+        boost::bind(&FragmentScheduler::shutdown, boost::ref(*this))),
+    connection(_io_service),
     sendJobOp(connection)
 {
   Info info(__FUNCTION__);
+
+  // sign on to idle workers and present jobs
+  pool.signOn(this, WorkerPool::WorkerIdle);
+  JobsQueue.signOn(this, FragmentQueue::JobAdded);
 
   // listen for controller
   ControllerListener.initiateSocket();
 
-  // only initiate socket if jobs are already present
-  if (JobsQueue.isJobPresent()) {
-    WorkerListener.initiateSocket();
-  }
+  // listen for workers
+  WorkerListener.initiateSocket();
+}
+
+FragmentScheduler::~FragmentScheduler()
+{
+  // sign off
+  pool.signOff(this, WorkerPool::WorkerIdle);
+  JobsQueue.signOff(this, FragmentQueue::JobAdded);
 }
 
@@ -208,4 +221,6 @@
     // restore NoOperation choice such that choice is not read twice
     choice = NoWorkerOperation;
+
+    initiateSocket();
   }
   else
@@ -217,10 +232,4 @@
     ELOG(0, e.message());
   }
-
-  if (JobsQueue.isJobPresent()) {
-    // Start an accept operation for a new Connection only when there
-    // are still jobs present
-    initiateSocket();
-  }
 }
 
@@ -234,12 +243,5 @@
 {
   Info info(__FUNCTION__);
-  if (!e)
-  {
-    if (JobsQueue.isJobPresent()) {
-      FragmentJob::ptr job = JobsQueue.popJob();
-      callback_sendJobToWorker(pool.getNextIdleWorker(), job);
-    }
-  }
-  else
+  if (e)
   {
     // An error occurred. Log it and return. Since we are not starting a new
@@ -276,10 +278,4 @@
   result.reset();
   LOG(1, "INFO: JobsQueue has " << JobsQueue.getDoneJobs() << " results.");
-
-  // send out new job if present
-  if (JobsQueue.isJobPresent()) {
-    FragmentJob::ptr job = JobsQueue.popJob();
-    callback_sendJobToWorker(pool.getNextIdleWorker(), job);
-  }
 }
 
@@ -412,4 +408,7 @@
       // Start an accept operation for a new Connection.
       initiateSocket();
+    } else {
+      // we shutdown? Hence, also shutdown controller
+      shutdownAllSockets();
     }
   }
@@ -436,6 +435,4 @@
 {
   Info info(__FUNCTION__);
-  bool need_initiateSocket = !JobsQueue.isJobPresent();
-
   // jobs are received, hence place in JobsQueue
   if (!jobs.empty()) {
@@ -443,10 +440,5 @@
     JobsQueue.pushJobs(jobs);
   }
-
   jobs.clear();
-
-  // initiate socket if we had no jobs before
-  if (need_initiateSocket)
-    initiateWorkerSocket();
 }
 
@@ -504,24 +496,90 @@
 }
 
-///** Helper function to shutdown a single worker.
-// *
-// * We send NoJob to indicate shutdown
-// *
-// * @param address of worker to shutdown
-// */
-//void FragmentScheduler::shutdownWorker(const WorkerAddress &address)
-//{
-//  sendJobToWorker(address, NoJob);
-//}
-//
-///** Sends shutdown to all current workers in the pool.
-// *
-// */
-//void FragmentScheduler::removeAllWorkers()
-//{
-//  // give all workers shutdown signal
-//  while (pool.presentIdleWorkers()) {
-//    const WorkerAddress address = pool.getNextIdleWorker();
-//    shutdownWorker(address);
-//  }
-//}
+/** Helper function to shutdown a single worker.
+ *
+ * We send NoJob to indicate shutdown
+ *
+ * @param address of worker to shutdown
+ */
+void FragmentScheduler::shutdownWorker(const WorkerAddress &address)
+{
+  LOG(3, "DEBUG: Shutting down worker " << address << "...");
+  sendJobToWorker(address, NoJob);
+}
+
+/** Sends shutdown to all current workers in the pool.
+ *
+ */
+void FragmentScheduler::removeAllWorkers()
+{
+  LOG(2, "INFO: Shutting down workers ...");
+
+  // give all workers shutdown signal
+  while (pool.presentIdleWorkers()) {
+    const WorkerAddress address = pool.getNextIdleWorker();
+    shutdownWorker(address);
+  }
+}
+
+/** Helper function to shutdown the server properly.
+ *
+ * \todo one should idle here until all workers have returned from
+ * calculating stuff (or workers need to still listen while the are
+ * calculating which is probably better).
+ *
+ */
+void FragmentScheduler::shutdown()
+{
+  LOG(1, "INFO: Shutting all down ...");
+
+  /// Remove all workers
+  removeAllWorkers();
+
+  /// close the worker listener's socket
+  WorkerListener.closeSocket();
+
+  /// close the controller listener's socket
+  ControllerListener.closeSocket();
+
+  /// finally, stop the io_service
+  io_service.stop();
+}
+
+/** Internal helper to send the next available job to the next idle worker.
+ *
+ */
+void FragmentScheduler::sendAvailableJobToNextIdleWorker()
+{
+  const WorkerAddress address = pool.getNextIdleWorker();
+  FragmentJob::ptr job = JobsQueue.popJob();
+  sendJobToWorker(address, job);
+}
+
+void FragmentScheduler::update(Observable *publisher)
+{
+  ASSERT(0, "FragmentScheduler::update() - we are not signed on for global updates.");
+}
+
+void FragmentScheduler::recieveNotification(Observable *publisher, Notification_ptr notification)
+{
+  // we have an idle worker
+  if ((publisher == &pool) && (notification->getChannelNo() == WorkerPool::WorkerIdle)) {
+    LOG(1, "INFO: We are notified of an idle worker.");
+    // are jobs available?
+    if (JobsQueue.isJobPresent()) {
+      sendAvailableJobToNextIdleWorker();
+    }
+  }
+
+  // we have new jobs
+  if ((publisher == &JobsQueue) && (notification->getChannelNo() == FragmentQueue::JobAdded)) {
+    LOG(1, "INFO: We are notified of a new job.");
+    // check for idle workers
+    if (pool.presentIdleWorkers()) {
+      sendAvailableJobToNextIdleWorker();
+    }
+  }
+}
+
+void FragmentScheduler::subjectKilled(Observable *publisher)
+{}
