infopark_reactor 1.10.0.beta → 1.11.0.beta2

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/rails_connector/abstract_model.rb +7 -0
  3. data/app/models/rails_connector/abstract_obj.rb +31 -0
  4. data/app/models/rails_connector/attribute.rb +94 -0
  5. data/app/models/rails_connector/blob_mapping.rb +12 -0
  6. data/app/models/rails_connector/channel.rb +41 -0
  7. data/app/models/rails_connector/content.rb +12 -0
  8. data/app/models/rails_connector/meta/eager_loader.rb +41 -0
  9. data/app/models/rails_connector/obj_class.rb +143 -0
  10. data/app/models/rails_connector/object_with_meta_data.rb +18 -0
  11. data/infopark_reactor.gemspec +4 -4
  12. data/lib/generators/cm/migration/USAGE +8 -0
  13. data/lib/generators/cm/migration/migration_generator.rb +16 -0
  14. data/lib/generators/cm/migration/templates/template.rb +8 -0
  15. data/lib/infopark_reactor.rb +35 -1
  16. data/lib/reactor/attributes.rb +2 -4
  17. data/lib/reactor/cm/attribute.rb +91 -0
  18. data/lib/reactor/cm/bridge.rb +50 -0
  19. data/lib/reactor/cm/channel.rb +18 -0
  20. data/lib/reactor/cm/editorial_group.rb +23 -0
  21. data/lib/reactor/cm/group.rb +241 -0
  22. data/lib/reactor/cm/language.rb +57 -0
  23. data/lib/reactor/cm/link.rb +136 -0
  24. data/lib/reactor/cm/live_group.rb +23 -0
  25. data/lib/reactor/cm/log_entry.rb +64 -0
  26. data/lib/reactor/cm/missing_credentials.rb +8 -0
  27. data/lib/reactor/cm/multi_xml_request.rb +102 -0
  28. data/lib/reactor/cm/obj.rb +544 -0
  29. data/lib/reactor/cm/obj_class.rb +187 -0
  30. data/lib/reactor/cm/object_base.rb +165 -0
  31. data/lib/reactor/cm/permissions.rb +44 -0
  32. data/lib/reactor/cm/user.rb +139 -0
  33. data/lib/reactor/cm/workflow.rb +41 -0
  34. data/lib/reactor/cm/xml_attribute.rb +36 -0
  35. data/lib/reactor/cm/xml_markup.rb +86 -0
  36. data/lib/reactor/cm/xml_multi_request_error.rb +10 -0
  37. data/lib/reactor/cm/xml_request.rb +83 -0
  38. data/lib/reactor/cm/xml_request_error.rb +11 -0
  39. data/lib/reactor/cm/xml_response.rb +43 -0
  40. data/lib/reactor/cm/xml_single_request_error.rb +21 -0
  41. data/lib/reactor/configuration.rb +8 -0
  42. data/lib/{engine.rb → reactor/engine.rb} +16 -1
  43. data/lib/reactor/legacy.rb +3 -3
  44. data/lib/reactor/link/temporary_link.rb +8 -4
  45. data/lib/reactor/migration.rb +87 -0
  46. data/lib/reactor/permission.rb +2 -2
  47. data/lib/reactor/persistence.rb +14 -12
  48. data/lib/reactor/plans/common_attribute.rb +33 -0
  49. data/lib/reactor/plans/common_channel.rb +32 -0
  50. data/lib/reactor/plans/common_group.rb +45 -0
  51. data/lib/reactor/plans/common_obj_class.rb +70 -0
  52. data/lib/reactor/plans/create_attribute.rb +33 -0
  53. data/lib/reactor/plans/create_channel.rb +24 -0
  54. data/lib/reactor/plans/create_group.rb +35 -0
  55. data/lib/reactor/plans/create_obj.rb +49 -0
  56. data/lib/reactor/plans/create_obj_class.rb +29 -0
  57. data/lib/reactor/plans/delete_attribute.rb +24 -0
  58. data/lib/reactor/plans/delete_channel.rb +22 -0
  59. data/lib/reactor/plans/delete_group.rb +29 -0
  60. data/lib/reactor/plans/delete_obj.rb +23 -0
  61. data/lib/reactor/plans/delete_obj_class.rb +23 -0
  62. data/lib/reactor/plans/prepared.rb +16 -0
  63. data/lib/reactor/plans/rename_group.rb +33 -0
  64. data/lib/reactor/plans/rename_obj_class.rb +25 -0
  65. data/lib/reactor/plans/update_attribute.rb +24 -0
  66. data/lib/reactor/plans/update_group.rb +31 -0
  67. data/lib/reactor/plans/update_obj.rb +31 -0
  68. data/lib/reactor/plans/update_obj_class.rb +27 -0
  69. data/lib/reactor/rails_connector_meta.rb +144 -0
  70. data/lib/reactor/tools/migrator.rb +136 -0
  71. data/lib/reactor/tools/response_handler/base.rb +23 -0
  72. data/lib/reactor/tools/response_handler/string.rb +20 -0
  73. data/lib/reactor/tools/response_handler/xml_attribute.rb +53 -0
  74. data/lib/reactor/tools/smart_xml_logger.rb +70 -0
  75. data/lib/reactor/tools/sower.rb +90 -0
  76. data/lib/reactor/tools/uploader.rb +134 -0
  77. data/lib/reactor/tools/versioner.rb +121 -0
  78. data/lib/reactor/tools/workflow_generator.rb +1 -1
  79. data/lib/reactor/tools/xml_attributes.rb +71 -0
  80. data/lib/reactor/version.rb +1 -1
  81. data/lib/tasks/cm_migrate.rake +8 -0
  82. data/lib/tasks/cm_seeds.rake +41 -0
  83. metadata +82 -13
  84. data/README.md +0 -186
@@ -0,0 +1,136 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'reactor/tools/versioner'
3
+
4
+ module Reactor
5
+ # Class responsible for running a single migration, a helper for Migrator
6
+ class MigrationProxy
7
+ def initialize(versioner, name, version, direction, filename)
8
+ @versioner = versioner
9
+ @name = name
10
+ @version = version
11
+ @filename = filename
12
+ @direction = direction
13
+ end
14
+
15
+ def load_migration
16
+ load @filename
17
+ end
18
+
19
+ def run
20
+ return down if @direction.to_sym == :down
21
+ return up
22
+ end
23
+
24
+ def up
25
+ if @versioner.applied?(@version) then
26
+ puts "Migrating up: #{@name} (#{@filename}) already applied, skipping"
27
+ return true
28
+ else
29
+ result = class_name.send(:up) and @versioner.add(@version)
30
+ class_name.contained.each do |version|
31
+ puts "#{class_name.to_s} contains migration #{version}"
32
+ #@versioner.add(version) # not neccesary!
33
+ end if result
34
+ result
35
+ end
36
+ end
37
+
38
+ def down
39
+ result = class_name.send(:down) and @versioner.remove(@version)
40
+ class_name.contained.each do |version|
41
+ puts "#{class_name.to_s} contains migration #{version}"
42
+ @versioner.remove(version)
43
+ end if result
44
+ result
45
+ end
46
+
47
+ def class_name
48
+ return Kernel.const_get(@name)
49
+ end
50
+
51
+ def name
52
+ @name
53
+ end
54
+
55
+ def version
56
+ @version
57
+ end
58
+
59
+ def filename
60
+ @filename
61
+ end
62
+ end
63
+
64
+ # Migrator is responsible for running migrations.
65
+ #
66
+ # <b>You should not use this class directly! Use rake cm:migrate instead.</b>
67
+ #
68
+ # Migrating to a specific version is possible by specifing VERSION environment
69
+ # variable: rake cm:migrate VERSION=0
70
+ # Depending on your current version migrations will be run up
71
+ # (target version > current version) or down (target version < current version)
72
+ #
73
+ # MIND THE FACT, that you land at the version <i>nearest</i> to target_version
74
+ # (possibly target version itself)
75
+ class Migrator
76
+ # Constructor takes two parameters migrations_path (relative path of migration files)
77
+ # and target_version (an integer or nil).
78
+ #
79
+ # Used by a rake task.
80
+ def initialize(migrations_path, target_version=nil)
81
+ @migrations_path = migrations_path
82
+ @target_version = target_version.to_i unless target_version.nil?
83
+ @target_version = 99999999999999 if target_version.nil?
84
+ @versioner = Versioner.instance
85
+ end
86
+
87
+ # Runs the migrations in proper direction (up or down)
88
+ # Ouputs current version when done
89
+ def migrate
90
+ return up if @target_version.to_i > current_version.to_i
91
+ return down
92
+ end
93
+
94
+ def up
95
+ rem_migrations = migrations.reject do |version, name, file|
96
+ version.to_i > @target_version.to_i or applied?(version)
97
+ end
98
+ run(rem_migrations, :up)
99
+ end
100
+
101
+ def down
102
+ rem_migrations = migrations.reject do |version, name, file|
103
+ version.to_i <= @target_version.to_i or not applied?(version)
104
+ end
105
+ run(rem_migrations.reverse, :down)
106
+ end
107
+
108
+ def migrations
109
+ files = Dir["#{@migrations_path}/[0-9]*_*.rb"].sort.collect do |file|
110
+ version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
111
+ [version, name, file]
112
+ end
113
+ end
114
+
115
+ def applied?(version)
116
+ @versioner.applied?(version)
117
+ end
118
+
119
+ def current_version
120
+ @versioner.current_version
121
+ end
122
+
123
+ def run(rem_migrations, direction)
124
+ begin
125
+ rem_migrations.each do |version, name, file|
126
+ migration = MigrationProxy.new(@versioner, name.camelize, version, direction, file)
127
+ puts "Migrating #{direction.to_s}: #{migration.name} (#{migration.filename})"
128
+ migration.load_migration and migration.run or raise "Migrating #{direction.to_s}: #{migration.name} (#{migration.filename}) failed"
129
+ end
130
+ ensure
131
+ puts "At version: " + @versioner.current_version.to_s
132
+ puts "WARNING: Could not store applied migrations!" if not @versioner.store
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Reactor
3
+
4
+ module ResponseHandler
5
+
6
+ # Common base class to handle a xml response. Provides helper methods to extract the content
7
+ # from a xml response.
8
+ class Base
9
+
10
+ attr_accessor :response
11
+ attr_accessor :context
12
+
13
+ # Common strategy method for each sub class.
14
+ def get(response, context)
15
+ @response = response
16
+ @context = context
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'reactor/tools/response_handler/base'
3
+
4
+ module Reactor
5
+
6
+ module ResponseHandler
7
+
8
+ class String < Base
9
+
10
+ def get(response, string)
11
+ super(response, string)
12
+
13
+ self.response.xpath(string)
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,53 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'reactor/tools/response_handler/base'
3
+
4
+ module Reactor
5
+
6
+ module ResponseHandler
7
+
8
+ class XmlAttribute < Base
9
+
10
+ def get(response, attribute)
11
+ super(response, attribute)
12
+
13
+ name = attribute.name
14
+ type = attribute.type
15
+
16
+ method_name = "extract_#{type}"
17
+
18
+ self.send(method_name, name)
19
+ end
20
+
21
+ private
22
+
23
+ # Extracts a string value with the given +name+ and returns a string.
24
+ def extract_string(name)
25
+ self.response.xpath("//#{name}/text()").to_s
26
+ end
27
+
28
+ # Extracts a list value with the given +name+ and returns an array of strings.
29
+ def extract_list(name)
30
+ result = self.response.xpath("//#{name}/listitem/text()")
31
+ result = result.kind_of?(Array) ? result : [result]
32
+
33
+ result.map(&:to_s)
34
+ end
35
+
36
+ # This shit will break with the slightest change of the CM.
37
+ def extract_signaturelist(name)
38
+ signatures = []
39
+ self.response.xpath("//#{name}/").each do |potential_signature|
40
+ if (potential_signature.name.to_s == "listitem")
41
+ attribute = potential_signature.children.first.text.to_s
42
+ group = potential_signature.children.last.text.to_s
43
+ signatures << {:attribute => attribute, :group => group}
44
+ end
45
+ end
46
+ signatures
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,70 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'nokogiri'
3
+ require 'term/ansicolor'
4
+
5
+ class SmartXmlLogger
6
+
7
+ include Term::ANSIColor
8
+
9
+ def initialize(forward_to, method = nil)
10
+ @logger = forward_to
11
+ @method = method
12
+ end
13
+
14
+ def configure(key, options)
15
+ @configuration ||= {}
16
+ @configuration[key] = options
17
+ end
18
+
19
+ def log(text)
20
+ return unless @logger
21
+ @logger.send(@method, text)
22
+ end
23
+
24
+ def log_xml(key, xml)
25
+ return unless @logger
26
+
27
+ options = @configuration[key]
28
+
29
+ dom = Nokogiri::XML::Document.parse(xml)
30
+
31
+ node_set = options[:xpath] ? dom.xpath(options[:xpath]) : dom
32
+
33
+ self.log(if node_set.respond_to?(:each)
34
+ node_set.map{|node| self.print_node(node, options[:start_indent] || 0)}.join
35
+ else
36
+ self.print_node(node_set, options[:start_indent] || 0)
37
+ end)
38
+ end
39
+
40
+ #private
41
+
42
+ def print_node(node, indent = 0)
43
+ return '' if node.text?
44
+
45
+ empty = node.children.empty?
46
+ has_text = node.children.detect{|child| child.text?}
47
+
48
+ out = ' ' * indent
49
+
50
+ attrs = node.attributes.values.map{|attr| %|#{attr.name}="#{red(attr.value)}"|}.join(' ')
51
+ attrs = " #{attrs}" if attrs.present?
52
+
53
+ out << "<#{green(node.name)}#{attrs}#{'/' if empty}>"
54
+
55
+ if has_text
56
+ out << "#{red(node.text)}"
57
+ else
58
+ out << "\n"
59
+ end
60
+
61
+ node.children.each do |child|
62
+ out << self.print_node(child, indent + 2)
63
+ end
64
+
65
+ out << ' ' * indent unless has_text || empty
66
+ out << "</#{green(node.name)}>\n" unless empty
67
+ out
68
+ end
69
+
70
+ end
@@ -0,0 +1,90 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Reactor
3
+
4
+ class Sower
5
+ def initialize(filename)
6
+ @filename = filename
7
+ end
8
+ def sow
9
+ require @filename
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ class SeedObject < RailsConnector::AbstractObj
16
+ end
17
+
18
+ module RailsConnector
19
+ class AbstractObj
20
+
21
+ attr_accessor :keep_edited
22
+
23
+ def self.plant(path, &block)
24
+ obj = Obj.find_by_path(path)
25
+ raise ActiveRecord::RecordNotFound.new('plant: Ground not found:' +path) if obj.nil?
26
+ #obj.objClass = 'Container' # TODO: enable it!
27
+ #obj.save!
28
+ #obj.release!
29
+ obj.send(:reload_attributes)
30
+ obj.instance_eval(&block) if block_given?
31
+ # ActiveRecord is incompatible with changing the obj class, therefore you get RecordNotFound
32
+ begin
33
+ obj.save!
34
+ rescue ActiveRecord::RecordNotFound
35
+ end
36
+ obj.release unless obj.keep_edited
37
+ obj
38
+ end
39
+
40
+ # creates of fetches an obj with given name (within context),
41
+ # executes a block on it (instance_eval)
42
+ # saves and releases (unless keep_edited = true was called)
43
+ # the object afterwards
44
+ def obj(name, objClass = 'Container', &block)
45
+ obj = Obj.find_by_path(File.join(self.path.to_s, name.to_s))
46
+ if obj.nil?
47
+ obj = Obj.create(:name => name, :parent => self.path, :obj_class => objClass)
48
+ else
49
+ obj = Obj.find_by_path(File.join(self.path.to_s, name.to_s))
50
+ if obj.obj_class != objClass
51
+ obj.obj_class = objClass
52
+ begin
53
+ obj.save!
54
+ rescue ActiveRecord::RecordNotFound
55
+ end
56
+ obj = Obj.find_by_path(File.join(self.path.to_s, name.to_s))
57
+ end
58
+ end
59
+ obj.send(:reload_attributes, objClass)
60
+ obj.instance_eval(&block) if block_given?
61
+ obj.save!
62
+ obj.release unless obj.keep_edited || !Obj.last.edited?
63
+ obj
64
+ end
65
+
66
+ def self.with(path, objClass = 'Container', &block)
67
+ splitted_path = path.split('/')
68
+ name = splitted_path.pop
69
+ # ensure path exists
70
+ (splitted_path.length).times do |i|
71
+ subpath = splitted_path[0,(i+1)].join('/').presence || '/'
72
+ subpath_parent = splitted_path[0,i].join('/').presence || '/'
73
+ subpath_name = splitted_path[i]
74
+ create(:name => subpath_name, :parent => subpath_parent, :obj_class => 'Container') unless Obj.find_by_path(subpath) unless subpath_name.blank?
75
+ end
76
+ parent_path = splitted_path.join('/').presence || '/'
77
+ parent = Obj.find_by_path(parent_path)
78
+ parent.obj(name, objClass, &block)
79
+ end
80
+
81
+ def do_not_release!
82
+ @keep_edited = true
83
+ end
84
+
85
+ def t(key, opts={})
86
+ I18n.t(key, opts)
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,134 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Reactor
3
+ module Tools
4
+ class Uploader
5
+
6
+ attr_reader :cm_obj
7
+
8
+ def initialize(cm_obj)
9
+ self.cm_obj = cm_obj
10
+ end
11
+
12
+ # Uses streaming interface to upload data from
13
+ # given IO stream or memory location.
14
+ # Extension is used as basis for content detection.
15
+ # Larger file transfers should be executed through IO
16
+ # streams, which conserve memory.
17
+ #
18
+ # After the data has been successfuly transfered to
19
+ # streaming interface it stores contentType and resulting
20
+ # ticket into Reactor::Cm::Obj provided on initialization.
21
+ #
22
+ # NOTE: there is a known bug for Mac OS X: if you are
23
+ # uploading more files (IO objects) in sequence,
24
+ # the upload may fail randomly. For this platform
25
+ # and this case fallback to memory streaming is used.
26
+ def upload(data_or_io, extension)
27
+ if (data_or_io.kind_of?IO)
28
+ io = data_or_io
29
+ begin
30
+ ticket_id = stream_io(io, extension)
31
+ rescue Errno::EINVAL => e
32
+ if RUBY_PLATFORM.downcase.include?("darwin")
33
+ # mac os x is such a piece of shit
34
+ # writing to a socket can fail with EINVAL, randomly without
35
+ # visible reason when using body_stream
36
+ # in this case fallback to memory upload which always works (?!?!)
37
+ Reactor::Cm::LOGGER.log "MacOS X bug detected for #{io.inspect}"
38
+ io.rewind
39
+ return upload(io.read, extension)
40
+ else
41
+ raise e
42
+ end
43
+ end
44
+ else
45
+ ticket_id = stream_data(data_or_io, extension)
46
+ end
47
+
48
+ cm_obj.set(:contentType, extension)
49
+ cm_obj.set(:blob, {ticket_id=>{:encoding=>'stream'}})
50
+
51
+ ticket_id
52
+ end
53
+
54
+ protected
55
+
56
+ attr_writer :cm_obj
57
+
58
+ # Stream into CM from memory. Used in cases when the file
59
+ # has already been read into memory
60
+ def stream_data(data, extension)
61
+ response = (Net::HTTP.new(self.class.streaming_host, self.class.streaming_port).post('/stream', data,
62
+ {'Content-Type' => self.class.content_type_for_ext(extension)}))
63
+ ticket_id = response.body
64
+
65
+ handle_response(response, ticket_id)
66
+ end
67
+
68
+ # Stream directly an IO object into CM. Uses minimal memory,
69
+ # as the IO is read in 1024B-Blocks
70
+ def stream_io(io, extension)
71
+ request = Net::HTTP::Post.new('/stream')
72
+ request.body_stream = io
73
+ request.content_length = read_io_content_length(io)
74
+ request.content_type = self.class.content_type_for_ext(extension)
75
+
76
+ response, ticket_id = nil, nil
77
+ Net::HTTP.start(self.class.streaming_host, self.class.streaming_port) do |http|
78
+ http.read_timeout = 60
79
+ #http.set_debug_output $stderr
80
+ response = http.request(request)
81
+ ticket_id = response.body
82
+ end
83
+
84
+ handle_response(response, ticket_id)
85
+ end
86
+
87
+ # Returns ticket_id if response if one of success (success or redirect)
88
+ def handle_response(response, ticket_id)
89
+ if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
90
+ ticket_id
91
+ else
92
+ nil
93
+ end
94
+ end
95
+
96
+ # Returns the size of the IO stream.
97
+ # The underlying stream must support either
98
+ # the :stat method or be able to seek to
99
+ # random position
100
+ def read_io_content_length(io)
101
+ if (io.respond_to?(:stat))
102
+ # For files it is easy to read the filesize
103
+ return io.stat.size
104
+ else
105
+ # For streams it is not. We seek to end of
106
+ # the stream, read the position, and rewind
107
+ # to the previous location
108
+ old_pos = io.pos
109
+ io.seek(0, IO::SEEK_END)
110
+ content_length = io.pos
111
+ io.seek(old_pos, IO::SEEK_SET)
112
+
113
+ content_length
114
+ end
115
+ end
116
+
117
+ def self.streaming_host
118
+ Reactor::Configuration.xml_access[:host]
119
+ end
120
+
121
+ def self.streaming_port
122
+ Reactor::Configuration.xml_access[:port]
123
+ end
124
+
125
+ # It should theoretically return correct/matching
126
+ # mime type for given extension. But since the CM
127
+ # accepts 'application/octet-stream', no extra logic
128
+ # or external dependency is required.
129
+ def self.content_type_for_ext(extension)
130
+ 'application/octet-stream'
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,121 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'base64'
3
+ require 'yaml'
4
+ require 'singleton'
5
+
6
+ module Reactor
7
+ # Class responsible for interfacing with version-storing mechanism
8
+ class Versioner
9
+ include Singleton
10
+
11
+ # Slave class used by Versioner class to load and store migrated files
12
+ # inside the CM. It uses separate object type named "version_store"
13
+ # and stores data as base64'ed YAML inside recordSetCallback
14
+ # (Versionszuweisungsfunktion).
15
+ # Theoretically you could use any class for this purpose, but you would
16
+ # lose the ability to set recordSetCallback for this class. Other than
17
+ # that, it does not affect the object class in any way!
18
+ #
19
+ # Maybe the future version won't disrupt even this fuction.
20
+ class Slave
21
+ def name
22
+ "version_store"
23
+ end
24
+
25
+ def base_name
26
+ "objClass"
27
+ end
28
+
29
+ def exists?
30
+ begin
31
+ request = Reactor::Cm::XmlRequest.prepare do |xml|
32
+ xml.where_key_tag!(base_name, 'name', name)
33
+ xml.get_key_tag!(base_name, 'name')
34
+ end
35
+ response = request.execute!
36
+ return response.ok?
37
+ rescue
38
+ return false
39
+ end
40
+ end
41
+
42
+ def load
43
+ create if not exists?
44
+ request = Reactor::Cm::XmlRequest.prepare do |xml|
45
+ xml.where_key_tag!(base_name, 'name', name)
46
+ xml.get_key_tag!(base_name, 'recordSetCallback')
47
+ end
48
+ response = request.execute!
49
+ base64 = response.xpath("//recordSetCallback").text.to_s
50
+ yaml = Base64::decode64(base64)
51
+ data = YAML::load(yaml)
52
+ return [] if data.nil? or data == false
53
+ return data.to_a
54
+ end
55
+
56
+ def store(data)
57
+ create if not exists?
58
+ yaml = data.to_yaml
59
+ base64 = Base64::encode64(yaml).gsub("\n", '').gsub("\r", '')
60
+ content = '#' + base64
61
+ request = Reactor::Cm::XmlRequest.prepare do |xml|
62
+ xml.where_key_tag!(base_name, 'name', name)
63
+ xml.set_key_tag!(base_name, 'recordSetCallback', content)
64
+ end
65
+ response = request.execute!
66
+ response.ok?
67
+ end
68
+
69
+ def create
70
+ request = Reactor::Cm::XmlRequest.prepare do |xml|
71
+ xml.create_tag!(base_name) do
72
+ xml.tag!('name') do
73
+ xml.text!(name)
74
+ end
75
+ xml.tag!('objType') do
76
+ xml.text!('document')
77
+ end
78
+ end
79
+ end
80
+ response = request.execute!
81
+ response.ok?
82
+ end
83
+ end
84
+
85
+ def initialize
86
+ @versions = []
87
+ @backend = Slave.new
88
+ load
89
+ end
90
+
91
+ def load
92
+ @versions = @backend.load
93
+ end
94
+
95
+ def store
96
+ @backend.store(@versions)
97
+ end
98
+
99
+ def applied?(version)
100
+ @versions.include? version.to_s
101
+ end
102
+
103
+ def add(version)
104
+ @versions << version.to_s
105
+ end
106
+
107
+ def remove(version)
108
+ not @versions.delete(version.to_s).nil?
109
+ end
110
+
111
+ def versions
112
+ @versions
113
+ end
114
+
115
+ def current_version
116
+ current = @versions.sort.reverse.first
117
+ return 0 if current.nil?
118
+ return current
119
+ end
120
+ end
121
+ end
@@ -145,7 +145,7 @@ module Reactor
145
145
  end
146
146
 
147
147
  def destroy_objs
148
- RailsConnector::AbstractObj.find_all_by_obj_class(@class_name).each(&:destroy)
148
+ RailsConnector::AbstractObj.where(obj_class: @class_name).each(&:destroy)
149
149
  end
150
150
 
151
151
  def destroy_obj_class