<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,25 +0,0 @@
-History.txt
-License.txt
-Manifest.txt
-PostInstall.txt
-README.txt
-Rakefile
-config/hoe.rb
-config/requirements.rb
-lib/ermarb.rb
-lib/ermarb/version.rb
-script/console
-script/destroy
-script/generate
-script/txt2html
-setup.rb
-tasks/deployment.rake
-tasks/environment.rake
-tasks/website.rake
-test/test_ermarb.rb
-test/test_helper.rb
-website/index.html
-website/index.txt
-website/javascripts/rounded_corners_lite.inc.js
-website/stylesheets/screen.css
-website/template.html.erb</diff>
      <filename>Manifest.txt</filename>
    </modified>
    <modified>
      <diff>@@ -4,22 +4,112 @@ module Erma
   class MonitoringEngine
     include Singleton
 
-     # Starts up the monitoring engine. This method should be called before
-     # using ERMA.
-     #
-     # This call initializes the system and calls startup() on the
-     # MonitorProcessorFactory supplied. Therefore, the
-     # MonitorProcessorFactory to be used should have been set prior to calling
-     # this method.
-     #
-     # *This method is not thread-safe.* Clients should take care to ensure
-     # that multithreaded access to this method is synchronized.
+    attr_accessor :processor_factory
+
+    # Starts up the monitoring engine. This method should be called before
+    # using ERMA.
+    #
+    # This call initializes the system and calls startup() on the
+    # MonitorProcessorFactory supplied. Therefore, the
+    # MonitorProcessorFactory to be used should have been set prior to calling
+    # this method.
+    #
+    # *This method is not thread-safe.* Clients should take care to ensure
+    # that multithreaded access to this method is synchronized.
     def startup
-      @enabled = true
+      raise 'processor_factory has not been set' unless processor_factory
+
+      processor_factory.startup
+
+      @running = true
+      self.enabled = true
+    end
+
+    # Shuts down the monitoring engine. This method should be called before
+    # shutting down the application to give the ERMA system a chance to cleanly
+    # close all its resources.
+    #
+    # This call disables ERMA and calls shutdown() on the
+    # MonitorProcessorFactory supplied.
+    #
+    # *This method is not thread-safe.* Client should take care to ensure
+    # that multithreaded access to this method is synchronized.
+    def shutdown
+      if running?
+        @running = false
+        processor_factory.shutdown
+        processor_factory = nil
+      end
+    end
+
+    # A lifecycle method that initializes the Monitor. All monitor
+    # implementations must call this methods before setting any attributes on
+    # themselves.
+    #
+    # After this method returns, the monitor will have had any implicitly
+    # inherited and global attributes applied.
+    def init_monitor(monitor)
+      return unless enabled?
+
+      monitor.set(:created_at, Time.now).serializable.lock
+      monitor.set(:thread_id, Thread.current.__id__).serializable.lock
+    end
+
+    # A lifecycle method that notifies observing MonitorProcessors that a new
+    # monitor has been created. All monitor implementations should call this
+    # method after setting attributes known at creation on themselves.
+    def monitor_created(monitor)
+      return unless enabled?
+      handle_monitor(monitor, :monitor_created)
     end
 
+    # A lifecylce method that notifies observing MonitorProcessors that a
+    # monitor has been started. All monitor implementations that have a
+    # start-stop concept should call this monitor at start.
+    def composite_monitor_started(monitor)
+      return unless enabled?
+      handle_monitor(monitor, :composite_monitor_started)
+    end
+
+    # A lifecycle method that notifies observing MonitorProcessors that a
+    # monitor is ready to be processed. All monitor implementations should call
+    # as the last call of their lifecycle.
+    def composite_monitor_completed(monitor)
+      return unless enabled?
+      handle_monitor(monitor, :composite_monitor_completed)
+    end
+
+    # A lifecycle method that notifies observing MonitorProcessors that a
+    # monitor is ready to be processed. All monitor implementations should call this 
+    # method as the last call of their lifecycle.
+    def process(monitor)
+      return unless enabled?
+      handle_monitor(monitor, :process)
+    end
+
+    attr_writer :enabled
     def enabled?
       @enabled
     end
+
+    def running?
+      @running
+    end
+
+    private
+    def handle_monitor(monitor, callback_method)
+      begin
+        processors = processor_factory.processors_for_monitor(monitor)
+        processors.each do |p| 
+          begin
+            p.send(callback_method, monitor) 
+          rescue Exception
+            # Swallowed
+          end
+        end
+      rescue Exception
+        # Swallowed
+      end
+    end
   end
 end</diff>
      <filename>lib/erma/monitoring_engine.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,153 @@
 require File.dirname(File.expand_path(__FILE__)) + '/spec_helper'
 
 describe Erma::MonitoringEngine do
+  before do
+    @engine = Erma::MonitoringEngine.instance
+    @engine.enabled = true
+    @engine.processor_factory = stub('MockProcessorFactory', :null_object =&gt; true)
+  end
+
+  after { @engine.shutdown }
+
   it &quot;should be enabled after startup&quot; do
-    Erma::MonitoringEngine.instance.startup
-    Erma::MonitoringEngine.instance.should be(:enabled)
+    @engine.startup
+    @engine.should be_enabled
+  end
+
+  describe &quot;without a processor_factory set&quot; do
+    before { @engine.processor_factory = nil }
+
+    it &quot;should raise an Error when startup is called&quot; do
+      lambda { @engine.startup }.should raise_error
+    end
+
+    it &quot;should not throw an error when shutdown is called afterwards&quot; do
+      lambda { @engine.startup }.should raise_error
+      @engine.shutdown
+    end
+  end
+
+  describe &quot;without a decomposer set&quot; do
+    it &quot;should raise an Error when startup is called&quot; 
+    it &quot;should not throw an error when shutdown is called afterwards&quot; 
+  end
+
+  it &quot;should call processor_factory.startup when startup is called&quot; do
+    @engine.processor_factory.should_receive(:startup)
+    @engine.startup
+  end
+
+  it &quot;should let processor_factory.startup Errors pass through to the client code&quot; do
+    @engine.processor_factory.should_receive(:startup).and_raise
+    lambda { @engine.startup }.should raise_error
+  end
+
+  it &quot;should call processor_factory.shutdown when shutdown is called&quot; do
+    @engine.startup
+    @engine.processor_factory.should_receive(:shutdown)
+    @engine.shutdown
+  end
+
+  it &quot;should let processor_factory.shutdown Errors pass through to the client code&quot; do
+    @engine.startup
+    @engine.processor_factory.should_receive(:shutdown).and_raise
+    lambda { @engine.shutdown }.should raise_error
+  end
+
+  it &quot;should not be running when processor_factory.shutdown raises an Error&quot; do
+    @engine.startup
+    @engine.processor_factory.should_receive(:shutdown).and_raise
+    lambda { @engine.shutdown }.should raise_error
+    @engine.should_not be_running
+  end
+
+  describe 'Monitor callback', :shared =&gt; true do
+    it &quot;should do nothing if not enabled&quot; do
+      # TODO suggest this as an extra test case in Java ERMA impl
+      @engine.enabled = false
+      @engine.processor_factory.should_not_receive(:processors_for_monitor)
+      @engine.send(@callback_method, mock('fake_monitor'))
+    end
+
+    it &quot;should ask the MonitorProcessorFactory for the applicable MonitorProcessors&quot; do
+      @engine.processor_factory.should_receive(:processors_for_monitor)
+      @engine.send(@callback_method, mock('fake_monitor'))
+    end
+
+    it &quot;should swallow Errors raised by MonitorProcessorFactory.processors_for_monitor&quot; do
+      @engine.processor_factory.should_receive(:processors_for_monitor).and_raise
+      @engine.send(@callback_method, mock('fake_monitor'))
+    end
+
+    it &quot;should pass the monitor to each processor's callback method&quot; do
+      mock_processors = [mock('Processor1'), mock('Processor2')]
+      mock_processors.each {|p| p.should_receive(@callback_method)}
+      @engine.processor_factory.should_receive(:processors_for_monitor).and_return(mock_processors)
+      @engine.send(@callback_method, mock('fake_monitor'))
+    end
+
+    it &quot;should isolate Exceptions raised by individual processors&quot; do
+      mock_processors = [mock('Processor1'), mock('Processor2')]
+      mock_processors[0].should_receive(@callback_method).and_raise
+      mock_processors[1].should_receive(@callback_method)
+      @engine.processor_factory.should_receive(:processors_for_monitor).and_return(mock_processors)
+      @engine.send(@callback_method, mock('fake_monitor'))
+    end
+
+    it &quot;should not raise Exceptions when receiving callbacks before being started&quot; do
+      @engine.shutdown
+      @engine.send(@callback_method, mock('fake_monitor'))
+    end
+  end
+
+  describe &quot;processing init_monitor callback&quot; do
+    before do 
+      @monitor = stub_everything('mock_monitor')
+    end
+
+    it &quot;should set the created_at attribute on the monitor as serializable and locked&quot; do
+      attr_holder = mock('attr_holder')
+      @monitor.should_receive(:set).with(:created_at, anything).and_return(attr_holder)
+      @monitor.should_receive(:set).with(:thread_id, anything).and_return(stub_everything)
+      attr_holder.should_receive(:serializable).and_return(attr_holder)
+      attr_holder.should_receive(:lock)
+      @engine.init_monitor(@monitor)
+    end
+
+    it &quot;should set the thread ID attribute on the monitor and serializable and locked&quot; do
+      attr_holder = mock('attr_holder')
+      @monitor.should_receive(:set).with(:created_at, anything).and_return(stub_everything)
+      @monitor.should_receive(:set).with(:thread_id, Thread.current.__id__).and_return(attr_holder)
+      attr_holder.should_receive(:serializable).and_return(attr_holder)
+      attr_holder.should_receive(:lock)
+      @engine.init_monitor(@monitor)
+    end
+
+    it &quot;should set inherited attributes on monitor&quot;
+
+    it &quot;should do nothing if not enabled&quot; do
+      @engine.enabled = false
+      @engine.init_monitor(mock('mock_monitor'))
+    end
+  end
+
+  describe &quot;processing monitor_created callback&quot; do
+    before { @callback_method = :monitor_created }
+    it_should_behave_like 'Monitor callback'
+  end
+
+  describe &quot;processing composite_monitor_started callback&quot; do
+    before { @callback_method = :composite_monitor_started }
+    it_should_behave_like 'Monitor callback'
+  end
+
+  describe &quot;processing composite_monitor_completed callback&quot; do
+    before { @callback_method = :composite_monitor_completed }
+    it_should_behave_like 'Monitor callback'
+  end
+
+  describe &quot;processing process callback&quot; do
+    before { @callback_method = :process }
+    it_should_behave_like 'Monitor callback'
   end
 end</diff>
      <filename>spec/monitoring_engine_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>d2cc63762cfe22ff9b5d34c10cf806f866f12d59</id>
    </parent>
  </parents>
  <author>
    <name>Doug Barth</name>
    <email>dougbarth@gmail.com</email>
  </author>
  <url>http://github.com/dougbarth/ermarb/commit/378f0b442bd46c8b6870d638791d2f74cdf6b8f9</url>
  <id>378f0b442bd46c8b6870d638791d2f74cdf6b8f9</id>
  <committed-date>2008-06-30T10:37:45-07:00</committed-date>
  <authored-date>2008-06-30T10:37:45-07:00</authored-date>
  <message>Working on specs for the MonitoringEngine.</message>
  <tree>d169ff7db555c4b2f4109b4ce905a8f552e39286</tree>
  <committer>
    <name>Doug Barth</name>
    <email>dougbarth@gmail.com</email>
  </committer>
</commit>
