Index: /branches/3.0/sources/HeuristicLab.Core/PersistenceManager.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Core/PersistenceManager.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Core/PersistenceManager.cs	(revision 279)
@@ -88,5 +88,5 @@
     public static string BuildTypeString(Type type) {
       string assembly = type.Assembly.FullName;
-      assembly = assembly.Split(new string[] { ", " }, StringSplitOptions.None)[0];
+      assembly = assembly.Substring(0, assembly.IndexOf(", "));
 
       StringBuilder builder = new StringBuilder();
Index: /branches/3.0/sources/HeuristicLab.DistributedEngine/DistributedEngine.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.DistributedEngine/DistributedEngine.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.DistributedEngine/DistributedEngine.cs	(revision 279)
@@ -30,13 +30,13 @@
 using System.IO;
 using System.IO.Compression;
+using HeuristicLab.PluginInfrastructure;
+using System.Windows.Forms;
+using System.Diagnostics;
 
 namespace HeuristicLab.DistributedEngine {
   public class DistributedEngine : EngineBase, IEditable {
-    private IGridServer server;
-    private Dictionary<Guid, AtomicOperation> engineOperations = new Dictionary<Guid, AtomicOperation>();
-    private List<Guid> runningEngines = new List<Guid>();
+    private JobManager jobManager;
+    private CompositeOperation waitingOperations;
     private string serverAddress;
-    private bool cancelRequested;
-    private CompositeOperation waitingOperations;
     public string ServerAddress {
       get { return serverAddress; }
@@ -47,9 +47,4 @@
       }
     }
-    public override bool Terminated {
-      get {
-        return myExecutionStack.Count == 0 && runningEngines.Count == 0 && waitingOperations==null;
-      }
-    }
     public override object Clone(IDictionary<Guid, object> clonedObjects) {
       DistributedEngine clone = (DistributedEngine)base.Clone(clonedObjects);
@@ -66,12 +61,6 @@
 
     public override void Execute() {
-      NetTcpBinding binding = new NetTcpBinding();
-      binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
-      binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
-      binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
-      binding.Security.Mode = SecurityMode.None;
-      ChannelFactory<IGridServer> factory = new ChannelFactory<IGridServer>(binding);
-      server = factory.CreateChannel(new EndpointAddress(serverAddress));
-
+      if(jobManager == null) this.jobManager = new JobManager(serverAddress);
+      jobManager.Reset();
       base.Execute();
     }
@@ -81,100 +70,136 @@
     }
 
-    public override void Abort() {
-      lock(runningEngines) {
-        cancelRequested = true;
-        foreach(Guid engineGuid in runningEngines) {
-          server.AbortEngine(engineGuid);
-        }
-      }
-    }
-    public override void Reset() {
-      base.Reset();
-      engineOperations.Clear();
-      runningEngines.Clear();
-      cancelRequested = false;
-    }
-
     protected override void ProcessNextOperation() {
-      lock(runningEngines) {
-        if(runningEngines.Count == 0 && cancelRequested) {
-          base.Abort();
-          cancelRequested = false;
-          if(waitingOperations != null && waitingOperations.Operations.Count != 0) {
-            myExecutionStack.Push(waitingOperations);
-            waitingOperations = null;
+      IOperation operation = myExecutionStack.Pop();
+      if(operation is AtomicOperation) {
+        AtomicOperation atomicOperation = (AtomicOperation)operation;
+        IOperation next = null;
+        try {
+          next = atomicOperation.Operator.Execute(atomicOperation.Scope);
+        } catch(Exception ex) {
+          // push operation on stack again
+          myExecutionStack.Push(atomicOperation);
+          Abort();
+          ThreadPool.QueueUserWorkItem(delegate(object state) { OnExceptionOccurred(ex); });
+        }
+        if(next != null)
+          myExecutionStack.Push(next);
+        OnOperationExecuted(atomicOperation);
+        if(atomicOperation.Operator.Breakpoint) Abort();
+      } else if(operation is CompositeOperation) {
+        CompositeOperation compositeOperation = (CompositeOperation)operation;
+        if(compositeOperation.ExecuteInParallel) {
+          try {
+            WaitHandle[] waithandles = new WaitHandle[compositeOperation.Operations.Count];
+            int i = 0;
+            // HACK: assume that all atomicOperations have the same parent scope.
+            // 1) find that parent scope
+            // 2) remove all branches starting from the global scope that don't lead to the parentScope of the parallel operation
+            // 3) keep the branches to 'repair' the scope-tree later
+            // 4) for each parallel job attach only the sub-scope that this operation uses
+            // 5) after starting all parallel jobs restore the whole scope-tree
+            IScope parentScope = FindParentScope(GlobalScope, compositeOperation);
+            List<IList<IScope>> prunedScopes = new List<IList<IScope>>();
+            PruneToParentScope(GlobalScope, parentScope, prunedScopes);
+            List<IScope> subScopes = new List<IScope>(parentScope.SubScopes);
+            foreach(IScope scope in subScopes) {
+              parentScope.RemoveSubScope(scope);
+            }
+            // start all parallel jobs
+            foreach(AtomicOperation parOperation in compositeOperation.Operations) {
+              parentScope.AddSubScope(parOperation.Scope);
+              waithandles[i++] = jobManager.BeginExecuteOperation(GlobalScope, parOperation);
+              parentScope.RemoveSubScope(parOperation.Scope);
+            }
+            foreach(IScope scope in subScopes) {
+              parentScope.AddSubScope(scope);
+            }
+            prunedScopes.Reverse();
+            RestoreFullTree(GlobalScope, prunedScopes);
+
+            // wait until all jobs are finished
+            // WaitAll works only with maximally 64 waithandles
+            if(waithandles.Length <= 64) {
+              WaitHandle.WaitAll(waithandles);
+            } else {
+              for(i = 0; i < waithandles.Length; i++) {
+                waithandles[i].WaitOne();
+                waithandles[i].Close();
+              }
+            }
+            // retrieve results and merge into scope-tree
+            foreach(AtomicOperation parOperation in compositeOperation.Operations) {
+              IScope result = jobManager.EndExecuteOperation(parOperation);
+              MergeScope(parOperation.Scope, result);
+            }
+          } catch(Exception e) {
+            myExecutionStack.Push(compositeOperation);
+            Abort();
+            ThreadPool.QueueUserWorkItem(delegate(object state) { OnExceptionOccurred(e); });
           }
-          return;
-        }
-        if(runningEngines.Count != 0) {
-          Guid engineGuid = runningEngines[0];
-          byte[] resultXml = server.TryEndExecuteEngine(engineGuid, 100);
-          if(resultXml != null) {
-            GZipStream stream = new GZipStream(new MemoryStream(resultXml), CompressionMode.Decompress);
-            ProcessingEngine resultEngine = (ProcessingEngine)PersistenceManager.Load(stream);
-            IScope oldScope = engineOperations[engineGuid].Scope;
-            oldScope.Clear();
-            foreach(IVariable variable in resultEngine.InitialOperation.Scope.Variables) {
-              oldScope.AddVariable(variable);
-            }
-            foreach(IScope subScope in resultEngine.InitialOperation.Scope.SubScopes) {
-              oldScope.AddSubScope(subScope);
-            }
-            OnOperationExecuted(engineOperations[engineGuid]);
-
-            if(cancelRequested & resultEngine.ExecutionStack.Count != 0) {
-              if(waitingOperations == null) {
-                waitingOperations = new CompositeOperation();
-                waitingOperations.ExecuteInParallel = false;
-              }
-              CompositeOperation task = new CompositeOperation();
-              while(resultEngine.ExecutionStack.Count > 0) {
-                AtomicOperation oldOperation = (AtomicOperation)resultEngine.ExecutionStack.Pop();
-                if(oldOperation.Scope == resultEngine.InitialOperation.Scope) {
-                  oldOperation = new AtomicOperation(oldOperation.Operator, oldScope);
-                }
-                task.AddOperation(oldOperation);
-              }
-              waitingOperations.AddOperation(task);
-            }
-            runningEngines.Remove(engineGuid);
-            engineOperations.Remove(engineGuid);
-          }
-          return;
-        }
-        IOperation operation = myExecutionStack.Pop();
-        if(operation is AtomicOperation) {
-          AtomicOperation atomicOperation = (AtomicOperation)operation;
-          IOperation next = null;
-          try {
-            next = atomicOperation.Operator.Execute(atomicOperation.Scope);
-          } catch(Exception ex) {
-            // push operation on stack again
-            myExecutionStack.Push(atomicOperation);
-            Abort();
-            ThreadPool.QueueUserWorkItem(delegate(object state) { OnExceptionOccurred(ex); });
-          }
-          if(next != null)
-            myExecutionStack.Push(next);
-          OnOperationExecuted(atomicOperation);
-          if(atomicOperation.Operator.Breakpoint) Abort();
-        } else if(operation is CompositeOperation) {
-          CompositeOperation compositeOperation = (CompositeOperation)operation;
-          if(compositeOperation.ExecuteInParallel) {
-            foreach(AtomicOperation parOperation in compositeOperation.Operations) {
-              ProcessingEngine engine = new ProcessingEngine(OperatorGraph, GlobalScope, parOperation); // OperatorGraph not needed?
-              MemoryStream memStream = new MemoryStream();
-              GZipStream stream = new GZipStream(memStream, CompressionMode.Compress, true);
-              PersistenceManager.Save(engine, stream);
-              stream.Close();
-              Guid currentEngineGuid = server.BeginExecuteEngine(memStream.ToArray());
-              runningEngines.Add(currentEngineGuid);
-              engineOperations[currentEngineGuid] = parOperation;
-            }
-          } else {
-            for(int i = compositeOperation.Operations.Count - 1; i >= 0; i--)
-              myExecutionStack.Push(compositeOperation.Operations[i]);
-          }
-        }
+        } else {
+          for(int i = compositeOperation.Operations.Count - 1; i >= 0; i--)
+            myExecutionStack.Push(compositeOperation.Operations[i]);
+        }
+      }
+    }
+
+    private void RestoreFullTree(IScope currentScope, IList<IList<IScope>> savedScopes) {
+      if(savedScopes.Count == 0) return;
+      IScope remainingBranch = currentScope.SubScopes[0];
+      currentScope.RemoveSubScope(remainingBranch);
+      IList<IScope> savedScopesForCurrent = savedScopes[0];
+      foreach(IScope savedScope in savedScopesForCurrent) {
+        currentScope.AddSubScope(savedScope);
+      }
+      savedScopes.RemoveAt(0);
+      RestoreFullTree(remainingBranch, savedScopes);
+    }
+
+    private IScope PruneToParentScope(IScope currentScope, IScope scope, IList<IList<IScope>> prunedScopes) {
+      if(currentScope == scope) return currentScope;
+      if(currentScope.SubScopes.Count == 0) return null;
+      IScope foundScope = null;
+      // try to find the searched scope in all my sub-scopes
+      foreach(IScope subScope in currentScope.SubScopes) {
+        foundScope = PruneToParentScope(subScope, scope, prunedScopes);
+        if(foundScope != null) break; // we can stop as soon as we find the scope in a branch
+      }
+      if(foundScope != null) { // when we found the scopes in my sub-scopes
+        List<IScope> subScopes = new List<IScope>(currentScope.SubScopes); // store the list of sub-scopes
+        prunedScopes.Add(subScopes);
+        // remove all my sub-scopes
+        foreach(IScope subScope in subScopes) { 
+          currentScope.RemoveSubScope(subScope);
+        }
+        // add only the branch that leads to the scope that I search for
+        currentScope.AddSubScope(foundScope);
+        return currentScope; // return that this scope contains the branch that leads to the searched scopes
+      } else {
+        return null; // otherwise we didn't find the searched scope and we can return null
+      }
+    }
+
+    private IScope FindParentScope(IScope currentScope, CompositeOperation compositeOperation) {
+      AtomicOperation currentOperation = (AtomicOperation)compositeOperation.Operations[0];
+      if(currentScope.SubScopes.Contains(currentOperation.Scope)) return currentScope;
+      foreach(IScope subScope in currentScope.SubScopes) {
+        IScope result = FindParentScope(subScope, compositeOperation);
+        if(result != null) return result;
+      }
+      return null;
+    }
+
+    private void MergeScope(IScope original, IScope result) {
+      // merge the results
+      original.Clear();
+      foreach(IVariable variable in result.Variables) {
+        original.AddVariable(variable);
+      }
+      foreach(IScope subScope in result.SubScopes) {
+        original.AddSubScope(subScope);
+      }
+      foreach(KeyValuePair<string, string> alias in result.Aliases) {
+        original.AddAlias(alias.Key, alias.Value);
       }
     }
Index: /branches/3.0/sources/HeuristicLab.DistributedEngine/HeuristicLab.DistributedEngine.csproj
===================================================================
--- /branches/3.0/sources/HeuristicLab.DistributedEngine/HeuristicLab.DistributedEngine.csproj	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.DistributedEngine/HeuristicLab.DistributedEngine.csproj	(revision 279)
@@ -50,4 +50,5 @@
   <ItemGroup>
     <Compile Include="HeuristicLabDistributedEnginePlugin.cs" />
+    <Compile Include="JobManager.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="DistributedEngine.cs" />
Index: /branches/3.0/sources/HeuristicLab.DistributedEngine/JobManager.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.DistributedEngine/JobManager.cs	(revision 279)
+++ /branches/3.0/sources/HeuristicLab.DistributedEngine/JobManager.cs	(revision 279)
@@ -0,0 +1,236 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ServiceModel;
+using HeuristicLab.Grid;
+using System.Threading;
+using HeuristicLab.Core;
+using System.IO;
+using System.IO.Compression;
+using System.Windows.Forms;
+
+namespace HeuristicLab.DistributedEngine {
+  class JobManager {
+    private IGridServer server;
+    private string address;
+    private Dictionary<Guid, ProcessingEngine> engines = new Dictionary<Guid, ProcessingEngine>();
+    private Dictionary<Guid, ManualResetEvent> waithandles = new Dictionary<Guid, ManualResetEvent>();
+    private Dictionary<AtomicOperation, byte[]> results = new Dictionary<AtomicOperation, byte[]>();
+    private object connectionLock = new object();
+    private object dictionaryLock = new object();
+
+    private const int MAX_RESTARTS = 5;
+    private const int MAX_CONNECTION_RETRIES = 10;
+    private const int RETRY_TIMEOUT_SEC = 10;
+    private const int CHECK_RESULTS_TIMEOUT = 10;
+
+    private ChannelFactory<IGridServer> factory;
+
+    public JobManager(string address) {
+      this.address = address;
+    }
+
+    internal void Reset() {
+      ResetConnection();
+      lock(dictionaryLock) {
+        foreach(WaitHandle wh in waithandles.Values) wh.Close();
+        waithandles.Clear();
+        engines.Clear();
+        results.Clear();
+      }
+    }
+
+    private void ResetConnection() {
+      lock(connectionLock) {
+        // open a new channel
+        NetTcpBinding binding = new NetTcpBinding();
+        binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
+        binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
+        binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
+        binding.Security.Mode = SecurityMode.None;
+
+        factory = new ChannelFactory<IGridServer>(binding);
+        server = factory.CreateChannel(new EndpointAddress(address));
+      }
+    }
+
+    public WaitHandle BeginExecuteOperation(IScope globalScope, AtomicOperation operation) {
+      ProcessingEngine engine = new ProcessingEngine(globalScope, operation);
+      byte[] zippedEngine = ZipEngine(engine);
+      Guid currentEngineGuid = Guid.Empty;
+      bool success = false;
+      int retryCount = 0;
+      do {
+        lock(connectionLock) {
+          try {
+            currentEngineGuid = server.BeginExecuteEngine(zippedEngine);
+            success = true;
+          } catch(TimeoutException timeoutException) {
+            if(retryCount < MAX_CONNECTION_RETRIES) {
+              Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+              retryCount++;
+            } else {
+              throw new ApplicationException("Max retries reached.", timeoutException);
+            }
+          } catch(CommunicationException communicationException) {
+            ResetConnection();
+            // wait some time and try again (limit with maximal retries if retry count reached throw exception -> engine can decide to stop execution)
+            if(retryCount < MAX_CONNECTION_RETRIES) {
+              Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+              retryCount++;
+            } else {
+              throw new ApplicationException("Max retries reached.", communicationException);
+            }
+          }
+        }
+      } while(!success);
+      lock(dictionaryLock) {
+        engines[currentEngineGuid] = engine;
+        waithandles[currentEngineGuid] = new ManualResetEvent(false);
+      }
+      ThreadPool.QueueUserWorkItem(new WaitCallback(TryGetResult), currentEngineGuid);
+      return waithandles[currentEngineGuid];
+    }
+
+    private byte[] ZipEngine(ProcessingEngine engine) {
+      MemoryStream memStream = new MemoryStream();
+      GZipStream stream = new GZipStream(memStream, CompressionMode.Compress, true);
+      PersistenceManager.Save(engine, stream);
+      stream.Close();
+      byte[] zippedEngine = memStream.ToArray();
+      memStream.Close();
+      return zippedEngine;
+    }
+
+    public IScope EndExecuteOperation(AtomicOperation operation) {
+      byte[] zippedResult = null;
+      lock(dictionaryLock) {
+        zippedResult = results[operation];
+        results.Remove(operation);
+      }
+      // restore the engine 
+      using(GZipStream stream = new GZipStream(new MemoryStream(zippedResult), CompressionMode.Decompress)) {
+        ProcessingEngine resultEngine = (ProcessingEngine)PersistenceManager.Load(stream);
+        return resultEngine.InitialOperation.Scope;
+      }      
+    }
+
+    private void TryGetResult(object state) {
+      Guid engineGuid = (Guid)state;
+      int restartCounter = 0;
+      do {
+        Thread.Sleep(TimeSpan.FromSeconds(CHECK_RESULTS_TIMEOUT));
+        byte[] zippedResult = null;
+        lock(connectionLock) {
+          bool success = false;
+          int retries = 0;
+          do {
+            try {
+              zippedResult = server.TryEndExecuteEngine(engineGuid, 100);
+              success = true;
+            } catch(TimeoutException timeoutException) {
+              success = false;
+              retries++;
+              Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+            } catch(CommunicationException communicationException) {
+              ResetConnection();
+              success = false;
+              retries++;
+              Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+            }
+
+          } while(!success && retries < MAX_CONNECTION_RETRIES);
+        }
+        if(zippedResult != null) {
+          lock(dictionaryLock) {
+            // store result
+            results[engines[engineGuid].InitialOperation] = zippedResult;
+
+            // signal the wait handle and clean up then return
+            engines.Remove(engineGuid);
+            waithandles[engineGuid].Set();
+            waithandles.Remove(engineGuid);
+          }
+          return;
+        } else {
+          // check if the server is still working on the job
+          bool success = false;
+          int retries = 0;
+          JobState jobState = JobState.Unkown;
+          do {
+            try {
+              lock(connectionLock) {
+                jobState = server.JobState(engineGuid);
+              }
+              success = true;
+            } catch(TimeoutException timeoutException) {
+              retries++;
+              success = false;
+              Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+            } catch(CommunicationException communicationException) {
+              ResetConnection();
+              retries++;
+              success = false;
+              Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+            }
+          } while(!success && retries < MAX_CONNECTION_RETRIES);
+          if(jobState == JobState.Unkown) {
+            // restart job
+            ProcessingEngine engine;
+            lock(dictionaryLock) {
+              engine = engines[engineGuid];
+            }
+            byte[] zippedEngine = ZipEngine(engine);
+            success = false;
+            retries = 0;
+            do {
+              try {
+                lock(connectionLock) {
+                  server.BeginExecuteEngine(zippedEngine);
+                }
+                success = true;
+              } catch(TimeoutException timeoutException) {
+                success = false;
+                retries++;
+                Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+              } catch(CommunicationException communicationException) {
+                ResetConnection();
+                success = false;
+                retries++;
+                Thread.Sleep(TimeSpan.FromSeconds(RETRY_TIMEOUT_SEC));
+              }
+            } while(!success && retries < MAX_CONNECTION_RETRIES);
+            restartCounter++;
+          }
+        }
+
+        // when we reach a maximum amount of restarts => signal the wait-handle and set a flag that there was a problem
+        if(restartCounter > MAX_RESTARTS) {
+          throw new ApplicationException("Maximum number of job restarts reached.");
+        }
+      } while(true);
+    }
+  }
+}
Index: /branches/3.0/sources/HeuristicLab.Grid/ClientForm.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/ClientForm.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/ClientForm.cs	(revision 279)
@@ -38,13 +38,14 @@
 namespace HeuristicLab.Grid {
   [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
-  public partial class ClientForm : Form, IClient {
+  public partial class ClientForm : Form {
     private ChannelFactory<IEngineStore> factory;
-    private ServiceHost clientHost;
     private System.Timers.Timer fetchOperationTimer;
     private IEngineStore engineStore;
     private Guid currentGuid;
     private ProcessingEngine currentEngine;
-    private string clientUrl;
-    private object locker = new object();
+    private object connectionLock = new object();
+    private bool stopped;
+    private const int CONNECTION_RETRY_TIMEOUT_SEC = 10;
+    private const int MAX_RETRIES = 10;
 
     public ClientForm() {
@@ -54,40 +55,19 @@
       fetchOperationTimer.Elapsed += new System.Timers.ElapsedEventHandler(fetchOperationTimer_Elapsed);
       statusTextBox.Text = "Stopped";
+      stopped = true;
       currentGuid = Guid.Empty;
     }
 
     private void startButton_Click(object sender, EventArgs e) {
-      string hostname = Dns.GetHostName();
-      IPAddress[] addresses = Dns.GetHostAddresses(hostname);
-
-      // windows XP returns the external ip on index 0 while windows vista returns the external ip on index 2
-      if (System.Environment.OSVersion.Version.Major >= 6) {
-        clientUrl = "net.tcp://" + Dns.GetHostAddresses(Dns.GetHostName())[2] + ":" + clientPort.Text +"/Grid/Client";
-      } else {
-        clientUrl = "net.tcp://" + Dns.GetHostAddresses(Dns.GetHostName())[0] + ":" + clientPort.Text +"/Grid/Client";
-      }
-
-      clientHost = new ServiceHost(this, new Uri(clientUrl));
       try {
-        NetTcpBinding binding = new NetTcpBinding();
-        binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
-        binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
-        binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
-        binding.Security.Mode = SecurityMode.None;
-
-        clientHost.AddServiceEndpoint(typeof(IClient), binding, clientUrl);
-        clientHost.Open();
-
-        factory = new ChannelFactory<IEngineStore>(binding);
-        engineStore = factory.CreateChannel(new EndpointAddress(addressTextBox.Text));
-
+        ResetConnection();
         fetchOperationTimer.Start();
         startButton.Enabled = false;
         stopButton.Enabled = true;
         statusTextBox.Text = "Waiting for engine";
+        stopped = false;
 
-      } catch (CommunicationException ex) {
+      } catch(CommunicationException ex) {
         MessageBox.Show("Exception while connecting to the server: " + ex.Message);
-        clientHost.Abort();
         startButton.Enabled = true;
         stopButton.Enabled = false;
@@ -96,8 +76,25 @@
     }
 
+    private void ResetConnection() {
+      NetTcpBinding binding = new NetTcpBinding();
+      binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
+      binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
+      binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
+      binding.Security.Mode = SecurityMode.None;
+      factory = new ChannelFactory<IEngineStore>(binding);
+      engineStore = factory.CreateChannel(new EndpointAddress(addressTextBox.Text));
+    }
+
     private void stopButton_Click(object sender, EventArgs e) {
+      stopped = true;
       fetchOperationTimer.Stop();
-      factory.Abort();
-      clientHost.Close();
+      if(currentEngine != null)
+        currentEngine.Abort();
+      lock(connectionLock) {
+        if(factory.State == CommunicationState.Opened || factory.State == CommunicationState.Opening) {
+          IAsyncResult closeResult = factory.BeginClose(null, null);
+          factory.EndClose(closeResult);
+        }
+      }
       statusTextBox.Text = "Stopped";
       stopButton.Enabled = false;
@@ -106,21 +103,39 @@
 
     private void fetchOperationTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
-      lock(locker) {
-        byte[] engineXml;
-        fetchOperationTimer.Stop();
-        if(engineStore.TryTakeEngine(clientUrl, out currentGuid, out engineXml)) {
-          currentEngine = RestoreEngine(engineXml);
-          if(InvokeRequired) { Invoke((MethodInvoker)delegate() { statusTextBox.Text = "Executing engine"; }); } else statusTextBox.Text = "Executing engine";
-          currentEngine.Finished += delegate(object src, EventArgs args) {
-            byte[] resultXml = SaveEngine(currentEngine);
-            engineStore.StoreResult(currentGuid, resultXml);
-            currentGuid = Guid.Empty;
-            currentEngine = null;
-            fetchOperationTimer.Interval = 100;
-            fetchOperationTimer.Start();
-          };
-          currentEngine.Execute();
-        } else {
+      byte[] engineXml = null;
+      // first stop the timer!
+      fetchOperationTimer.Stop();
+      bool gotEngine = false;
+      lock(connectionLock) {
+        if(stopped) return;
+        try {
+          gotEngine = engineStore.TryTakeEngine(out currentGuid, out engineXml);
+        } catch(TimeoutException timeoutException) {
+          currentEngine = null;
+          currentGuid = Guid.Empty;
+          // timeout -> just start the timer again
+          fetchOperationTimer.Interval = 5000;
+          fetchOperationTimer.Start();
+        } catch(CommunicationException communicationException) {
+          // connection problem -> reset connection and start the timer again
+          ResetConnection();
+          currentEngine = null;
+          currentGuid = Guid.Empty;
+          fetchOperationTimer.Interval = 5000;
+          fetchOperationTimer.Start();
+        }
+      }
+      // got engine from server and user didn't press stop -> execute the engine
+      if(gotEngine && !stopped) {
+        currentEngine = RestoreEngine(engineXml);
+        if(InvokeRequired) { Invoke((MethodInvoker)delegate() { statusTextBox.Text = "Executing engine"; }); } else statusTextBox.Text = "Executing engine";
+        currentEngine.Finished += new EventHandler(currentEngine_Finished); // register event-handler that sends result back to server and restarts timer
+        currentEngine.Execute();
+      } else {
+        // ok we didn't get engine -> if the user didn't press stop this means that the server doesn't have engines for us
+        // if the user pressed stop we must not start the timer
+        if(!stopped) {
           if(InvokeRequired) { Invoke((MethodInvoker)delegate() { statusTextBox.Text = "Waiting for engine"; }); } else statusTextBox.Text = "Waiting for engine";
+          // start the timer again
           fetchOperationTimer.Interval = 5000;
           fetchOperationTimer.Start();
@@ -128,13 +143,40 @@
       }
     }
-    public void Abort(Guid guid) {
-      lock(locker) {
-        if(!IsRunningEngine(guid)) return;
-        currentEngine.Abort();
-      }
+
+    void currentEngine_Finished(object sender, EventArgs e) {
+      IEngine engine = (IEngine)sender;
+      byte[] resultXml = SaveEngine(engine);
+      bool success = false;
+      int retries = 0;
+      do {
+        lock(connectionLock) {
+          if(!stopped) {
+            try {
+              engineStore.StoreResult(currentGuid, resultXml);
+              success = true;
+            } catch(TimeoutException timeoutException) {
+              success = false;
+              retries++;
+              Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
+            } catch(CommunicationException communicationException) {
+              ResetConnection();
+              success = false;
+              retries++;
+              Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
+            }
+          }
+        }
+      } while(!stopped && !success && retries < MAX_RETRIES);
+      // ok if we could store the result it's probable that the server can send us another engine use a small time-interval
+      if(success)
+        fetchOperationTimer.Interval = 100;
+      else fetchOperationTimer.Interval = CONNECTION_RETRY_TIMEOUT_SEC; // if there were problems -> sleep for a longer time
+      // clear state
+      currentEngine = null;
+      currentGuid = Guid.Empty;
+      // start the timer
+      fetchOperationTimer.Start();
     }
-    public bool IsRunningEngine(Guid guid) {
-      return currentGuid == guid;
-    }
+
     private ProcessingEngine RestoreEngine(byte[] engine) {
       GZipStream stream = new GZipStream(new MemoryStream(engine), CompressionMode.Decompress);
Index: /branches/3.0/sources/HeuristicLab.Grid/EngineStore.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/EngineStore.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/EngineStore.cs	(revision 279)
@@ -34,7 +34,9 @@
     private Dictionary<Guid, ManualResetEvent> waitHandles;
     private Dictionary<Guid, byte[]> results;
-    private Dictionary<Guid, string> runningClients;
+    private Dictionary<Guid, DateTime> resultDate;
+    private Dictionary<Guid, DateTime> runningEngineDate;
+    private const int RESULT_EXPIRY_TIME_MIN = 10;
+    private const int RUNNING_JOB_EXPIRY_TIME_MIN = 10;
     private object bigLock;
-    private ChannelFactory<IClient> clientChannelFactory;
     public int WaitingJobs {
       get {
@@ -59,19 +61,12 @@
       waitingEngines = new Dictionary<Guid, byte[]>();
       runningEngines = new Dictionary<Guid, byte[]>();
-      runningClients = new Dictionary<Guid, string>();
       waitHandles = new Dictionary<Guid, ManualResetEvent>();
       results = new Dictionary<Guid, byte[]>();
+      resultDate = new Dictionary<Guid, DateTime>();
+      runningEngineDate = new Dictionary<Guid, DateTime>();
       bigLock = new object();
-
-      NetTcpBinding binding = new NetTcpBinding();
-      binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
-      binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
-      binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
-      binding.Security.Mode = SecurityMode.None;
-
-      clientChannelFactory = new ChannelFactory<IClient>(binding);
     }
 
-    public bool TryTakeEngine(string clientUrl, out Guid guid, out byte[] engine) {
+    public bool TryTakeEngine(out Guid guid, out byte[] engine) {
       lock(bigLock) {
         if(engineList.Count == 0) {
@@ -85,5 +80,5 @@
           waitingEngines.Remove(guid);
           runningEngines[guid] = engine;
-          runningClients[guid] = clientUrl;
+          runningEngineDate[guid] = DateTime.Now;
           return true;
         }
@@ -93,11 +88,37 @@
     public void StoreResult(Guid guid, byte[] result) {
       lock(bigLock) {
-        if(!runningEngines.ContainsKey(guid)) return; // ignore result when the engine is not known to be running
-
+        // clear old results
+        List<Guid> expiredResults = FindExpiredResults(DateTime.Now.AddMinutes(-RESULT_EXPIRY_TIME_MIN));
+        foreach(Guid expiredGuid in expiredResults) {
+          results.Remove(expiredGuid);
+          waitHandles.Remove(expiredGuid);
+          resultDate.Remove(expiredGuid);
+        }
+        // add the new result
         runningEngines.Remove(guid);
-        runningClients.Remove(guid);
+        runningEngineDate.Remove(guid);
         results[guid] = result;
+        resultDate[guid] = DateTime.Now;
         waitHandles[guid].Set();
       }
+    }
+
+    private List<Guid> FindExpiredResults(DateTime expirationDate) {
+      List<Guid> expiredResults = new List<Guid>();
+      foreach(Guid guid in results.Keys) {
+        if(resultDate[guid] < expirationDate) {
+          expiredResults.Add(guid);
+        }
+      }
+      return expiredResults;
+    }
+    private List<Guid> FindExpiredJobs(DateTime expirationDate) {
+      List<Guid> expiredJobs = new List<Guid>();
+      foreach(Guid guid in runningEngines.Keys) {
+        if(runningEngineDate[guid] < expirationDate) {
+          expiredJobs.Add(guid);
+        }
+      }
+      return expiredJobs;
     }
 
@@ -113,19 +134,41 @@
       return GetResult(guid, System.Threading.Timeout.Infinite);
     }
+
     internal byte[] GetResult(Guid guid, int timeout) {
       lock(bigLock) {
-        if(waitHandles.ContainsKey(guid)) {
+        // result already available
+        if(results.ContainsKey(guid)) {
+          // if the wait-handle for this result is still alive then close and remove it
+          if(waitHandles.ContainsKey(guid)) {
+            ManualResetEvent waitHandle = waitHandles[guid];
+            waitHandle.Close();
+            waitHandles.Remove(guid);
+          }
+          byte[] result = results[guid];
+          results.Remove(guid);
+          return result;
+        } else {
+          // result not yet available, if there is also no wait-handle for that result then we will never have a result and can return null
+          if(!waitHandles.ContainsKey(guid)) return null;
+          // otherwise we have a wait-handle and can wait for the result
           ManualResetEvent waitHandle = waitHandles[guid];
+          // wait
           if(waitHandle.WaitOne(timeout, true)) {
+            // ok got the result in within the wait time => close and remove the wait-hande and return the result
             waitHandle.Close();
             waitHandles.Remove(guid);
             byte[] result = results[guid];
-            results.Remove(guid);
             return result;
           } else {
+            // no result yet, check for which jobs we waited too long and requeue those jobs
+            List<Guid> expiredJobs = FindExpiredJobs(DateTime.Now.AddMinutes(-RUNNING_JOB_EXPIRY_TIME_MIN));
+            foreach(Guid expiredGuid in expiredJobs) {
+              engineList.Insert(0, expiredGuid);
+              waitingEngines[expiredGuid] = runningEngines[expiredGuid];
+              runningEngines.Remove(expiredGuid);
+              runningEngineDate.Remove(expiredGuid);
+            }
             return null;
           }
-        } else {
-          return null;
         }
       }
@@ -133,17 +176,13 @@
 
     internal void AbortEngine(Guid guid) {
-      string clientUrl = "";
+      throw new NotImplementedException();
+    }
+
+    internal JobState JobState(Guid guid) {
       lock(bigLock) {
-        if(runningClients.ContainsKey(guid)) {
-          clientUrl = runningClients[guid];
-          IClient client = clientChannelFactory.CreateChannel(new EndpointAddress(clientUrl));
-          client.Abort(guid);
-        } else if(waitingEngines.ContainsKey(guid)) {
-          byte[] engine = waitingEngines[guid];
-          waitingEngines.Remove(guid);
-          engineList.Remove(guid);
-          waitHandles[guid].Set();
-          results.Add(guid, engine);
-        }
+        if(waitingEngines.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Waiting;
+        else if(waitHandles.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Busy;
+        else if(results.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Finished;
+        else return HeuristicLab.Grid.JobState.Unkown;
       }
     }
Index: /branches/3.0/sources/HeuristicLab.Grid/GridClientApplication.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/GridClientApplication.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/GridClientApplication.cs	(revision 279)
@@ -27,5 +27,5 @@
 
 namespace HeuristicLab.Grid {
-  [ClassInfo(Name = "Grid Client", Description="Client application for the distributed engine grid.")]
+  [ClassInfo(Name = "Grid Client", Description="Client application for the distributed engine grid.", AutoRestart = true)]
   class GridClientApplication : ApplicationBase {
     public override void Run() {
Index: /branches/3.0/sources/HeuristicLab.Grid/GridServer.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/GridServer.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/GridServer.cs	(revision 279)
@@ -35,4 +35,8 @@
     }
 
+    public JobState JobState(Guid guid) {
+      return engineStore.JobState(guid);
+    }
+
     public Guid BeginExecuteEngine(byte[] engine) {
       Guid guid = Guid.NewGuid();
Index: /branches/3.0/sources/HeuristicLab.Grid/GridServerApplication.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/GridServerApplication.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/GridServerApplication.cs	(revision 279)
@@ -27,5 +27,5 @@
 
 namespace HeuristicLab.Grid {
-  [ClassInfo(Name = "Grid Server", Description="Server application for the distributed engine grid.")]
+  [ClassInfo(Name = "Grid Server", Description = "Server application for the distributed engine grid.", AutoRestart=true)]
   class GridServerApplication : ApplicationBase {
     public override void Run() {
Index: /branches/3.0/sources/HeuristicLab.Grid/HeuristicLab.Grid.csproj
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/HeuristicLab.Grid.csproj	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/HeuristicLab.Grid.csproj	(revision 279)
@@ -63,5 +63,4 @@
     <Compile Include="GridServerApplication.cs" />
     <Compile Include="HeuristicLabGridPlugin.cs" />
-    <Compile Include="IClient.cs" />
     <Compile Include="IEngineStore.cs" />
     <Compile Include="IGridServer.cs" />
Index: anches/3.0/sources/HeuristicLab.Grid/IClient.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/IClient.cs	(revision 278)
+++ 	(revision )
@@ -1,16 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.ServiceModel;
-
-namespace HeuristicLab.Grid {
-  [ServiceContract(Namespace = "http://HeuristicLab.Grid")]
-  interface IClient {
-    [OperationContract]
-    void Abort(Guid guid);
-
-    [OperationContract]
-    bool IsRunningEngine(Guid guid);
-  }
-}
Index: /branches/3.0/sources/HeuristicLab.Grid/IEngineStore.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/IEngineStore.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/IEngineStore.cs	(revision 279)
@@ -30,5 +30,5 @@
   interface IEngineStore {
     [OperationContract]
-    bool TryTakeEngine(string clientUrl, out Guid guid, out byte[] engine);
+    bool TryTakeEngine(out Guid guid, out byte[] engine);
 
     [OperationContract]
Index: /branches/3.0/sources/HeuristicLab.Grid/IGridServer.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/IGridServer.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/IGridServer.cs	(revision 279)
@@ -26,6 +26,16 @@
 
 namespace HeuristicLab.Grid {
+  public enum JobState {
+    Unkown,
+    Waiting,
+    Busy,
+    Finished
+  }
+
+
   [ServiceContract(Namespace = "http://HeuristicLab.Grid")]
   public interface IGridServer {
+    [OperationContract]
+    JobState JobState(Guid guid);
     [OperationContract]
     Guid BeginExecuteEngine(byte[] engine);
Index: /branches/3.0/sources/HeuristicLab.Grid/ProcessingEngine.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/ProcessingEngine.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/ProcessingEngine.cs	(revision 279)
@@ -39,9 +39,8 @@
     }
 
-    public ProcessingEngine(IOperatorGraph graph, IScope globalScope, AtomicOperation initialOperation)
+    public ProcessingEngine(IScope globalScope, AtomicOperation initialOperation)
       : base() {
       this.initialOperation = initialOperation;
       myGlobalScope = globalScope;
-      myOperatorGraph = graph;
       myExecutionStack.Push(initialOperation);
     }
@@ -68,9 +67,7 @@
           myExecutionStack.Push(atomicOperation);
           Abort();
-          ThreadPool.QueueUserWorkItem(delegate(object state) { OnExceptionOccurred(ex); });
         }
         if(next != null)
           myExecutionStack.Push(next);
-        OnOperationExecuted(atomicOperation);
         if(atomicOperation.Operator.Breakpoint) Abort();
       } else if(operation is CompositeOperation) {
Index: /branches/3.0/sources/HeuristicLab.Grid/ServerForm.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/ServerForm.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/ServerForm.cs	(revision 279)
@@ -52,13 +52,15 @@
         internalAddressTextBox.Text = "net.tcp://" + Dns.GetHostAddresses(Dns.GetHostName())[0] + ":8001/Grid/JobStore";
       }
-
       jobStore = new EngineStore();
       server = new GridServer(jobStore);
-      
+      Start();
     }
 
-    private void startButton_Click(object sender, EventArgs e) {
+    private void Start() {
       externalHost = new ServiceHost(server, new Uri(externalAddressTextBox.Text));
       internalHost = new ServiceHost(jobStore, new Uri(internalAddressTextBox.Text));
+      ServiceThrottlingBehavior throttlingBehavior = new ServiceThrottlingBehavior();
+      throttlingBehavior.MaxConcurrentSessions = 20;
+      internalHost.Description.Behaviors.Add(throttlingBehavior);
       try {
         NetTcpBinding binding = new NetTcpBinding();
@@ -67,4 +69,5 @@
         binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
         binding.Security.Mode = SecurityMode.None;
+        
 
         externalHost.AddServiceEndpoint(typeof(IGridServer), binding, externalAddressTextBox.Text);
@@ -73,7 +76,4 @@
         internalHost.AddServiceEndpoint(typeof(IEngineStore), binding, internalAddressTextBox.Text);
         internalHost.Open();
-
-        startButton.Enabled = false;
-        stopButton.Enabled = true;
       } catch (CommunicationException ex) {
         MessageBox.Show("An exception occurred: " + ex.Message);
@@ -82,12 +82,4 @@
       }
     }
-
-    private void stopButton_Click(object sender, EventArgs e) {
-      externalHost.Close();
-      internalHost.Close();
-      stopButton.Enabled = false;
-      startButton.Enabled = true;
-    }
-
     private void statusUpdateTimer_Tick(object sender, EventArgs e) {
       waitingJobsTextBox.Text = jobStore.WaitingJobs+"";
Index: /branches/3.0/sources/HeuristicLab.Grid/ServerForm.designer.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Grid/ServerForm.designer.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Grid/ServerForm.designer.cs	(revision 279)
@@ -47,6 +47,4 @@
       this.components = new System.ComponentModel.Container();
       this.externalAddressTextBox = new System.Windows.Forms.TextBox();
-      this.startButton = new System.Windows.Forms.Button();
-      this.stopButton = new System.Windows.Forms.Button();
       this.externalAddressLabel = new System.Windows.Forms.Label();
       this.internalAddressLabel = new System.Windows.Forms.Label();
@@ -68,27 +66,4 @@
       this.externalAddressTextBox.Size = new System.Drawing.Size(229, 20);
       this.externalAddressTextBox.TabIndex = 0;
-      // 
-      // startButton
-      // 
-      this.startButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
-      this.startButton.Location = new System.Drawing.Point(12, 160);
-      this.startButton.Name = "startButton";
-      this.startButton.Size = new System.Drawing.Size(75, 23);
-      this.startButton.TabIndex = 1;
-      this.startButton.Text = "St&art";
-      this.startButton.UseVisualStyleBackColor = true;
-      this.startButton.Click += new System.EventHandler(this.startButton_Click);
-      // 
-      // stopButton
-      // 
-      this.stopButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
-      this.stopButton.Enabled = false;
-      this.stopButton.Location = new System.Drawing.Point(99, 160);
-      this.stopButton.Name = "stopButton";
-      this.stopButton.Size = new System.Drawing.Size(75, 23);
-      this.stopButton.TabIndex = 2;
-      this.stopButton.Text = "St&op";
-      this.stopButton.UseVisualStyleBackColor = true;
-      this.stopButton.Click += new System.EventHandler(this.stopButton_Click);
       // 
       // externalAddressLabel
@@ -185,5 +160,5 @@
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.ClientSize = new System.Drawing.Size(347, 195);
+      this.ClientSize = new System.Drawing.Size(347, 150);
       this.Controls.Add(this.waitingResultsLabel);
       this.Controls.Add(this.waitingResultsTextBox);
@@ -195,6 +170,4 @@
       this.Controls.Add(this.internalAddressTextBox);
       this.Controls.Add(this.externalAddressLabel);
-      this.Controls.Add(this.stopButton);
-      this.Controls.Add(this.startButton);
       this.Controls.Add(this.externalAddressTextBox);
       this.Name = "ServerForm";
@@ -208,6 +181,4 @@
 
     private System.Windows.Forms.TextBox externalAddressTextBox;
-    private System.Windows.Forms.Button startButton;
-    private System.Windows.Forms.Button stopButton;
     private System.Windows.Forms.Label externalAddressLabel;
     private System.Windows.Forms.Label internalAddressLabel;
Index: /branches/3.0/sources/HeuristicLab.PluginInfrastructure/ApplicationInfo.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.PluginInfrastructure/ApplicationInfo.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.PluginInfrastructure/ApplicationInfo.cs	(revision 279)
@@ -46,8 +46,13 @@
     }
 
+    private bool autoRestart;
+    public bool AutoRestart {
+      get { return autoRestart; }
+      set { autoRestart = value; }
+    }
+
     private string pluginAssembly;
     /// <summary>
     /// Name of the assembly that contains the IApplication type.
-    /// NEEDED?
     /// </summary>
     public string PluginAssembly {
@@ -59,5 +64,4 @@
     /// <summary>
     /// Name of the type that implements the interface IApplication.
-    /// NEEDED?
     /// </summary>
     public string PluginType {
Index: /branches/3.0/sources/HeuristicLab.PluginInfrastructure/BaseClasses/ApplicationBase.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.PluginInfrastructure/BaseClasses/ApplicationBase.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.PluginInfrastructure/BaseClasses/ApplicationBase.cs	(revision 279)
@@ -30,5 +30,6 @@
     private Version version;
     private string description;
-    
+    private bool autoRestart;
+
     public ApplicationBase() {
       ReadAttributes();
@@ -45,24 +46,27 @@
       // after the assertion we are sure that the array access will not fail
       ClassInfoAttribute pluginAttribute = (ClassInfoAttribute)pluginAttributes[0];
+      if(pluginAttribute != null) {
+        // if the plugin name is not explicitly set in the attribute then the default plugin name is the FullName of the type
+        if(pluginAttribute.Name != null) {
+          this.name = pluginAttribute.Name;
+        } else {
+          this.name = this.GetType().FullName;
+        }
 
-      // if the plugin name is not explicitly set in the attribute then the default plugin name is the FullName of the type
-      if(pluginAttribute != null && pluginAttribute.Name != null) {
-        this.name = pluginAttribute.Name;
-      } else {
-        this.name = this.GetType().FullName;
-      }
+        // if the version is not explicitly set in the attribute then the version of the assembly is used as default
+        if(pluginAttribute.Version != null) {
+          this.version = new Version(pluginAttribute.Version);
+        } else {
+          this.version = this.GetType().Assembly.GetName().Version;
+        }
 
-      // if the version is not explicitly set in the attribute then the version of the assembly is used as default
-      if(pluginAttribute != null && pluginAttribute.Version != null) {
-        this.version = new Version(pluginAttribute.Version);
-      } else {
-        this.version = this.GetType().Assembly.GetName().Version;
-      }
+        // if the description is not explicitly set in the attribute then the name of name of the application is used as default
+        if(pluginAttribute.Description != null) {
+          this.description = pluginAttribute.Description;
+        } else {
+          this.description = name;
+        }
 
-      // if the description is not explicitly set in the attribute then the name of name of the application is used as default
-      if(pluginAttribute != null && pluginAttribute.Description != null) {
-        this.description = pluginAttribute.Description;
-      } else {
-        this.description = name;
+        this.autoRestart = pluginAttribute.AutoRestart;
       }
     }
@@ -83,5 +87,9 @@
     }
 
-    public abstract void Run() ;
+    public bool AutoRestart {
+      get { return autoRestart; }
+    }
+
+    public abstract void Run();
 
     #endregion
Index: /branches/3.0/sources/HeuristicLab.PluginInfrastructure/ClassInfoAttribute.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.PluginInfrastructure/ClassInfoAttribute.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.PluginInfrastructure/ClassInfoAttribute.cs	(revision 279)
@@ -52,4 +52,10 @@
     }
 
+    private bool autoRestart;
+    public bool AutoRestart {
+      get { return autoRestart; }
+      set { autoRestart = value; }
+    }
+
     public ClassInfoAttribute() {}
   }
Index: /branches/3.0/sources/HeuristicLab.PluginInfrastructure/Interfaces/IApplication.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.PluginInfrastructure/Interfaces/IApplication.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.PluginInfrastructure/Interfaces/IApplication.cs	(revision 279)
@@ -29,4 +29,5 @@
     Version Version { get; }
     string Description { get;}
+    bool AutoRestart { get; }
     void Run();
   }
Index: /branches/3.0/sources/HeuristicLab.PluginInfrastructure/Loader.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.PluginInfrastructure/Loader.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.PluginInfrastructure/Loader.cs	(revision 279)
@@ -120,4 +120,5 @@
         info.Version = application.Version;
         info.Description = application.Description;
+        info.AutoRestart = application.AutoRestart;
         info.PluginAssembly = application.GetType().Assembly.GetName().Name;
         info.PluginType = application.GetType().Namespace + "." + application.GetType().Name;
Index: /branches/3.0/sources/HeuristicLab.PluginInfrastructure/PluginManager.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.PluginInfrastructure/PluginManager.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.PluginInfrastructure/PluginManager.cs	(revision 279)
@@ -103,12 +103,17 @@
       setup.PrivateBinPath = pluginDir;
       AppDomain applicationDomain = AppDomain.CreateDomain(appInfo.Name + " AppDomain", null, setup);
-
-      Runner remoteRunner = (Runner)applicationDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfrastructure", "HeuristicLab.PluginInfrastructure.Runner");
-      NotifyListeners(PluginManagerAction.Initializing, "All plugins");
-      remoteRunner.LoadPlugins(remoteLoader.ActivePlugins);
-      NotifyListeners(PluginManagerAction.Initialized, "All plugins");
-      remoteRunner.Run(appInfo);
-
-      AppDomain.Unload(applicationDomain);
+      try {
+        Runner remoteRunner = (Runner)applicationDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfrastructure", "HeuristicLab.PluginInfrastructure.Runner");
+        NotifyListeners(PluginManagerAction.Initializing, "All plugins");
+        remoteRunner.LoadPlugins(remoteLoader.ActivePlugins);
+        NotifyListeners(PluginManagerAction.Initialized, "All plugins");
+        remoteRunner.Run(appInfo);
+      } catch(Exception ex) {
+        // can't handle exception here -> rethrow 
+        throw new ApplicationException("Exception in "+appInfo.Name, ex);
+      } finally {
+        // make sure domain is unloaded in all cases
+        AppDomain.Unload(applicationDomain);
+      }
     }
 
Index: /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/HeuristicLab.Scheduling.JSSP.csproj
===================================================================
--- /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/HeuristicLab.Scheduling.JSSP.csproj	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/HeuristicLab.Scheduling.JSSP.csproj	(revision 279)
@@ -37,5 +37,5 @@
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
Index: /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/HeuristicLabJSSPPlugin.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/HeuristicLabJSSPPlugin.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/HeuristicLabJSSPPlugin.cs	(revision 279)
@@ -32,5 +32,5 @@
   [Dependency(Dependency = "HeuristicLab.Operators")]
   [Dependency(Dependency = "HeuristicLab.Permutation")]
-  public class HeuristicLabRoutingTSPPlugin : PluginBase {
+  public class HeuristicLabSchedulingJSPPlugin : PluginBase {
   }
 }
Index: /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/OperationUpdater.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/OperationUpdater.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab.Scheduling.JSSP/OperationUpdater.cs	(revision 279)
@@ -52,5 +52,4 @@
             op.Predecessors.RemoveAt(index); // remove scheduled op from predecessor list
             op.Start = scheduledOp.Start + scheduledOp.Duration; // new earliest start date
-            return null;
           }
         }
Index: /branches/3.0/sources/HeuristicLab/MainForm.cs
===================================================================
--- /branches/3.0/sources/HeuristicLab/MainForm.cs	(revision 278)
+++ /branches/3.0/sources/HeuristicLab/MainForm.cs	(revision 279)
@@ -94,5 +94,15 @@
           PluginManager.Manager.Action += new PluginManagerActionEventHandler(splashScreen.Manager_Action);
           Thread t = new Thread(delegate() {
-            PluginManager.Manager.Run(app);
+            bool stopped = false;
+            do {
+              try {
+                PluginManager.Manager.Run(app);
+                stopped = true;
+              } catch(Exception ex) {
+                stopped = false;
+                ThreadPool.QueueUserWorkItem(delegate(object exception) { ShowErrorMessageBox((Exception)exception); }, ex);
+                Thread.Sleep(5000); // sleep 5 seconds before autorestart
+              }
+            } while(!stopped && app.AutoRestart);
           });
           t.SetApartmentState(ApartmentState.STA); // needed for the AdvancedOptimizationFrontent
@@ -122,4 +132,20 @@
     }
 
+    public void ShowErrorMessageBox(Exception ex) {
+      MessageBox.Show(BuildErrorMessage(ex),
+                      "Error - " + ex.GetType().Name,
+                      MessageBoxButtons.OK,
+                      MessageBoxIcon.Error);
+    }
+    private string BuildErrorMessage(Exception ex) {
+      StringBuilder sb = new StringBuilder();
+      sb.Append("Sorry, but something went wrong!\n\n" + ex.Message + "\n\n" + ex.StackTrace);
+
+      while(ex.InnerException != null) {
+        ex = ex.InnerException;
+        sb.Append("\n\n-----\n\n" + ex.Message + "\n\n" + ex.StackTrace);
+      }
+      return sb.ToString();
+    }
   }
 }
