dcm4chee 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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