throw a ParseError exception for problems with the XML
[opensuse:shared-resources.git] / buildservice / lib / activexml / base.rb
1 module ActiveXML
2   class GeneralError < StandardError; end
3   class NotFoundError < GeneralError; end
4   class CreationError < GeneralError; end
5   class ParseError < GeneralError; end
6
7   class Base < LibXMLNode
8
9     include ActiveXML::Config
10
11     # need it for test case
12     attr_reader :init_options
13
14     @default_find_parameter = :name
15
16     class << self #class methods
17
18       #transport object, gets defined according to configuration when Base is subclassed
19       attr_reader :transport
20
21       def inherited( subclass )
22         # called when a subclass is defined
23         #logger.debug "Initializing ActiveXML model #{subclass}"
24         subclass.instance_variable_set "@default_find_parameter", @default_find_parameter
25       end
26       private :inherited
27
28       # setup the default parameter for find calls. If the first parameter to <Model>.find is a string,
29       # the value of this string is used as value f
30       def default_find_parameter( sym )
31         @default_find_parameter = sym
32       end
33
34       def setup(transport_object)
35         super()
36         @@transport = transport_object
37         logger.debug "--> ActiveXML successfully set up"
38         true
39       end
40
41       def belongs_to(*tag_list)
42         logger.debug "#{self.name} belongs_to #{tag_list.inspect}"
43         @rel_belongs_to ||= Array.new
44         @rel_belongs_to.concat(tag_list).uniq!
45       end
46
47       def has_many(*tag_list)
48         #logger.debug "#{self.name} has_many #{tag_list.inspect}"
49         @rel_has_many ||= Array.new
50         @rel_has_many.concat(tag_list).uniq!
51       end
52
53       def error
54         @error
55       end
56
57       def find( *args )
58         #FIXME: needs cleanup
59         #TODO: factor out xml stuff to ActiveXML::Node
60         #logger.debug "#{self.name}.find( #{args.map {|a| a.inspect}.join(', ')} )"
61
62         args[1] ||= {}
63         opt = args[0].kind_of?(Hash) ? args[0] : args[1]
64         opt[@default_find_parameter] = args[0] if( args[0].kind_of? String )
65
66         #logger.debug "prepared find args: #{args.inspect}"
67
68         #TODO: somehow we need to set the transport again, as it was not set when subclassing.
69         # only happens with rails >= 2.3.4 and config.cache_classes = true
70         transport = config.transport_for(self.name.downcase.to_sym)
71         raise "No transport defined for model #{self.name}" unless transport
72         transport.find( self, *args )
73       end
74
75       def find_cached( *args )
76         cache_key = self.name + '-' + args.to_s
77         if !(results = Rails.cache.read(cache_key))
78           results = find( *args )
79           Rails.cache.write(cache_key, results, :expires_in => 30.minutes) if results
80         end
81       results
82       end
83
84       def free_cache( *args )
85         cache_key = self.name + '-' + args.to_s
86         Rails.cache.delete(cache_key)
87       end
88
89     end #class methods
90
91     def initialize( data, opt={} )
92       super(data)
93       opt = data if data.kind_of? Hash and opt.empty?
94       @init_options = opt
95     end
96
97     def name
98       method_missing( :name )
99     end
100
101     def marshal_dump
102       a = super
103       a.push(@init_options)
104     end
105
106     def marshal_load(dumped)
107       super
108       @init_options = *dumped.shift(1)
109     end
110
111     def save(opt={})
112       logger.debug "Save #{self.class}"
113       logger.debug "XML #{data}"
114       transport = TransportMap.transport_for(self.class.name.downcase.to_sym)
115       if opt[:create]
116         @raw_data = transport.create self, opt
117         @data = nil
118       else
119         transport.save self, opt
120       end
121       return true
122     end
123
124     def delete(opt={})
125       logger.debug "Delete #{self.class}, opt: #{opt.inspect}"
126       transport = TransportMap.transport_for(self.class.name.downcase.to_sym)
127       transport.delete self, opt
128       return true
129     end
130
131   end
132 end