Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/HiveExperimentView.Designer.cs
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/HiveExperimentView.Designer.cs	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/HiveExperimentView.Designer.cs	(revision 4173)
@@ -54,4 +54,6 @@
       this.hiveStatusTabPage = new System.Windows.Forms.TabPage();
       this.jobListView = new HeuristicLab.Hive.Experiment.Views.JobItemListView();
+      this.runsTabPage = new System.Windows.Forms.TabPage();
+      this.runCollectionView = new HeuristicLab.Optimization.Views.RunCollectionView();
       this.logTabPage = new System.Windows.Forms.TabPage();
       this.logView = new HeuristicLab.Core.Views.LogView();
@@ -68,12 +70,10 @@
       this.disconnectButton = new System.Windows.Forms.Button();
       this.reconnectButton = new System.Windows.Forms.Button();
-      this.runsTabPage = new System.Windows.Forms.TabPage();
-      this.runCollectionView = new HeuristicLab.Optimization.Views.RunCollectionView();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
       this.tabControl.SuspendLayout();
       this.experimentTabPage.SuspendLayout();
       this.hiveStatusTabPage.SuspendLayout();
+      this.runsTabPage.SuspendLayout();
       this.logTabPage.SuspendLayout();
-      this.runsTabPage.SuspendLayout();
       this.SuspendLayout();
       // 
@@ -187,4 +187,27 @@
       this.jobListView.TabIndex = 0;
       // 
+      // runsTabPage
+      // 
+      this.runsTabPage.Controls.Add(this.runCollectionView);
+      this.runsTabPage.Location = new System.Drawing.Point(4, 22);
+      this.runsTabPage.Name = "runsTabPage";
+      this.runsTabPage.Size = new System.Drawing.Size(727, 369);
+      this.runsTabPage.TabIndex = 4;
+      this.runsTabPage.Text = "Runs";
+      this.runsTabPage.UseVisualStyleBackColor = true;
+      // 
+      // runCollectionView
+      // 
+      this.runCollectionView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+                  | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.runCollectionView.Caption = "RunCollection View";
+      this.runCollectionView.Content = null;
+      this.runCollectionView.Location = new System.Drawing.Point(0, 3);
+      this.runCollectionView.Name = "runCollectionView";
+      this.runCollectionView.ReadOnly = false;
+      this.runCollectionView.Size = new System.Drawing.Size(727, 366);
+      this.runCollectionView.TabIndex = 0;
+      // 
       // logTabPage
       // 
@@ -322,9 +345,9 @@
       this.disconnectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
       this.disconnectButton.Enabled = false;
-      this.disconnectButton.Image = ((System.Drawing.Image)(resources.GetObject("disconnectButton.Image")));
-      this.disconnectButton.Location = new System.Drawing.Point(120, 500);
+      this.disconnectButton.Location = new System.Drawing.Point(131, 500);
       this.disconnectButton.Name = "disconnectButton";
-      this.disconnectButton.Size = new System.Drawing.Size(24, 24);
+      this.disconnectButton.Size = new System.Drawing.Size(120, 24);
       this.disconnectButton.TabIndex = 15;
+      this.disconnectButton.Text = "Disconnect from Hive";
       this.toolTip.SetToolTip(this.disconnectButton, "Disconnect from Hive (Jobs will be continue to be calculated)");
       this.disconnectButton.UseVisualStyleBackColor = true;
@@ -335,46 +358,22 @@
       this.reconnectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
       this.reconnectButton.Enabled = false;
-      this.reconnectButton.Image = ((System.Drawing.Image)(resources.GetObject("reconnectButton.Image")));
-      this.reconnectButton.Location = new System.Drawing.Point(150, 500);
+      this.reconnectButton.Location = new System.Drawing.Point(257, 500);
       this.reconnectButton.Name = "reconnectButton";
-      this.reconnectButton.Size = new System.Drawing.Size(24, 24);
+      this.reconnectButton.Size = new System.Drawing.Size(77, 24);
       this.reconnectButton.TabIndex = 16;
+      this.reconnectButton.Text = "Reconnect";
       this.toolTip.SetToolTip(this.reconnectButton, "Reconnect to Hive");
       this.reconnectButton.UseVisualStyleBackColor = true;
       this.reconnectButton.Click += new System.EventHandler(this.reconnectButton_Click);
       // 
-      // runsTabPage
-      // 
-      this.runsTabPage.Controls.Add(this.runCollectionView);
-      this.runsTabPage.Location = new System.Drawing.Point(4, 22);
-      this.runsTabPage.Name = "runsTabPage";
-      this.runsTabPage.Size = new System.Drawing.Size(727, 369);
-      this.runsTabPage.TabIndex = 4;
-      this.runsTabPage.Text = "Runs";
-      this.runsTabPage.UseVisualStyleBackColor = true;
-      // 
-      // runCollectionView
-      // 
-      this.runCollectionView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
-      this.runCollectionView.Caption = "RunCollection View";
-      this.runCollectionView.Content = null;
-      this.runCollectionView.Location = new System.Drawing.Point(0, 3);
-      this.runCollectionView.Name = "runCollectionView";
-      this.runCollectionView.ReadOnly = false;
-      this.runCollectionView.Size = new System.Drawing.Size(727, 366);
-      this.runCollectionView.TabIndex = 0;
-      // 
       // HiveExperimentView
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.reconnectButton);
-      this.Controls.Add(this.disconnectButton);
       this.Controls.Add(this.resourceIdsTextBox);
       this.Controls.Add(this.serverUrlTextBox);
       this.Controls.Add(this.resourceIdsLabel);
       this.Controls.Add(this.tabControl);
+      this.Controls.Add(this.disconnectButton);
       this.Controls.Add(this.startButton);
       this.Controls.Add(this.executionTimeTextBox);
@@ -384,6 +383,8 @@
       this.Controls.Add(this.stopButton);
       this.Controls.Add(this.resetButton);
+      this.Controls.Add(this.reconnectButton);
       this.Name = "HiveExperimentView";
       this.Size = new System.Drawing.Size(735, 524);
+      this.Controls.SetChildIndex(this.reconnectButton, 0);
       this.Controls.SetChildIndex(this.resetButton, 0);
       this.Controls.SetChildIndex(this.stopButton, 0);
@@ -393,10 +394,9 @@
       this.Controls.SetChildIndex(this.executionTimeTextBox, 0);
       this.Controls.SetChildIndex(this.startButton, 0);
+      this.Controls.SetChildIndex(this.disconnectButton, 0);
       this.Controls.SetChildIndex(this.tabControl, 0);
       this.Controls.SetChildIndex(this.resourceIdsLabel, 0);
       this.Controls.SetChildIndex(this.serverUrlTextBox, 0);
       this.Controls.SetChildIndex(this.resourceIdsTextBox, 0);
-      this.Controls.SetChildIndex(this.disconnectButton, 0);
-      this.Controls.SetChildIndex(this.reconnectButton, 0);
       this.Controls.SetChildIndex(this.nameLabel, 0);
       this.Controls.SetChildIndex(this.descriptionLabel, 0);
@@ -407,6 +407,6 @@
       this.experimentTabPage.ResumeLayout(false);
       this.hiveStatusTabPage.ResumeLayout(false);
+      this.runsTabPage.ResumeLayout(false);
       this.logTabPage.ResumeLayout(false);
-      this.runsTabPage.ResumeLayout(false);
       this.ResumeLayout(false);
       this.PerformLayout();
Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/HiveExperimentView.resx
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/HiveExperimentView.resx	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/HiveExperimentView.resx	(revision 4173)
@@ -128,6 +128,6 @@
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALDQAA
-        Cw0B7QfALAAAAn9JREFUOE+lk2tI01EYxhf0oU8WqVEIRpaIBWJgSPUhROmippS3QkkTylsXDMW8ts3b
+        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALDAAA
+        CwwBP0AiyAAAAn9JREFUOE+lk2tI01EYxhf0oU8WqVEIRpaIBWJgSPUhROmippS3QkkTylsXDMW8ts3b
         1G06daVibuqaOq0sxbBCKBSJ0PJCialZUFSKqaGSt1//TbIsww8deOBwznl+5zkv71kHiP5rGAFrKb1Q
         5ypR6bmaVU6m2kCiXJv007Om2XgwJEaNT4QiyDi/GF9mKRVgsWkav+CYQkR1utwAQfypphqZ4l/JIhOL
@@ -146,6 +146,6 @@
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALDQAA
-        Cw0B7QfALAAAAaJJREFUOE+Nkk1LAkEYx5egU9Sla9AX6NKhLlH3IujSoXtBn0EI+gB5qVBIKyIMtEDo
+        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALDAAA
+        CwwBP0AiyAAAAaJJREFUOE+Nkk1LAkEYx5egU9Sla9AX6NKhLlH3IujSoXtBn0EI+gB5qVBIKyIMtEDo
         BUIhK6qDSUj4gqYloilmvqa5rrr/Zlx3dkU0B/48z87O/zfzPDMcAE7SOg8sB2AkqYdIXIoAK4LyX17X
         HiVzYPhC0NBUB1yR6Jfy5lx59rQXRAKEhl6Y4YhMnXOSmUDywRlYHV5YbG6YLp1UW2pgEyBoSdARbdNP
@@ -160,6 +160,6 @@
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAgAA
-        CwIBm8luNgAAALZJREFUOE9j/P//PwNFAGQAOi7bn+2GTRybGIZmkKKEGRH/iTUEpwGWZfpEGYLVgKgp
+        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAQAA
+        CwEBNnBPWwAAALZJREFUOE9j/P//PwNFAGQAOi7bn+2GTRybGIZmkKKEGRH/iTUEpwGWZfpEGYLVgKgp
         Qf833Fr8nxhDsBoQPMEbZDtRhmA1wKfLGWwACEctCsDrEqwGODZb/M/YEAvWbNus/1+nWOG/RBo3iFZD
         jwmsBpjX6KFo5k9gwaoZnIawxa1eqTLcZnyacRqgki8FdjYhzTgNkM4QJEozTgNEkjlx+pmoQMQW2rjy
@@ -170,6 +170,6 @@
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAgAA
-        CwIBm8luNgAAAXJJREFUOE+tkj1IQmEYhWsoaIi2xmhpiYSgKFoiCMLJJYSEJiEI0mgIyqjA6vaLUKIU
+        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAQAA
+        CwEBNnBPWwAAAXJJREFUOE+tkj1IQmEYhWsoaIi2xmhpiYSgKFoiCMLJJYSEJiEI0mgIyqjA6vaLUKIU
         iZlJKKUoWEbZDzVYCYlQYVxcNDIoRND8ud7idD83C27g7YNvPM8573nfcgBlgh4BCPmCxIX0Qtx/ATTu
         Lyy78ph3ZKC2pTBlSWB86w2jhleMrD9jWB9N/jQsSkDEj5FPPERZ+J7yOL5j4PYzsPsYGL1piKR7nL64
@@ -183,6 +183,6 @@
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAgAA
-        CwIBm8luNgAAAYNJREFUOE9j/P//PwNFAGQAJZgizWDXI9veu/nvfxhuW/vtf+OKz/9rF7//XzHv1f+S
+        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAQAA
+        CwEBNnBPWwAAAYNJREFUOE9j/P//PwNFAGQAJZgizWDXI9veu/nvfxhuW/vtf+OKz/9rF7//XzHv1f+S
         2c//F0x//L901mOgFoSrUQzo2vDr/6aT3/6vPPTl/4I9n/5ffvDzf+/ad/+bl74BG5I3/cV/3dBVuA0A
         2bri4Jf/83Z9+n/ryS+Qwv8NS978L5378n/O1Of/k3qf/Vf1W4TbAJCT5+z49P/hyx9gzSBQMvvl/6wp
@@ -196,14 +196,4 @@
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAgAA
-        CwIBm8luNgAAAMZJREFUOE9j/P//PwNFAGQAJZgizWDXU2I7VgN6N//937Xh1/+8qY8+gRSg89EtxHAB
-        SPPVh3/+64auAqr9z4DOJ2hA29pv/289/f1f1W8R2AB0PkEDGld8/n/54e//cm6zwAag8wkaULv4/f8T
-        13//F7ObBDYAnU/QgIp5r/7vvvDzP79ZN9gAdD5BA0pmP/+//uTP/5wGrWAD0PkEDSiY/vj/gj2f/7Pq
-        NIINQOcTNAAU/2y6TXAD0PkEDSA1ZVI/KZPqAgBmE8VVB/UQsAAAAABJRU5ErkJggg==
-</value>
-  </data>
-  <data name="disconnectButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
         YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAQAA
         CwEBNnBPWwAAAMZJREFUOE9j/P//PwNFAGQAJZgizWDXU2I7VgN6N//937Xh1/+8qY8+gRSg89EtxHAB
@@ -213,13 +203,3 @@
 </value>
   </data>
-  <data name="reconnectButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAAAA
-        CwAB5DetvwAAAMZJREFUOE9j/P//PwNFAGQAJZgizWDXU2I7VgN6N//937Xh1/+8qY8+gRSg89EtxHAB
-        SPPVh3/+64auAqr9z4DOJ2hA29pv/289/f1f1W8R2AB0PkEDGld8/n/54e//cm6zwAag8wkaULv4/f8T
-        13//F7ObBDYAnU/QgIp5r/7vvvDzP79ZN9gAdD5BA0pmP/+//uTP/5wGrWAD0PkEDSiY/vj/gj2f/7Pq
-        NIINQOcTNAAU/2y6TXAD0PkEDSA1ZVI/KZPqAgBmE8VVB/UQsAAAAABJRU5ErkJggg==
-</value>
-  </data>
 </root>
Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/JobItemView.Designer.cs
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/JobItemView.Designer.cs	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/JobItemView.Designer.cs	(revision 4173)
@@ -262,4 +262,5 @@
       this.snapshotGroupBox.TabStop = false;
       this.snapshotGroupBox.Text = "Latest Snapshot";
+      this.snapshotGroupBox.Visible = false;
       // 
       // requestSnapshotButton
@@ -433,5 +434,5 @@
       this.logTabPage.Name = "logTabPage";
       this.logTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.logTabPage.Size = new System.Drawing.Size(545, 453);
+      this.logTabPage.Size = new System.Drawing.Size(619, 492);
       this.logTabPage.TabIndex = 1;
       this.logTabPage.Text = "Log";
Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/JobItemView.cs
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/JobItemView.cs	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment.Views/3.3/JobItemView.cs	(revision 4173)
@@ -102,23 +102,27 @@
 
     protected override void SetEnabledStateOfControls() {
-      base.SetEnabledStateOfControls();
-      if (Content != null) {
-        openSnapshotButton.Enabled = Content.LatestSnapshot != null && Content.SnapshotRequestedState == SnapshotRequestedState.Idle;
-        requestSnapshotButton.Enabled = Content.SnapshotRequestedState == SnapshotRequestedState.Idle;
+      if (InvokeRequired) {
+        this.InvokeIfRequired(c => { SetEnabledStateOfControls(); });
+      } else {
+        base.SetEnabledStateOfControls();
+        if (Content != null) {
+          openSnapshotButton.Enabled = Content.LatestSnapshot != null && Content.SnapshotRequestedState == SnapshotRequestedState.Idle;
+          requestSnapshotButton.Enabled = Content.SnapshotRequestedState == SnapshotRequestedState.Idle;
+        }
+        this.jobIdTextBox.ReadOnly = this.ReadOnly;
+        this.stateTextBox.ReadOnly = this.ReadOnly;
+        this.userIdTextBox.ReadOnly = this.ReadOnly;
+        this.percentageTextBox.ReadOnly = this.ReadOnly;
+        this.dateCreatedTextBox.ReadOnly = this.ReadOnly;
+        this.dateCalculatedText.ReadOnly = this.ReadOnly;
+        this.dateFinishedTextBox.ReadOnly = this.ReadOnly;
+        this.priorityTextBox.ReadOnly = this.ReadOnly;
+        this.coresNeededTextBox.ReadOnly = this.ReadOnly;
+        this.memoryNeededTextBox.ReadOnly = this.ReadOnly;
+        this.exceptionTextBox.ReadOnly = this.ReadOnly;
+        this.projectTextBox.ReadOnly = this.ReadOnly;
+        this.snapshotStatusText.ReadOnly = this.ReadOnly;
+        this.snapshotTimeText.ReadOnly = this.ReadOnly;
       }
-      this.jobIdTextBox.ReadOnly = this.ReadOnly;
-      this.stateTextBox.ReadOnly = this.ReadOnly;
-      this.userIdTextBox.ReadOnly = this.ReadOnly;
-      this.percentageTextBox.ReadOnly = this.ReadOnly;
-      this.dateCreatedTextBox.ReadOnly = this.ReadOnly;
-      this.dateCalculatedText.ReadOnly = this.ReadOnly;
-      this.dateFinishedTextBox.ReadOnly = this.ReadOnly;
-      this.priorityTextBox.ReadOnly = this.ReadOnly;
-      this.coresNeededTextBox.ReadOnly = this.ReadOnly;
-      this.memoryNeededTextBox.ReadOnly = this.ReadOnly;
-      this.exceptionTextBox.ReadOnly = this.ReadOnly;
-      this.projectTextBox.ReadOnly = this.ReadOnly;
-      this.snapshotStatusText.ReadOnly = this.ReadOnly;
-      this.snapshotTimeText.ReadOnly = this.ReadOnly;
     }
 
Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment/3.3/HiveExperiment.cs
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment/3.3/HiveExperiment.cs	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment/3.3/HiveExperiment.cs	(revision 4173)
@@ -65,6 +65,7 @@
     private Semaphore fetchJobSemaphore = new Semaphore(2, 2);
 
-    [Storable]
-    private DateTime lastUpdateTime;
+    private bool stopResultsPollingPending = false;
+
+    private Thread resultPollingThread;
 
     private bool isPollingResults;
@@ -79,7 +80,17 @@
     }
 
-    private bool stopResultsPollingPending = false;
-
-    private Thread resultPollingThread;
+    public IEnumerable<string> ResourceGroups {
+      get {
+        if (!string.IsNullOrEmpty(resourceIds)) {
+          return resourceIds.Split(';');
+        } else {
+          return new List<string>();
+        }
+      }
+    }
+    
+    #region Storable Properties
+    [Storable]
+    private DateTime lastUpdateTime;
 
     /// <summary>
@@ -146,4 +157,29 @@
       get { return log; }
     }
+
+    [Storable]
+    private Core.ExecutionState executionState;
+    public ExecutionState ExecutionState {
+      get { return executionState; }
+      private set {
+        if (executionState != value) {
+          executionState = value;
+          OnExecutionStateChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private TimeSpan executionTime;
+    public TimeSpan ExecutionTime {
+      get { return executionTime; }
+      private set {
+        if (executionTime != value) {
+          executionTime = value;
+          OnExecutionTimeChanged();
+        }
+      }
+    }
+    #endregion
 
     [StorableConstructor]
@@ -198,4 +234,5 @@
     }
 
+    #region Execution Time Timer
     private void InitTimer() {
       timer = new System.Timers.Timer(100);
@@ -209,40 +246,7 @@
       lastUpdateTime = now;
     }
-
-    public IEnumerable<string> ResourceGroups {
-      get {
-        if (!string.IsNullOrEmpty(resourceIds)) {
-          return resourceIds.Split(';');
-        } else {
-          return new List<string>();
-        }
-      }
-    }
-    #region IExecutable Members
-
-    [Storable]
-    private Core.ExecutionState executionState;
-    public ExecutionState ExecutionState {
-      get { return executionState; }
-      private set {
-        if (executionState != value) {
-          executionState = value;
-          OnExecutionStateChanged();
-        }
-      }
-    }
-
-    [Storable]
-    private TimeSpan executionTime;
-    public TimeSpan ExecutionTime {
-      get { return executionTime; }
-      private set {
-        if (executionTime != value) {
-          executionTime = value;
-          OnExecutionTimeChanged();
-        }
-      }
-    }
-
+    #endregion
+
+    #region IExecutable Methods
     public void Pause() {
       throw new NotSupportedException();
@@ -252,7 +256,11 @@
       if (experiment != null) {
         StopResultPolling();
-        pendingOptimizersByJobId.Clear();
+        lock (pendingOptimizersByJobId) {
+          pendingOptimizersByJobId.Clear();
+        }
         parentOptimizersByPendingOptimizer.Clear();
-        jobItems.Clear();
+        lock (jobItems) {
+          jobItems.Clear();
+        }
         experiment.Prepare();
         this.ExecutionState = Core.ExecutionState.Prepared;
@@ -262,4 +270,5 @@
 
     public void Start() {
+      sendingJobsFinished = false;
       OnStarted();
       ExecutionTime = new TimeSpan();
@@ -270,5 +279,5 @@
       Thread t = new Thread(() => {
         IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
-        
+
         try {
           pendingOptimizersByJobId = new Dictionary<Guid, IOptimizer>();
@@ -277,12 +286,13 @@
           parentOptimizersByPendingOptimizer = GetOptimizers(true);
           LogMessage("Extraction of jobs from Experiment finished");
-          
+
           IEnumerable<string> groups = ResourceGroups;
 
-          sendingJobsFinished = false;
           foreach (IOptimizer optimizer in parentOptimizersByPendingOptimizer.Keys) {
             SerializedJob serializedJob = CreateSerializedJob(optimizer);
             ResponseObject<JobDto> response = executionEngineFacade.AddJobWithGroupStrings(serializedJob, groups);
-            pendingOptimizersByJobId.Add(response.Obj.Id, optimizer);
+            lock (pendingOptimizersByJobId) {
+              pendingOptimizersByJobId.Add(response.Obj.Id, optimizer);
+            }
 
             JobItem jobItem = new JobItem() {
@@ -296,5 +306,4 @@
             LogMessage(jobItem.JobDto.Id, "Job sent to Hive");
           }
-          sendingJobsFinished = true;
         } catch (Exception e) {
           LogMessage("Error: Starting HiveExperiment failed: " + e.Message);
@@ -303,4 +312,5 @@
         }
 
+        sendingJobsFinished = true;
       });
       t.Start();
@@ -314,23 +324,7 @@
       OnStopped();
     }
-
-    public void StartResultPolling() {
-      this.stopResultsPollingPending = false;
-      this.IsPollingResults = true;
-      resultPollingThread = CreateResultPollingThread();
-      if (resultPollingThread.ThreadState != System.Threading.ThreadState.Running)
-        resultPollingThread.Start();
-    }
-
-    public void StopResultPolling() {
-      this.stopResultsPollingPending = true;
-      resultPollingThread.Interrupt();
-      this.stopResultsPollingPending = false;
-    }
-
-    private JobItem GetJobItemById(Guid jobId) {
-      return jobItems.Single(x => x.JobDto.Id == jobId);
-    }
-
+    #endregion
+
+    #region Optimizier Management
     /// <summary>
     /// Returns all optimizers in the current Experiment
@@ -381,16 +375,12 @@
         optimizer.Name = prepend + optimizer.Name;
         optimizers.Add(optimizer, parent);
+        LogMessage("Optimizer extracted: " + optimizer.Name);
       } else {
         Logger.Warn("Optimizer of type " + optimizers.GetType().ToString() + " unknown");
         optimizer.Name = prepend + optimizer.Name;
         optimizers.Add(optimizer, parent);
+        LogMessage("Optimizer extracted: " + optimizer.Name);
       }
       return optimizers;
-    }
-
-    private void AddRange(IDictionary<IOptimizer, IOptimizer> optimizers, IDictionary<IOptimizer, IOptimizer> childs) {
-      foreach (KeyValuePair<IOptimizer, IOptimizer> kvp in childs) {
-        optimizers.Add(kvp);
-      }
     }
 
@@ -414,23 +404,92 @@
     }
 
+    private bool NoMorePendingOptimizers() {
+      lock (pendingOptimizersByJobId) {
+        return pendingOptimizersByJobId.Count == 0;
+      }
+    }
+
+    /// <summary>
+    /// Removes optimizers from
+    ///  - parentOptimizersByPendingOptimizer
+    ///  - pendingOptimizersByJobId
+    /// </summary>
+    /// <param name="jobId"></param>
+    private void DisposeOptimizerMappings(Guid jobId) {
+      lock (pendingOptimizersByJobId) {
+        LogMessage(jobId, "Disposing Optimizer Mappings");
+        parentOptimizersByPendingOptimizer.Remove(pendingOptimizersByJobId[jobId]);
+        pendingOptimizersByJobId.Remove(jobId);
+      }
+    }
+
+    #endregion
+
+    #region Job Management
+    /// <summary>
+    /// Updates all JobItems with the results
+    /// </summary>
+    /// <param name="jobResultList"></param>
+    private void UpdateJobItems(JobResultList jobResultList) {
+      // use a Dict to avoid quadratic runtime complexity
+      IDictionary<Guid, JobResult> jobResultDict = jobResultList.ToDictionary(job => job.JobId);
+      lock (jobItems) {
+        foreach (JobItem jobItem in JobItems) {
+          if (jobResultDict.ContainsKey(jobItem.JobDto.Id)) {
+            jobItem.JobResult = jobResultDict[jobItem.JobDto.Id];
+          }
+        }
+      }
+    }
+
+    private void JobItem_JobStateChanged(object sender, EventArgs e) {
+      JobItem jobItem = (JobItem)sender;
+      Thread t = new Thread(() => {
+        if (jobItem.State == State.Finished) {
+          FetchAndUpdateJob(jobItem.JobDto.Id);
+          DisposeOptimizerMappings(jobItem.JobDto.Id);
+        } else if (jobItem.State == State.Failed) {
+          DisposeOptimizerMappings(jobItem.JobDto.Id);
+        }
+
+        if (NoMorePendingOptimizers()) {
+          StopResultPolling();
+          this.ExecutionState = Core.ExecutionState.Stopped;
+          OnStopped();
+        }
+      });
+      t.Start();
+    }
+
+    /// <summary>
+    /// Fetches the finished job from the server and updates the jobItem
+    /// </summary>
+    private void FetchAndUpdateJob(Guid jobId) {
+      LogMessage(jobId, "FetchAndUpdateJob started");
+      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
+      IOptimizer originalOptimizer;
+      lock (pendingOptimizersByJobId) {
+        originalOptimizer = pendingOptimizersByJobId[jobId];
+      }
+
+      fetchJobSemaphore.WaitOne();
+      ResponseObject<SerializedJob> jobResponse = executionEngineFacade.GetLastSerializedResult(jobId, false, false);
+      IJob restoredObject = XmlParser.Deserialize<IJob>(new MemoryStream(jobResponse.Obj.SerializedJobData));
+      IOptimizer restoredOptimizer = ((OptimizerJob)restoredObject).Optimizer;
+
+      ReplaceOptimizer(parentOptimizersByPendingOptimizer[originalOptimizer], originalOptimizer, restoredOptimizer);
+      fetchJobSemaphore.Release();
+      LogMessage(jobId, "FetchAndUpdateJob ended");
+    }
+
+    private void UpdateJobItem(JobDto jobDto) {
+      JobItem jobItem = jobItems.Single(x => x.JobDto.Id == jobDto.Id);
+      jobItem.JobDto = jobDto;
+    }
+
     public void AbortJob(Guid jobId) {
       IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
       Response response = executionEngineFacade.AbortJob(jobId);
       LogMessage(jobId, "Aborting Job: " + response.StatusMessage);
-    }
-
-    #endregion
-
-    private IExecutionEngineFacade GetExecutionEngineFacade() {
-      IExecutionEngineFacade executionEngineFacade = null;
-      do {
-        try {
-          executionEngineFacade = ServiceLocator.CreateExecutionEngineFacade(ServerUrl);
-        } catch (EndpointNotFoundException exception) {
-          LogMessage("Could not connect to Server: " + exception.Message + ". Will try again in " + (resultPollingIntervalMs / 1000) + " sec.");
-          Thread.Sleep(resultPollingIntervalMs);
-        }
-      } while (executionEngineFacade == null && this.ExecutionState != Core.ExecutionState.Stopped);
-      return executionEngineFacade;
     }
 
@@ -470,8 +529,24 @@
     }
 
-    /// <summary>
-    /// Requests a resultList for all jobItems not finished or aborted
-    /// </summary>
-    /// <returns></returns>
+    private JobItem GetJobItemById(Guid jobId) {
+      return jobItems.Single(x => x.JobDto.Id == jobId);
+    }
+    #endregion
+
+    #region Result Polling
+    public void StartResultPolling() {
+      this.stopResultsPollingPending = false;
+      this.IsPollingResults = true;
+      resultPollingThread = CreateResultPollingThread();
+      if (resultPollingThread.ThreadState != System.Threading.ThreadState.Running)
+        resultPollingThread.Start();
+    }
+
+    public void StopResultPolling() {
+      this.stopResultsPollingPending = true;
+      resultPollingThread.Interrupt();
+      this.stopResultsPollingPending = false;
+    }
+
     private Thread CreateResultPollingThread() {
       return new Thread(() => {
@@ -512,175 +587,7 @@
     }
 
-    /// <summary>
-    /// Updates all JobItems with the results
-    /// </summary>
-    /// <param name="jobResultList"></param>
-    private void UpdateJobItems(JobResultList jobResultList) {
-      // use a Dict to avoid quadratic runtime complexity
-      IDictionary<Guid, JobResult> jobResultDict = jobResultList.ToDictionary(job => job.JobId);
-      lock (jobItems) {
-        foreach (JobItem jobItem in JobItems) {
-          if (jobResultDict.ContainsKey(jobItem.JobDto.Id)) {
-            jobItem.JobResult = jobResultDict[jobItem.JobDto.Id];
-          }
-        }
-      }
-    }
-
-    void JobItem_JobStateChanged(object sender, EventArgs e) {
-      JobItem jobItem = (JobItem)sender;
-      Thread t = new Thread(() => {
-        if (jobItem.State == State.Finished) {
-          FetchAndUpdateJob(jobItem.JobDto.Id);
-          DisposeOptimizerMappings(jobItem.JobDto.Id);
-        } else if (jobItem.State == State.Failed) {
-          DisposeOptimizerMappings(jobItem.JobDto.Id);
-        }
-
-        if (NoMorePendingOptimizers()) {
-          StopResultPolling();
-          this.ExecutionState = Core.ExecutionState.Stopped;
-          OnStopped();
-        }
-      });
-      t.Start();
-    }
-
-    private bool NoMorePendingOptimizers() {
-      return pendingOptimizersByJobId.Count == 0;
-    }
-
-    /// <summary>
-    /// Removes optimizers from
-    ///  - parentOptimizersByPendingOptimizer
-    ///  - pendingOptimizersByJobId
-    /// </summary>
-    /// <param name="jobId"></param>
-    private void DisposeOptimizerMappings(Guid jobId) {
-      parentOptimizersByPendingOptimizer.Remove(pendingOptimizersByJobId[jobId]);
-      pendingOptimizersByJobId.Remove(jobId);
-    }
-
-    /// <summary>
-    /// Fetches the finished job from the server and updates the jobItem
-    /// </summary>
-    private void FetchAndUpdateJob(Guid jobId) {
-      LogMessage(jobId, "FetchAndUpdateJob started");
-      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
-      IOptimizer originalOptimizer = pendingOptimizersByJobId[jobId];
-
-      fetchJobSemaphore.WaitOne();
-      ResponseObject<SerializedJob> jobResponse = executionEngineFacade.GetLastSerializedResult(jobId, false, false);
-      UpdateSnapshot(jobResponse);
-
-      IJob restoredObject = XmlParser.Deserialize<IJob>(new MemoryStream(jobResponse.Obj.SerializedJobData));
-      IOptimizer restoredOptimizer = ((OptimizerJob)restoredObject).Optimizer;
-
-      ReplaceOptimizer(parentOptimizersByPendingOptimizer[originalOptimizer], originalOptimizer, restoredOptimizer);
-      fetchJobSemaphore.Release();
-      LogMessage(jobId, "FetchAndUpdateJob ended");
-    }
-
-    //// ensure that not all resultPollingThreads can access the server simultaniously
-    //private Semaphore resultPollingSemaphore = new Semaphore(5, 5);
-
-    //private Thread CreateResultPollingThread(JobDto job) {
-    //  return new Thread(() => {
-    //    try {
-    //      GetJobItemById(job.Id).LogMessage("Starting job results polling");
-    //      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
-    //      IJob restoredObject = null;
-    //      IOptimizer originalOptimizer = pendingOptimizersByJobId[job.Id];
-
-    //      do {
-    //        // loop while 
-    //        // 1. the user doesn't request an abort 
-    //        // 2. there is a problem with server communication (success==false)
-    //        // 3. no result for the job is available yet (response.Obj==null)
-    //        // 4. the result that we get from the server is a snapshot and not the final result
-    //        try {
-    //          resultPollingSemaphore.WaitOne();
-    //          if (stopPending || !this.IsPollingResults) {
-    //            return;
-    //          }
-
-    //          ResponseObject<JobDto> response = null;
-    //          try {
-    //            response = executionEngineFacade.GetJobById(job.Id);
-    //            LogMessage("Response: " + response.StatusMessage + " (jobId: " + job.Id + ")");
-    //            GetJobItemById(job.Id).LogMessage("Response: " + response.StatusMessage);
-
-    //            UpdateJobItem(response.Obj);
-
-    //            if (response.Obj.State == State.Abort) {
-    //              pendingOptimizersByJobId.Remove(job.Id);
-    //              parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
-    //              GetJobItemById(job.Id).LogMessage("Job successfully aborted");
-    //              return;
-    //            }
-
-    //            if (response.Obj.State == State.Failed) {
-    //              pendingOptimizersByJobId.Remove(job.Id);
-    //              parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
-    //              GetJobItemById(job.Id).LogMessage("Job failed with exception: " + response.Obj.Exception);
-    //              return;
-    //            }
-    //          } catch (Exception e) {
-    //            LogMessage("Error: Result polling failed for job (" + job.Id + "): " + e.Message);
-    //            GetJobItemById(job.Id).LogMessage("Error: Result polling failed: " + e.Message);
-    //          }
-
-    //          if (response != null && response.Success && response.Obj != null && response.Obj.State == State.Finished) {
-    //            try {
-    //              ResponseObject<SerializedJob> jobResponse = executionEngineFacade.GetLastSerializedResult(job.Id, false, false);
-    //              restoredObject = XmlParser.Deserialize<IJob>(new MemoryStream(jobResponse.Obj.SerializedJobData));
-    //              UpdateSnapshot(jobResponse);
-    //            } catch (Exception e) {
-    //              LogMessage("Error: Retrieving final result failed for job (" + job.Id + "): " + e.Message);
-    //              GetJobItemById(job.Id).LogMessage("Error: Retrieving final result failed: " + e.Message);
-    //            }
-    //          } else {
-    //            Thread.Sleep(resultPollingIntervalMs);
-    //          }
-    //        } finally {
-    //          // use finally to always release the semaphore lock
-    //          resultPollingSemaphore.Release();
-    //        }
-    //      } while (restoredObject == null || restoredObject.ExecutionState != Core.ExecutionState.Stopped);
-
-    //      LogMessage("Job finished (jobId: " + job.Id + ")");
-    //      GetJobItemById(job.Id).LogMessage("Job finished");
-    //      // job retrieved... replace the existing optimizers with the finished one
-
-    //      IOptimizer restoredOptimizer = ((OptimizerJob)restoredObject).Optimizer;
-
-    //      ReplaceOptimizer(parentOptimizersByPendingOptimizer[originalOptimizer], originalOptimizer, restoredOptimizer);
-    //      pendingOptimizersByJobId.Remove(job.Id);
-    //      parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
-
-    //    } catch (ThreadInterruptedException exception) {
-
-    //    } finally {
-    //      GetJobItemById(job.Id).LogMessage("ResultsPolling Thread stopped");
-    //      //lock (resultPollingThreads) {
-    //      //  resultPollingThreads.Remove(job.Id);
-    //      //  if (resultPollingThreads.Count == 0) {
-    //      //    IsPollingResults = false;
-    //      //  }
-    //      //}
-
-    //      // check if finished
-    //      if (pendingOptimizersByJobId.Count == 0) {
-    //        this.ExecutionState = Core.ExecutionState.Stopped;
-    //        OnStopped();
-    //      }
-    //    }
-    //  });
-    //}
-
-    private void UpdateJobItem(JobDto jobDto) {
-      JobItem jobItem = jobItems.Single(x => x.JobDto.Id == jobDto.Id);
-      jobItem.JobDto = jobDto;
-    }
+    #endregion
+
+    #region Snapshots
 
     private void UpdateSnapshot(ResponseObject<SerializedJob> response) {
@@ -689,14 +596,42 @@
     }
 
-    private void LogMessage(string message) {
-      // HeuristicLab.Log is not Thread-Safe, so lock on every call
-      lock (locker) {
-        log.LogMessage(message);
-      }
-    }
-
-    private void LogMessage(Guid jobId, string message) {
-      GetJobItemById(jobId).LogMessage(message);
-      LogMessage(message + " (jobId: " + jobId + ")");
+    public void RequestSnapshot(Guid jobId) {
+      Thread t = new Thread(() => {
+        IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
+        ResponseObject<SerializedJob> response;
+        int retryCount = 0;
+
+        Response snapShotResponse = executionEngineFacade.RequestSnapshot(jobId);
+        if (snapShotResponse.StatusMessage == ApplicationConstants.RESPONSE_JOB_IS_NOT_BEEING_CALCULATED) {
+          // job already finished
+          Logger.Debug("HiveExperiment: Abort - GetLastResult(false)");
+          response = executionEngineFacade.GetLastSerializedResult(jobId, false, false);
+          Logger.Debug("HiveExperiment: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
+        } else {
+          // server sent snapshot request to client
+          // poll until snapshot is ready
+          do {
+            Thread.Sleep(snapshotPollingIntervalMs);
+            Logger.Debug("HiveExperiment: Abort - GetLastResult(true)");
+            response = executionEngineFacade.GetLastSerializedResult(jobId, false, true);
+            Logger.Debug("HiveExperiment: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
+            retryCount++;
+            // loop while
+            // 1. problem with communication with server
+            // 2. job result not yet ready
+          } while (
+            (retryCount < maxSnapshotRetries) && (
+            !response.Success ||
+            response.StatusMessage == ApplicationConstants.RESPONSE_JOB_RESULT_NOT_YET_HERE)
+            );
+        }
+        if (response.Success) {
+          LogMessage(jobId, "Snapshot polling successfull for job " + jobId);
+          UpdateSnapshot(response);
+        } else {
+          LogMessage(jobId, "Error: Polling of Snapshot failed for job " + jobId + ": " + response.StatusMessage);
+        }
+      });
+      t.Start();
     }
 
@@ -708,40 +643,5 @@
     }
 
-    public void RequestSnapshot(Guid jobId) {
-      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
-      ResponseObject<SerializedJob> response;
-      int retryCount = 0;
-
-      Response snapShotResponse = executionEngineFacade.RequestSnapshot(jobId);
-      if (snapShotResponse.StatusMessage == ApplicationConstants.RESPONSE_JOB_IS_NOT_BEEING_CALCULATED) {
-        // job already finished
-        Logger.Debug("HiveEngine: Abort - GetLastResult(false)");
-        response = executionEngineFacade.GetLastSerializedResult(jobId, false, false);
-        Logger.Debug("HiveEngine: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
-      } else {
-        // server sent snapshot request to client
-        // poll until snapshot is ready
-        do {
-          Thread.Sleep(snapshotPollingIntervalMs);
-          Logger.Debug("HiveEngine: Abort - GetLastResult(true)");
-          response = executionEngineFacade.GetLastSerializedResult(jobId, false, true);
-          Logger.Debug("HiveEngine: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
-          retryCount++;
-          // loop while
-          // 1. problem with communication with server
-          // 2. job result not yet ready
-        } while (
-          (retryCount < maxSnapshotRetries) && (
-          !response.Success ||
-          response.StatusMessage == ApplicationConstants.RESPONSE_JOB_RESULT_NOT_YET_HERE)
-          );
-      }
-      if (response.Success) {
-        LogMessage(jobId, "Snapshot polling successfull for job " + jobId);
-        GetJobItemById(jobId).LatestSnapshot = response;
-      } else {
-        LogMessage(jobId, "Error: Polling of Snapshot failed for job " + jobId + ": " + response.StatusMessage);
-      }
-    }
+    #endregion
 
     #region Required Plugin Search
@@ -915,4 +815,7 @@
       jobItems.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsRemoved);
       jobItems.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsReplaced);
+      foreach (JobItem jobItem in jobItems) {
+        RegisterJobItemEvents(jobItem);
+      }
     }
 
@@ -922,4 +825,7 @@
       jobItems.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsRemoved);
       jobItems.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsReplaced);
+      foreach (JobItem jobItem in jobItems) {
+        DeregisterJobItemEvents(jobItem);
+      }
     }
 
@@ -931,14 +837,22 @@
       if (e.OldItems != null) {
         foreach (var item in e.OldItems) {
-          item.Value.SnapshotRequestedStateChanged -= new EventHandler(JobItem_SnapshotRequestedStateChanged);
-          item.Value.JobStateChanged -= new EventHandler(JobItem_JobStateChanged);
+          DeregisterJobItemEvents(item.Value);
         }
       }
       if (e.Items != null) {
         foreach (var item in e.Items) {
-          item.Value.JobStateChanged += new EventHandler(JobItem_JobStateChanged);
-          item.Value.SnapshotRequestedStateChanged += new EventHandler(JobItem_SnapshotRequestedStateChanged);
-        }
-      }
+          RegisterJobItemEvents(item.Value);
+        }
+      }
+    }
+
+    private void RegisterJobItemEvents(JobItem jobItem) {
+      jobItem.SnapshotRequestedStateChanged += new EventHandler(JobItem_SnapshotRequestedStateChanged);
+      jobItem.JobStateChanged += new EventHandler(JobItem_JobStateChanged);
+    }
+
+    private void DeregisterJobItemEvents(JobItem jobItem) {
+      jobItem.SnapshotRequestedStateChanged -= new EventHandler(JobItem_SnapshotRequestedStateChanged);
+      jobItem.JobStateChanged -= new EventHandler(JobItem_JobStateChanged);
     }
 
@@ -958,4 +872,42 @@
     }
     #endregion
+
+    #region Helper Functions
+    private IExecutionEngineFacade GetExecutionEngineFacade() {
+      IExecutionEngineFacade executionEngineFacade = null;
+      do {
+        try {
+          executionEngineFacade = ServiceLocator.CreateExecutionEngineFacade(ServerUrl);
+        } catch (EndpointNotFoundException exception) {
+          LogMessage("Could not connect to Server: " + exception.Message + ". Will try again in " + (resultPollingIntervalMs / 1000) + " sec.");
+          Thread.Sleep(resultPollingIntervalMs);
+        }
+      } while (executionEngineFacade == null && this.ExecutionState != Core.ExecutionState.Stopped);
+      return executionEngineFacade;
+    }
+
+
+    private void AddRange(IDictionary<IOptimizer, IOptimizer> optimizers, IDictionary<IOptimizer, IOptimizer> childs) {
+      foreach (KeyValuePair<IOptimizer, IOptimizer> kvp in childs) {
+        optimizers.Add(kvp);
+      }
+    }
+
+    #endregion
+
+    #region Logging
+    private void LogMessage(string message) {
+      // HeuristicLab.Log is not Thread-Safe, so lock on every call
+      lock (locker) {
+        log.LogMessage(message);
+      }
+    }
+
+    private void LogMessage(Guid jobId, string message) {
+      GetJobItemById(jobId).LogMessage(message);
+      LogMessage(message + " (jobId: " + jobId + ")");
+    }
+
+    #endregion
   }
 }
Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment/3.3/JobItem.cs
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment/3.3/JobItem.cs	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment/3.3/JobItem.cs	(revision 4173)
@@ -155,5 +155,5 @@
     public event EventHandler JobStateChanged;
     private void OnJobStateChanged() {
-      LogMessage("JobStateChanged");
+      LogMessage("JobStateChanged (State: " + this.State + ", Percentage: " + this.Percentage + ")");
       EventHandler handler = JobStateChanged;
       if (handler != null) handler(this, EventArgs.Empty);
Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Server.Core/3.3/ClientCommunicator.cs
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Server.Core/3.3/ClientCommunicator.cs	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Server.Core/3.3/ClientCommunicator.cs	(revision 4173)
@@ -349,5 +349,10 @@
           response.Success = false;
           response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_JOB_IS_NOT_BEEING_CALCULATED;
-          Logger.Error("There is no job calculated by this user " + hbData.ClientId);
+
+          foreach (Guid jobId in hbData.JobProgress.Keys) {
+            response.ActionRequest.Add(new MessageContainer(MessageContainer.MessageType.AbortJob, jobId));
+          }
+
+          Logger.Error("There is no job calculated by this user " + hbData.ClientId + ", advise him to abort all");
           return;
         }
@@ -359,4 +364,5 @@
             response.Success = false;
             response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_JOB_IS_NOT_BEEING_CALCULATED;
+            response.ActionRequest.Add(new MessageContainer(MessageContainer.MessageType.AbortJob, curJob.Id));
             Logger.Error("There is no job calculated by this user " + hbData.ClientId + " Job: " + curJob);
           } else if (curJob.State == State.Abort) {
@@ -524,5 +530,4 @@
         response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_NO_JOB_WITH_THIS_ID;
         response.JobId = jobId;
-
         Logger.Error("No job with Id " + jobId);
 
Index: /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Server.Core/3.3/JobManager.cs
===================================================================
--- /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Server.Core/3.3/JobManager.cs	(revision 4172)
+++ /branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Server.Core/3.3/JobManager.cs	(revision 4173)
@@ -235,4 +235,6 @@
     // [chn] [refactor] why does this method handle 3 different cases? wouldn't 3 methods be easier?
     //Requested means: there MUST be a job result which gets sent back
+    // requested==true: resultat mit job
+    // requested==false: 
     public ResponseObject<SerializedJob> GetLastSerializedJobResultOf(Guid jobId, bool requested, bool snapshot) {
       ResponseObject<SerializedJob> response = new ResponseObject<SerializedJob>();
