dcm4chee 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/README.md +45 -0
  2. data/Rakefile +9 -0
  3. data/app/controllers/dcm4chee/api/v1/application_entities_controller.rb +178 -0
  4. data/app/controllers/dcm4chee/api/v1/base_controller.rb +15 -0
  5. data/app/controllers/dcm4chee/api/v1/dicom_objects_controller.rb +58 -0
  6. data/app/controllers/dcm4chee/api/v1/file_systems_controller.rb +37 -0
  7. data/app/controllers/dcm4chee/api/v1/instances_controller.rb +68 -0
  8. data/app/controllers/dcm4chee/api/v1/modalities_controller.rb +29 -0
  9. data/app/controllers/dcm4chee/api/v1/patients_controller.rb +77 -0
  10. data/app/controllers/dcm4chee/api/v1/series_controller.rb +69 -0
  11. data/app/controllers/dcm4chee/api/v1/source_aets_controller.rb +29 -0
  12. data/app/controllers/dcm4chee/api/v1/studies_controller.rb +69 -0
  13. data/app/controllers/dcm4chee/api/v1/trashed_instances_controller.rb +82 -0
  14. data/app/controllers/dcm4chee/api/v1/trashed_patients_controller.rb +84 -0
  15. data/app/controllers/dcm4chee/api/v1/trashed_series_controller.rb +81 -0
  16. data/app/controllers/dcm4chee/api/v1/trashed_studies_controller.rb +81 -0
  17. data/app/controllers/dcm4chee/api/v1/trashes_controller.rb +23 -0
  18. data/app/controllers/dcm4chee/application_controller.rb +4 -0
  19. data/app/models/dcm4chee/application_entity.rb +129 -0
  20. data/app/models/dcm4chee/dicom_file.rb +62 -0
  21. data/app/models/dcm4chee/file_system.rb +95 -0
  22. data/app/models/dcm4chee/instance.rb +69 -0
  23. data/app/models/dcm4chee/modality.rb +17 -0
  24. data/app/models/dcm4chee/patient.rb +42 -0
  25. data/app/models/dcm4chee/series.rb +78 -0
  26. data/app/models/dcm4chee/source_aet.rb +17 -0
  27. data/app/models/dcm4chee/study.rb +60 -0
  28. data/app/models/dcm4chee/trashed_dicom_file.rb +58 -0
  29. data/app/models/dcm4chee/trashed_instance.rb +56 -0
  30. data/app/models/dcm4chee/trashed_patient.rb +40 -0
  31. data/app/models/dcm4chee/trashed_series.rb +50 -0
  32. data/app/models/dcm4chee/trashed_study.rb +40 -0
  33. data/config/routes.rb +27 -0
  34. data/lib/dcm4chee.rb +58 -0
  35. data/lib/dcm4chee/api_constraints.rb +12 -0
  36. data/lib/dcm4chee/dicom_object_manager.rb +48 -0
  37. data/lib/dcm4chee/engine.rb +5 -0
  38. data/lib/dcm4chee/models/has_dicom_object.rb +71 -0
  39. data/lib/dcm4chee/services/application_entity_service.rb +113 -0
  40. data/lib/dcm4chee/services/content_edit_service.rb +37 -0
  41. data/lib/dcm4chee/services/file_system_management.rb +16 -0
  42. data/lib/dcm4chee/services/mbean.rb +11 -0
  43. data/lib/dcm4chee/services/move_scu_service.rb +54 -0
  44. data/lib/dcm4chee/version.rb +3 -0
  45. data/lib/tasks/dcm4chee_tasks.rake +4 -0
  46. metadata +241 -0
@@ -0,0 +1,27 @@
1
+ Dcm4chee::Engine.routes.draw do
2
+ namespace :api, defaults: { format: 'json' } do
3
+ scope module: :v1, constraints: Dcm4chee::ApiConstraints.new(version: 1, default: true) do
4
+ resources :patients, only: [:index, :create]
5
+ resources :studies, only: [:index, :create]
6
+ resources :series, only: [:index, :create]
7
+ resources :instances, only: [:index, :create]
8
+
9
+ resources :modalities, only: :index
10
+ resources :source_aets, only: :index
11
+
12
+ resources :trashed_patients, only: [:index, :create, :destroy]
13
+ resources :trashed_studies, only: [:index, :create, :destroy]
14
+ resources :trashed_series, only: [:index, :create, :destroy]
15
+ resources :trashed_instances, only: [:index, :create, :destroy]
16
+
17
+ resources :file_systems, only: :index
18
+
19
+ resource :trash, only: :destroy
20
+
21
+ resources :application_entities, only: [:index, :create, :update, :destroy]
22
+ resources :dicom_objects, only: [:move] do
23
+ post :move, on: :collection
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,58 @@
1
+ require 'data_mapper'
2
+ require 'confstruct'
3
+ require 'jolokia'
4
+ require 'sys/filesystem'
5
+ require 'dm-searcher'
6
+ require 'dm-pager'
7
+
8
+ require 'dcm4chee/engine'
9
+ require 'dcm4chee/api_constraints'
10
+ require 'dcm4chee/dicom_object_manager'
11
+
12
+ require 'dcm4chee/services/mbean'
13
+ require 'dcm4chee/services/application_entity_service'
14
+ require 'dcm4chee/services/content_edit_service'
15
+ require 'dcm4chee/services/file_system_management'
16
+ require 'dcm4chee/services/move_scu_service'
17
+
18
+ module Dcm4chee
19
+ REPOSITORY_NAME = :dcm4chee
20
+
21
+ class << self
22
+ def jolokia
23
+ @jolokia ||= ::Jolokia.new(url: config.jolokia_url)
24
+ end
25
+
26
+ def config
27
+ @config ||= Confstruct::Configuration.new
28
+ end
29
+
30
+ def configure(&block)
31
+ config.configure(&block)
32
+
33
+ config.repository_name = REPOSITORY_NAME unless config.repository_name
34
+ DataMapper.setup(:dcm4chee, config.repository_uri) if config.repository_uri
35
+ end
36
+
37
+ def respond_to?(method)
38
+ Dcm4chee::Service.constants.include?(method.to_s.camelize.to_sym) || super(method)
39
+ end
40
+
41
+ def method_missing(name, *args, &block)
42
+ service = instance_variable_get("@#{name}")
43
+ return service if service
44
+
45
+ begin
46
+ service_class = "Dcm4chee::Service::#{name.to_s.camelize}".constantize
47
+ service = service_class.new(jolokia)
48
+ instance_variable_set("@#{name}", service)
49
+
50
+ service
51
+ rescue
52
+ super(name, *args, &block)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ require 'dcm4chee/models/has_dicom_object'
@@ -0,0 +1,12 @@
1
+ module Dcm4chee
2
+ class ApiConstraints
3
+ def initialize(options)
4
+ @version = options[:version]
5
+ @default = options[:default]
6
+ end
7
+
8
+ def matches?(req)
9
+ @default || req.headers['Accept'].include?("application/vnd.menglifang.org; version=#{@version}")
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,48 @@
1
+ module Dcm4chee
2
+ class DicomObjectManager
3
+ def move(dest_aet, study_iuids, series_iuids, instance_iuids)
4
+ move_studies(dest_aet, study_iuids)
5
+
6
+ series_iuids.each { |k, v| move_series(dest_aet, k, v) }
7
+
8
+ instance_iuids.each do |key, val|
9
+ val.each { |k, v| move_instances(dest_aet, key, k, v) }
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def move_studies(dest_aet, study_iuids)
16
+ Dcm4chee.move_scu_service.schedule_move(
17
+ nil,
18
+ dest_aet,
19
+ 0,
20
+ nil,
21
+ study_iuids
22
+ )
23
+ end
24
+
25
+ def move_series(dest_aet, study_iuid, series_iuids)
26
+ Dcm4chee.move_scu_service.schedule_move(
27
+ nil,
28
+ dest_aet,
29
+ 0,
30
+ nil,
31
+ [study_iuid],
32
+ series_iuids
33
+ )
34
+ end
35
+
36
+ def move_instances(dest_aet, study_iuid, series_iuid, instance_iuids)
37
+ Dcm4chee.move_scu_service.schedule_move(
38
+ nil,
39
+ dest_aet,
40
+ 0,
41
+ nil,
42
+ [study_iuid],
43
+ [series_iuid],
44
+ instance_iuids
45
+ )
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ module Dcm4chee
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Dcm4chee
4
+ end
5
+ end
@@ -0,0 +1,71 @@
1
+ require 'hex_string'
2
+ require 'virtus'
3
+ require 'dicom'
4
+
5
+ module Dcm4chee
6
+ module HasDicomObject
7
+ extend ActiveSupport::Concern
8
+
9
+ class Element
10
+ include ::Virtus
11
+
12
+ attribute :name, String
13
+ attribute :value, String
14
+ attribute :tag, String
15
+ attribute :value_representation, String
16
+ attribute :length, Integer
17
+ end
18
+
19
+ def dcm
20
+ tsuid = defined?(dicom_file) ? dicom_file.transfer_syntax_uid : ::DICOM::EXPLICIT_LITTLE_ENDIAN
21
+
22
+ return nil unless dicom_attributes
23
+
24
+ # TODO Cache it
25
+ adapter = repository.adapter.options[:adapter]
26
+ attrs = nil
27
+ if adapter == 'postgres'
28
+ attrs = dicom_attributes.gsub(/\\x/, '').to_byte_string
29
+ elsif adapter == 'mysql'
30
+ attrs = dicom_attributes.to_hex_string.to_byte_string
31
+ end
32
+
33
+ ::DICOM::DObject.parse(attrs, syntax: tsuid) if attrs
34
+ end
35
+
36
+ def dcm_elements
37
+ return [] unless dcm
38
+
39
+ @elements ||= begin
40
+ @elements = []
41
+ dcm.elements.each do |e|
42
+ @elements << Element.new(name: e.name,
43
+ value: e.value.to_s,
44
+ tag: e.tag,
45
+ value_representation: e.vr,
46
+ length: e.length)
47
+ end
48
+
49
+ @elements
50
+ end
51
+ end
52
+
53
+ def as_json(opts = {})
54
+ opts[:exclude] ||= []
55
+ opts[:exclude] << :dicom_attributes
56
+
57
+ opts[:methods] ||= []
58
+ opts[:methods] << :dcm_elements
59
+
60
+ super(opts)
61
+ end
62
+
63
+ module ClassMethods
64
+ def dicom_field(name)
65
+ property :dicom_attributes,
66
+ ::DataMapper::Property::Binary, field: name,
67
+ accessor: :private
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,113 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ module Service
4
+ class ApplicationEntityService < MBean
5
+
6
+ MBEAN_NAME = 'dcm4chee.archive:service=AE'
7
+
8
+ # Create application entities.
9
+ #
10
+ # @param [Array] attr_values Attributes of an application entity
11
+ # 0. [String] title
12
+ # 1. [String] host
13
+ # 2. [Integer] port
14
+ # 3. [String] cipher_suites, SSL_RSA_WITH_NULL_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA
15
+ # 4. [String] patient_id_issuer
16
+ # 5. [String] accession_number_issuer
17
+ # 6. [String] username
18
+ # 7. [String] password
19
+ # 8. [String] fs_group
20
+ # 9. [String] ae_group
21
+ # 10. [String] description
22
+ # 11. [String] wado_url
23
+ # 12. [String] station_name
24
+ # 13. [String] institution
25
+ # 14. [String] department
26
+ # 15. [Boolean] installed
27
+ # 16. [Boolean] check_host
28
+ def add_ae(attr_values)
29
+ signatures = [
30
+ 'java.lang.String',
31
+ 'java.lang.String',
32
+ 'int',
33
+ 'java.lang.String',
34
+ 'java.lang.String',
35
+ 'java.lang.String',
36
+ 'java.lang.String',
37
+ 'java.lang.String',
38
+ 'java.lang.String',
39
+ 'java.lang.String',
40
+ 'java.lang.String',
41
+ 'java.lang.String',
42
+ 'java.lang.String',
43
+ 'java.lang.String',
44
+ 'java.lang.String',
45
+ 'boolean',
46
+ 'boolean'
47
+ ]
48
+
49
+ jolokia.execute(MBEAN_NAME,
50
+ "addAE(#{signatures.join(',')})",
51
+ attr_values)
52
+
53
+ end
54
+
55
+ # Update application entities.
56
+ #
57
+ # @param [Array] attr_values Attributes of an application entity.
58
+ # 0. [Integer] ID,Add a new one if id is -1. if not, update an existed one
59
+ # 1. [String] title
60
+ # 2. [String] host
61
+ # 3. [Integer] port
62
+ # 4. [String] cipher_suites, SSL_RSA_WITH_NULL_SHA,TLS_RSA_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA
63
+ # 5. [String] patient_id_issuer
64
+ # 6. [String] accession_number_issuer
65
+ # 7. [String] username
66
+ # 8. [String] password
67
+ # 9. [String] fs_group
68
+ # 10. [String] ae_group
69
+ # 11. [String] description
70
+ # 12. [String] wado_url
71
+ # 13. [String] station_name
72
+ # 14. [String] institution
73
+ # 15. [String] department
74
+ # 16. [Boolean] installed
75
+ # 17. [Boolean] check_host
76
+ def update_ae(attr_values)
77
+ signatures = [
78
+ 'long',
79
+ 'java.lang.String',
80
+ 'java.lang.String',
81
+ 'int',
82
+ 'java.lang.String',
83
+ 'java.lang.String',
84
+ 'java.lang.String',
85
+ 'java.lang.String',
86
+ 'java.lang.String',
87
+ 'java.lang.String',
88
+ 'java.lang.String',
89
+ 'java.lang.String',
90
+ 'java.lang.String',
91
+ 'java.lang.String',
92
+ 'java.lang.String',
93
+ 'java.lang.String',
94
+ 'boolean',
95
+ 'boolean'
96
+ ]
97
+
98
+ jolokia.execute(MBEAN_NAME,
99
+ "updateAE(#{signatures.join(',')})",
100
+ attr_values)
101
+ end
102
+
103
+ # Delete an application entity.
104
+ #
105
+ # @param [String] title the title of the deleting AE.
106
+ def remove_ae(title)
107
+ jolokia.execute(MBEAN_NAME,
108
+ "removeAE(java.lang.String)",
109
+ title)
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,37 @@
1
+ module Dcm4chee
2
+ module Service
3
+ class ContentEditService < MBean
4
+
5
+ MBEAN_NAME = 'dcm4chee.archive:service=ContentEditService'
6
+
7
+ def empty_trash
8
+ jolokia.execute(MBEAN_NAME, 'emptyTrash')
9
+ end
10
+
11
+ class << self
12
+ def define_component(name)
13
+ name = name.to_s
14
+
15
+ define_method("undelete_#{name}".to_sym) do |id|
16
+ jolokia.execute(MBEAN_NAME,
17
+ "undelete#{name.camelize}(long)", id)
18
+ end
19
+
20
+ define_method("delete_#{name}".to_sym) do |id|
21
+ jolokia.execute(MBEAN_NAME,
22
+ "delete#{name.camelize}(long)", id)
23
+ end
24
+ define_method("move_#{name}_to_trash".to_sym) do |id|
25
+ jolokia.execute(MBEAN_NAME,
26
+ "move#{name.camelize}ToTrash(long)", id)
27
+ end
28
+ end
29
+ end
30
+
31
+ define_component :patient
32
+ define_component :study
33
+ define_component :series
34
+ define_component :instance
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ module Dcm4chee
2
+ module Service
3
+ class FileSystemManagement < MBean
4
+
5
+ MBEAN_NAME = 'dcm4chee.archive:group=ONLINE_STORAGE,service=FileSystemMgt'
6
+
7
+ def minimum_free_disk_space_bytes
8
+ jolokia.get_attribute(MBEAN_NAME, 'MinimumFreeDiskSpaceBytes') || 0
9
+ end
10
+
11
+ def expected_data_volume_per_day_bytes
12
+ jolokia.get_attribute(MBEAN_NAME, 'ExpectedDataVolumePerDayBytes') || 1_000_000_000
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module Dcm4chee
2
+ module Service
3
+ class MBean
4
+ attr_accessor :jolokia
5
+
6
+ def initialize(jolokia)
7
+ @jolokia = jolokia
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,54 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ module Service
4
+ class MoveScuService < MBean
5
+
6
+ MBEAN_NAME = 'dcm4chee.archive:service=MoveScu'
7
+
8
+ # Move data to AE
9
+ #
10
+ # @param [String] retrieve_aet
11
+ # @param [String] dest_aet
12
+ # @param [Integer] priority DICOM priority(0: Medium, 1: High, 2: Low)
13
+ # @param [String] pid
14
+ # @param [Array] study_iuids
15
+ # @param [Array] series_iuids
16
+ # @param [Array] sop_iuids
17
+ # @param [Integer] scheduled_time(milliseconds from 1970-01-01 00:00:00)
18
+ #
19
+ # @return [Hash] Result
20
+ def schedule_move(retrieve_aet,
21
+ dest_aet,
22
+ priority,
23
+ pid,
24
+ study_iuids,
25
+ series_iuids = nil,
26
+ sop_iuids = nil,
27
+ scheduled_time = 0)
28
+ signatures = [
29
+ 'java.lang.String',
30
+ 'java.lang.String',
31
+ 'int',
32
+ 'java.lang.String',
33
+ '[Ljava.lang.String;',
34
+ '[Ljava.lang.String;',
35
+ '[Ljava.lang.String;',
36
+ 'long'
37
+ ]
38
+
39
+ jolokia.execute(MBEAN_NAME,
40
+ "scheduleMove(#{signatures.join(',')})",
41
+ [
42
+ retrieve_aet,
43
+ dest_aet,
44
+ priority || 0,
45
+ pid,
46
+ study_iuids,
47
+ series_iuids,
48
+ sop_iuids,
49
+ scheduled_time
50
+ ])
51
+ end
52
+ end
53
+ end
54
+ end