infopark_reactor 1.10.0.beta → 1.11.0.beta2

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