   ##
   ###################################################
 
-  def init([mod, configuration]) do
-    {:ok, state} = mod.init(configuration)
-    {:ok, %__MODULE__{mod: mod, state: state}}
+  def init([name]) do
+    {:ok, %__MODULE__{state: %{name: name}}}
   end
 
-  def handle_cast(:run, s = %__MODULE__{mod: mod, state: state, observer_pid: nil}) do
+  def handle_call({:configure, plug_list}, _from, state) do
+    # create pipelines of plugins
+    {observer_fun, init_fun} = plug_list
+    |> Enum.reduce({fn s -> s end, fn s -> s end},
+    fn {plug, config}, {combined_plug, combined_init} ->
+      obs = fn(s) -> case do_observe(plug, s) do
+          {:ok, s_new} -> combined_plug.(s_new)
+          other -> other # abort any other operations
+        end
+      end
+      init = fn(s) ->
+        {:ok, s_init} = plug.init(config)
+        Map.put(s, plug, s_init)
+        |> combined_init.()
+      end
+      {obs, init}
+    end)
+    {:reply, :ok, %__MODULE__{state | observer_fun: observer_fun, init_fun: init_fun}}
+  end
+
+  @doc """
+  __INTERNAL FUNCTION: NO API __
+
+  This is the function which is called for each step within the plugin
+  pipelin. It manages the state and coordinates the execution of
+  plugin
+  """
+  @spec do_observe(atom, plugin_state) :: observer_return_t
+  def do_observe(plug, state) do
+    Logger.debug("do_observe: plug = #{inspect plug}, state = #{inspect state}")
+    case state |> Map.fetch!(plug) |> plug.observe() do
+      {:ok, url, bmf, s} ->
+        {:ok, state
+          |> Map.put(:"$url", url)
+          |> Map.put(:"$bmf", bmf)
+          |> Map.put(plug, s)
+        }
+      {:ok, s} -> {:ok, Map.put(state, plug, s)}
+      {:error, reason, s} ->
+        {:error, reason, Map.put(state, plug, s)}
+      {:stop, s} ->
+        {:stop, Map.put(state, plug, s)}
+    end
+  end
+
+  def handle_cast(:run, s = %__MODULE__{name: name, state: state, observer_pid: nil}) do
     # Start the oberserver as a distinct process, under supervision
     # control and linked to this server process
     parent_pid = self
     {:ok, pid} = Task.Supervisor.start_child(Baumeister.ObserverSupervisor,
       fn ->
-        EventCenter.sync_notify({:observer, :start_observer, mod})
-        case mod.observe(state) do
-          {:ok, url, baumeister_file} ->
+        EventCenter.sync_notify({:observer, :start_observer, name})
+        obs_state = s.init_fun.(state)
+        case s.observer_fun.(obs_state) do
+          {:ok, new_s} ->
+              url = Map.fetch!(new_s, :"$url")
+              baumeister_file = Map.fetch!(new_s, :"$bmf")
               Observer.execute(parent_pid, url, baumeister_file)
-          :error -> EventCenter.sync_notify{:observer, :failed_observer, mod}
+          {:error, _reason, new_s} -> EventCenter.sync_notify{:observer, :failed_observer, name}
               Observer.stop(parent_pid, :error)
+          {:stop, new_s } -> EventCenter.sync_notify{:observer, :stopped_observer, name}
+              Observer.stop(parent_pid, :normal)
         end
       end)
     {:noreply, %__MODULE__{s | observer_pid: pid}}

  ###################################################

  use GenServer

  defstruct [:mod, :state, :observer_pid]

  def start_link(mod, configuration) when is_atom(mod) do
    GenServer.start_link(__MODULE__, [mod, configuration])
  end

  @doc """

defmodule Baumeister.Observer do
  @moduledoc """
  Defines the API, which a specific observer has to implement.
  """
  alias Baumeister.EventCenter
  alias Baumeister.BaumeisterFile
  alias Baumeister.Observer

  @typedoc """
  A mapping between plugin name and its current state.
  """
  @type plugin_state :: %{atom => any}

  @typedoc """
  Allowed return values for an Observer Plugin:
  * `:ok` if everything went fine. We return the URL and BaumeisterFile.
  * `:error` somethings fails. Stops the Observer with a crash
  * `:stop` The Plugin decides, that the Observer should stop.
  """
  @type observer_return_t ::
    {:ok, String.t, String.t, any} |
    {:ok, any} |
    {:error, any, any} |
    {:stop, any}


  @doc """
  Initializes the observer. It is called with the observer's
