changeset 2601:5b6c3d77a2a1 jobs

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 17 May 2018 17:03:40 +0200
parents 140a539b4eba
children c25f1a52acbc
files Core/DicomNetworking/DicomUserConnection.cpp Core/DicomNetworking/IDicomConnectionManager.h Core/JobsEngine/Operations/IJobOperation.h Core/JobsEngine/Operations/JobOperationValue.h Core/JobsEngine/Operations/JobOperationValues.cpp Core/JobsEngine/Operations/JobOperationValues.h Core/JobsEngine/Operations/LogJobOperation.cpp Core/JobsEngine/Operations/LogJobOperation.h Core/JobsEngine/Operations/NullOperationValue.h Core/JobsEngine/Operations/StringOperationValue.h Resources/CMake/OrthancFrameworkConfiguration.cmake UnitTestsSources/MultiThreadingTests.cpp
diffstat 12 files changed, 639 insertions(+), 256 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomNetworking/DicomUserConnection.cpp	Thu May 17 16:22:40 2018 +0200
+++ b/Core/DicomNetworking/DicomUserConnection.cpp	Thu May 17 17:03:40 2018 +0200
@@ -1238,7 +1238,7 @@
   }
 
   
-  void SetDefaultTimeout(uint32_t seconds)
+  void DicomUserConnection::SetDefaultTimeout(uint32_t seconds)
   {
     LOG(INFO) << "Default timeout for DICOM connections if Orthanc acts as SCU (client): " 
               << seconds << " seconds (0 = no timeout)";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/DicomNetworking/IDicomConnectionManager.h	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,60 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "DicomUserConnection.h"
+
+namespace Orthanc
+{
+  class IDicomConnectionManager : public boost::noncopyable
+  {
+  public:
+    virtual ~IDicomConnectionManager()
+    {
+    }
+
+    class IResource : public boost::noncopyable
+    {
+    public:
+      virtual ~IResource()
+      {
+      }
+
+      virtual DicomUserConnection& GetConnection() = 0;
+    };
+
+    virtual IResource* AcquireConnection(const std::string& localAet,
+                                         const RemoteModalityParameters& remote) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/IJobOperation.h	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,50 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "JobOperationValues.h"
+
+namespace Orthanc
+{
+  class IJobOperation : public boost::noncopyable
+  {
+  public:
+    virtual ~IJobOperation()
+    {
+    }
+
+    virtual void Apply(JobOperationValues& outputs,
+                       const JobOperationValue& input) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/JobOperationValue.h	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,71 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <boost/noncopyable.hpp>
+
+namespace Orthanc
+{
+  class JobOperationValue : public boost::noncopyable
+  {
+  public:
+    enum Type
+    {
+      Type_DicomInstance,
+      Type_Null,
+      Type_String
+    };
+
+  private:
+    Type  type_;
+
+  protected:
+    JobOperationValue(Type type) :
+      type_(type)
+    {
+    }
+
+  public:
+    virtual ~JobOperationValue()
+    {
+    }
+
+    Type GetType() const
+    {
+      return type_;
+    }
+
+    virtual JobOperationValue* Clone() const = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/JobOperationValues.cpp	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,107 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../../PrecompiledHeaders.h"
+#include "JobOperationValues.h"
+
+#include "../../OrthancException.h"
+
+#include <cassert>
+
+namespace Orthanc
+{
+  void JobOperationValues::Append(JobOperationValues& target,
+                                  bool clear)
+  {
+    target.Reserve(target.GetSize() + GetSize());
+
+    for (size_t i = 0; i < values_.size(); i++)
+    {
+      if (clear)
+      {
+        target.Append(values_[i]);
+        values_[i] = NULL;
+      }
+      else
+      {
+        target.Append(GetValue(i).Clone());
+      }
+    }
+
+    if (clear)
+    {
+      Clear();
+    }
+  }
+
+
+  void JobOperationValues::Clear()
+  {
+    for (size_t i = 0; i < values_.size(); i++)
+    {
+      if (values_[i] != NULL)
+      {
+        delete values_[i];
+      }
+    }
+
+    values_.clear();
+  }
+
+
+  void JobOperationValues::Append(JobOperationValue* value)  // Takes ownership
+  {
+    if (value == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+    else
+    {
+      values_.push_back(value);
+    }
+  }
+
+
+  JobOperationValue& JobOperationValues::GetValue(size_t index) const
+  {
+    if (index >= values_.size())
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      assert(values_[index] != NULL);
+      return *values_[index];
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/JobOperationValues.h	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,82 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "JobOperationValue.h"
+
+#include <vector>
+
+namespace Orthanc
+{
+  class JobOperationValues : public boost::noncopyable
+  {
+  private:
+    std::vector<JobOperationValue*>   values_;
+
+    void Append(JobOperationValues& target,
+                bool clear);
+
+  public:
+    ~JobOperationValues()
+    {
+      Clear();
+    }
+
+    void Move(JobOperationValues& target)
+    {
+      return Append(target, true);
+    }
+
+    void Copy(JobOperationValues& target)
+    {
+      return Append(target, false);
+    }
+
+    void Clear();
+
+    void Reserve(size_t count)
+    {
+      values_.reserve(count);
+    }
+
+    void Append(JobOperationValue* value);  // Takes ownership
+
+    size_t GetSize() const
+    {
+      return values_.size();
+    }
+
+    JobOperationValue& GetValue(size_t index) const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/LogJobOperation.cpp	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,62 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../../PrecompiledHeaders.h"
+#include "LogJobOperation.h"
+
+#include "../../Logging.h"
+#include "StringOperationValue.h"
+
+namespace Orthanc
+{
+  void LogJobOperation::Apply(JobOperationValues& outputs,
+                              const JobOperationValue& input)
+  {
+    switch (input.GetType())
+    {
+      case JobOperationValue::Type_String:
+        LOG(INFO) << "Job value: " << dynamic_cast<const StringOperationValue&>(input).GetContent();
+        break;
+
+      case JobOperationValue::Type_Null:
+        LOG(INFO) << "Job value: (null)";
+        break;
+
+      default:
+        LOG(INFO) << "Job value: (unsupport)";
+        break;
+    }
+
+    outputs.Append(input.Clone());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/LogJobOperation.h	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,46 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IJobOperation.h"
+
+namespace Orthanc
+{
+  class LogJobOperation : public IJobOperation
+  {
+  public:
+    virtual void Apply(JobOperationValues& outputs,
+                       const JobOperationValue& input);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/NullOperationValue.h	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,53 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "JobOperationValue.h"
+
+namespace Orthanc
+{
+  class NullOperationValue : public JobOperationValue
+  {
+  public:
+    NullOperationValue() :
+      JobOperationValue(Type_Null)
+    {
+    }
+
+    virtual JobOperationValue* Clone() const
+    {
+      return new NullOperationValue;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/JobsEngine/Operations/StringOperationValue.h	Thu May 17 17:03:40 2018 +0200
@@ -0,0 +1,64 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program 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.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "JobOperationValue.h"
+
+#include <string>
+
+namespace Orthanc
+{
+  class StringOperationValue : public JobOperationValue
+  {
+  private:
+    std::string  content_;
+
+  public:
+    StringOperationValue(const std::string& content) :
+      JobOperationValue(JobOperationValue::Type_String),
+      content_(content)
+    {
+    }
+
+    virtual JobOperationValue* Clone() const
+    {
+      return new StringOperationValue(content_);
+    }
+
+    const std::string& GetContent() const
+    {
+      return content_;
+    }
+  };
+}
--- a/Resources/CMake/OrthancFrameworkConfiguration.cmake	Thu May 17 16:22:40 2018 +0200
+++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake	Thu May 17 17:03:40 2018 +0200
@@ -503,6 +503,8 @@
     ${ORTHANC_ROOT}/Core/JobsEngine/JobStepResult.cpp
     ${ORTHANC_ROOT}/Core/JobsEngine/JobsEngine.cpp
     ${ORTHANC_ROOT}/Core/JobsEngine/JobsRegistry.cpp
+    ${ORTHANC_ROOT}/Core/JobsEngine/Operations/JobOperationValues.cpp
+    ${ORTHANC_ROOT}/Core/JobsEngine/Operations/LogJobOperation.cpp
     ${ORTHANC_ROOT}/Core/JobsEngine/SetOfInstancesJob.cpp
     ${ORTHANC_ROOT}/Core/MultiThreading/RunnableWorkersPool.cpp
     ${ORTHANC_ROOT}/Core/MultiThreading/Semaphore.cpp
--- a/UnitTestsSources/MultiThreadingTests.cpp	Thu May 17 16:22:40 2018 +0200
+++ b/UnitTestsSources/MultiThreadingTests.cpp	Thu May 17 17:03:40 2018 +0200
@@ -745,238 +745,13 @@
 #include "../OrthancServer/ServerContext.h"
 #include "../Core/Logging.h"
 
-namespace
-{
-  class JobOperationValue : public boost::noncopyable
-  {
-  public:
-    enum Type
-    {
-      Type_DicomInstance,
-      Type_Null,
-      Type_String
-    };
-
-  private:
-    Type  type_;
-
-  protected:
-    JobOperationValue(Type type) :
-      type_(type)
-    {
-    }
-
-  public:
-    virtual ~JobOperationValue()
-    {
-    }
-
-    Type GetType() const
-    {
-      return type_;
-    }
-
-    virtual JobOperationValue* Clone() const = 0;
-  };
-
-
-  class NullOperationValue : public JobOperationValue
-  {
-  public:
-    NullOperationValue() :
-      JobOperationValue(Type_Null)
-    {
-    }
-
-    virtual JobOperationValue* Clone() const
-    {
-      return new NullOperationValue;
-    }
-  };
-
-
-  class StringOperationValue : public JobOperationValue
-  {
-  private:
-    std::string  content_;
-
-  public:
-    StringOperationValue(const std::string& content) :
-      JobOperationValue(JobOperationValue::Type_String),
-      content_(content)
-    {
-    }
-
-    virtual JobOperationValue* Clone() const
-    {
-      return new StringOperationValue(content_);
-    }
-
-    const std::string& GetContent() const
-    {
-      return content_;
-    }
-  };
-
-
-  class IDicomConnectionManager : public boost::noncopyable
-  {
-  public:
-    virtual ~IDicomConnectionManager()
-    {
-    }
-
-    class IResource : public boost::noncopyable
-    {
-    public:
-      virtual ~IResource()
-      {
-      }
-
-      virtual DicomUserConnection& GetConnection() = 0;
-    };
-
-    virtual IResource* AcquireConnection(const std::string& localAet,
-                                         const RemoteModalityParameters& remote) = 0;
-  };
-
-
-  class JobOperationValues : public boost::noncopyable
-  {
-  private:
-    std::vector<JobOperationValue*>   values_;
-
-    void Append(JobOperationValues& target,
-                bool clear)
-    {
-      target.Reserve(target.GetSize() + GetSize());
+#include "../Core/DicomNetworking/IDicomConnectionManager.h"
+#include "../Core/JobsEngine/Operations/JobOperationValues.h"
+#include "../Core/JobsEngine/Operations/StringOperationValue.h"
+#include "../Core/JobsEngine/Operations/LogJobOperation.h"
 
-      for (size_t i = 0; i < values_.size(); i++)
-      {
-        if (clear)
-        {
-          target.Append(values_[i]);
-          values_[i] = NULL;
-        }
-        else
-        {
-          target.Append(GetValue(i).Clone());
-        }
-      }
-
-      if (clear)
-      {
-        Clear();
-      }
-    }
-
-  public:
-    ~JobOperationValues()
-    {
-      Clear();
-    }
-
-    void Move(JobOperationValues& target)
-    {
-      return Append(target, true);
-    }
-
-    void Copy(JobOperationValues& target)
-    {
-      return Append(target, false);
-    }
-
-    void Clear()
-    {
-      for (size_t i = 0; i < values_.size(); i++)
-      {
-        if (values_[i] != NULL)
-        {
-          delete values_[i];
-        }
-      }
-
-      values_.clear();
-    }
-
-    void Reserve(size_t count)
-    {
-      values_.reserve(count);
-    }
-
-    void Append(JobOperationValue* value)  // Takes ownership
-    {
-      if (value == NULL)
-      {
-        throw OrthancException(ErrorCode_NullPointer);
-      }
-      else
-      {
-        values_.push_back(value);
-      }
-    }
-
-    size_t GetSize() const
-    {
-      return values_.size();
-    }
-
-    JobOperationValue& GetValue(size_t index) const
-    {
-      if (index >= values_.size())
-      {
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-      }
-      else
-      {
-        assert(values_[index] != NULL);
-        return *values_[index];
-      }
-    }
-  };
-
-
-
-  class IJobOperation : public boost::noncopyable
-  {
-  public:
-    virtual ~IJobOperation()
-    {
-    }
-
-    virtual void Apply(JobOperationValues& outputs,
-                       const JobOperationValue& input,
-                       IDicomConnectionManager& manager) = 0;
-  };
-
-
-  class LogJobOperation : public IJobOperation
-  {
-  public:
-    virtual void Apply(JobOperationValues& outputs,
-                       const JobOperationValue& input,
-                       IDicomConnectionManager& manager)
-    {
-      switch (input.GetType())
-      {
-        case JobOperationValue::Type_String:
-          LOG(INFO) << "Job value: " << dynamic_cast<const StringOperationValue&>(input).GetContent();
-          break;
-
-        case JobOperationValue::Type_Null:
-          LOG(INFO) << "Job value: (null)";
-          break;
-
-        default:
-          LOG(INFO) << "Job value: (unsupport)";
-          break;
-      }
-
-      outputs.Append(input.Clone());
-    }
-  };
-
-
+namespace Orthanc
+{
   class DicomInstanceValue : public JobOperationValue
   {
   private:
@@ -1172,7 +947,7 @@
       boost::mutex::scoped_lock lock(mutex_);
 
       timeout_ = boost::posix_time::milliseconds(timeout);
-      CheckTimeout();
+      CheckTimeoutInternal();
     }
 
     unsigned int GetTimeout()
@@ -1286,7 +1061,7 @@
         return currentInput_ >= originalInputs_.GetSize() + workInputs_.GetSize();
       }
 
-      void Step(IDicomConnectionManager& manager)
+      void Step()
       {
         if (IsDone())
         {
@@ -1305,7 +1080,7 @@
         }
 
         JobOperationValues outputs;
-        operation_->Apply(outputs, *input, manager);
+        operation_->Apply(outputs, *input);
 
         if (!nextOperations_.empty())
         {
@@ -1333,7 +1108,6 @@
     std::vector<Operation*>           operations_;
     size_t                            current_;
     boost::condition_variable         operationAdded_;
-    TimeoutDicomConnectionManager&    connectionManager_;
     boost::posix_time::time_duration  trailingTimeout_;
     std::list<IObserver*>             observers_;
 
@@ -1346,17 +1120,14 @@
     }
 
   public:
-    SequenceOfOperationsJob(TimeoutDicomConnectionManager& manager) :
-    jobType_("SequenceOfOperations"),
-    connectionManager_(manager)
+    SequenceOfOperationsJob() :
+      jobType_("SequenceOfOperations")
     {
       Setup();
     }    
 
-    SequenceOfOperationsJob(const std::string& jobType,
-                            TimeoutDicomConnectionManager& manager) :
-      jobType_(jobType),
-    connectionManager_(manager)
+    SequenceOfOperationsJob(const std::string& jobType) :
+      jobType_(jobType)
     {
       Setup();
     }    
@@ -1399,11 +1170,6 @@
         return that_.done_;
       }
 
-      void SetDicomConnectionTimeout(unsigned int timeout)
-      {
-        that_.connectionManager_.SetTimeout(timeout);
-      }
-
       void SetTrailingOperationTimeout(unsigned int timeout)
       {
         that_.trailingTimeout_ = boost::posix_time::milliseconds(timeout);
@@ -1513,7 +1279,7 @@
 
       if (current_ < operations_.size())
       {
-        operations_[current_]->Step(connectionManager_);
+        operations_[current_]->Step();
       }
 
       return JobStepResult::Continue();
@@ -1534,8 +1300,6 @@
 
     virtual void ReleaseResources()
     {
-      boost::mutex::scoped_lock lock(mutex_);
-      connectionManager_.Close();
     }
 
     virtual float GetProgress()
@@ -1573,13 +1337,24 @@
   private:
     boost::mutex                   mutex_;
     JobsEngine&                    engine_;
-    TimeoutDicomConnectionManager manager_;
+    TimeoutDicomConnectionManager  connectionManager_;
     std::string                    currentId_;
     SequenceOfOperationsJob*       currentJob_;
     size_t                         maxOperations_;
     int                            priority_;
     unsigned int                   trailingTimeout_;
+    bool                           continue_;
+    boost::thread                  connectionTimeoutThread_;
 
+    static void ConnectionTimeoutThread(LuaJobManager* manager)
+    {
+      while (manager->continue_)
+      {
+        manager->connectionManager_.CheckTimeout();
+        boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+      }
+    }
+    
     virtual void SignalDone(const SequenceOfOperationsJob& job)
     {
       boost::mutex::scoped_lock lock(mutex_);
@@ -1596,8 +1371,20 @@
     engine_(engine),
     currentJob_(NULL),
     maxOperations_(1000),
-    priority_(0)
+    priority_(0),
+    continue_(true)
     {
+      connectionTimeoutThread_ = boost::thread(ConnectionTimeoutThread, this);
+    }
+
+    ~LuaJobManager()
+    {
+      continue_ = false;
+
+      if (connectionTimeoutThread_.joinable())
+      {
+        connectionTimeoutThread_.join();
+      }
     }
 
     void SetMaxOperationsPerJob(size_t count)
@@ -1635,7 +1422,7 @@
 
       // Need to create a new job, as the previous one is either
       // finished, or is getting too long
-      currentJob_ = new SequenceOfOperationsJob(manager_);
+      currentJob_ = new SequenceOfOperationsJob;
       engine_.GetRegistry().Submit(currentId_, currentJob_, priority_);
 
       std::auto_ptr<Lock> result(new Lock(*currentJob_));
@@ -1649,7 +1436,6 @@
 
 TEST(JobsEngine, DISABLED_SequenceOfOperationsJob)
 {
-  TimeoutDicomConnectionManager manager;
   JobsEngine engine;
   engine.SetWorkersCount(3);
   engine.Start();
@@ -1658,7 +1444,7 @@
   SequenceOfOperationsJob* job = NULL;
 
   {
-    std::auto_ptr<SequenceOfOperationsJob> a(new SequenceOfOperationsJob(manager));
+    std::auto_ptr<SequenceOfOperationsJob> a(new SequenceOfOperationsJob);
     job = a.get();
     engine.GetRegistry().Submit(id, a.release(), 0);
   }