opennebula 3.9.80.beta

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 (42) hide show
  1. data/LICENSE +202 -0
  2. data/NOTICE +47 -0
  3. data/lib/opennebula.rb +58 -0
  4. data/lib/opennebula/acl.rb +266 -0
  5. data/lib/opennebula/acl_pool.rb +55 -0
  6. data/lib/opennebula/client.rb +119 -0
  7. data/lib/opennebula/cluster.rb +249 -0
  8. data/lib/opennebula/cluster_pool.rb +58 -0
  9. data/lib/opennebula/datastore.rb +171 -0
  10. data/lib/opennebula/datastore_pool.rb +55 -0
  11. data/lib/opennebula/document.rb +261 -0
  12. data/lib/opennebula/document_json.rb +131 -0
  13. data/lib/opennebula/document_pool.rb +102 -0
  14. data/lib/opennebula/document_pool_json.rb +58 -0
  15. data/lib/opennebula/error.rb +52 -0
  16. data/lib/opennebula/group.rb +163 -0
  17. data/lib/opennebula/group_pool.rb +56 -0
  18. data/lib/opennebula/host.rb +201 -0
  19. data/lib/opennebula/host_pool.rb +93 -0
  20. data/lib/opennebula/image.rb +297 -0
  21. data/lib/opennebula/image_pool.rb +79 -0
  22. data/lib/opennebula/ldap_auth.rb +99 -0
  23. data/lib/opennebula/ldap_auth_spec.rb +70 -0
  24. data/lib/opennebula/pool.rb +160 -0
  25. data/lib/opennebula/pool_element.rb +269 -0
  26. data/lib/opennebula/server_cipher_auth.rb +148 -0
  27. data/lib/opennebula/server_x509_auth.rb +104 -0
  28. data/lib/opennebula/ssh_auth.rb +139 -0
  29. data/lib/opennebula/system.rb +141 -0
  30. data/lib/opennebula/template.rb +213 -0
  31. data/lib/opennebula/template_pool.rb +79 -0
  32. data/lib/opennebula/user.rb +174 -0
  33. data/lib/opennebula/user_pool.rb +55 -0
  34. data/lib/opennebula/virtual_machine.rb +560 -0
  35. data/lib/opennebula/virtual_machine_pool.rb +323 -0
  36. data/lib/opennebula/virtual_network.rb +249 -0
  37. data/lib/opennebula/virtual_network_pool.rb +79 -0
  38. data/lib/opennebula/x509_auth.rb +288 -0
  39. data/lib/opennebula/xml_element.rb +427 -0
  40. data/lib/opennebula/xml_pool.rb +45 -0
  41. data/lib/opennebula/xml_utils.rb +34 -0
  42. metadata +118 -0
@@ -0,0 +1,79 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+
18
+ require 'opennebula/pool'
19
+
20
+ module OpenNebula
21
+ class VirtualNetworkPool < Pool
22
+ #######################################################################
23
+ # Constants and Class attribute accessors
24
+ #######################################################################
25
+
26
+
27
+ VN_POOL_METHODS = {
28
+ :info => "vnpool.info"
29
+ }
30
+
31
+ #######################################################################
32
+ # Class constructor & Pool Methods
33
+ #######################################################################
34
+
35
+ # +client+ a Client object that represents a XML-RPC connection
36
+ # +user_id+ is to refer to a Pool with VirtualNetworks from that user
37
+ def initialize(client, user_id=0)
38
+ super('VNET_POOL','VNET',client)
39
+
40
+ @user_id = user_id
41
+ end
42
+
43
+ # Default Factory Method for the Pools
44
+ def factory(element_xml)
45
+ OpenNebula::VirtualNetwork.new(element_xml,@client)
46
+ end
47
+
48
+ #######################################################################
49
+ # XML-RPC Methods for the Virtual Network Object
50
+ #######################################################################
51
+
52
+ # Retrieves all or part of the VirtualMachines in the pool.
53
+ def info(*args)
54
+ case args.size
55
+ when 0
56
+ info_filter(VN_POOL_METHODS[:info],@user_id,-1,-1)
57
+ when 3
58
+ info_filter(VN_POOL_METHODS[:info],args[0],args[1],args[2])
59
+ end
60
+ end
61
+
62
+ def info_all()
63
+ return super(VN_POOL_METHODS[:info])
64
+ end
65
+
66
+ def info_mine()
67
+ return super(VN_POOL_METHODS[:info])
68
+ end
69
+
70
+ def info_group()
71
+ return super(VN_POOL_METHODS[:info])
72
+ end
73
+
74
+ alias_method :info!, :info
75
+ alias_method :info_all!, :info_all
76
+ alias_method :info_mine!, :info_mine
77
+ alias_method :info_group!, :info_group
78
+ end
79
+ end
@@ -0,0 +1,288 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ require 'openssl'
18
+ require 'base64'
19
+ require 'fileutils'
20
+ require 'yaml'
21
+
22
+ module OpenNebula; end
23
+
24
+ # X509 authentication class. It can be used as a driver for auth_mad
25
+ # as auth method is defined. It also holds some helper methods to be used
26
+ # by oneauth command
27
+ class OpenNebula::X509Auth
28
+ ###########################################################################
29
+ #Constants with paths to relevant files and defaults
30
+ ###########################################################################
31
+ if !ENV["ONE_LOCATION"]
32
+ ETC_LOCATION = "/etc/one"
33
+ else
34
+ ETC_LOCATION = ENV["ONE_LOCATION"] + "/etc"
35
+ end
36
+
37
+ LOGIN_PATH = ENV['HOME']+'/.one/one_x509'
38
+
39
+ X509_AUTH_CONF_PATH = ETC_LOCATION + "/auth/x509_auth.conf"
40
+
41
+ X509_DEFAULTS = {
42
+ :ca_dir => ETC_LOCATION + "/auth/certificates"
43
+ }
44
+
45
+ def self.escape_dn(dn)
46
+ dn.gsub(/\s/) { |s| "\\"+s[0].ord.to_s(16) }
47
+ end
48
+
49
+ def self.unescape_dn(dn)
50
+ dn.gsub(/\\[0-9a-f]{2}/) { |s| s[1,2].to_i(16).chr }
51
+ end
52
+
53
+ ###########################################################################
54
+ # Initialize x509Auth object
55
+ #
56
+ # @param [Hash] default options for path
57
+ # @option options [String] :certs_pem
58
+ # cert chain array in colon-separated pem format
59
+ # @option options [String] :key_pem
60
+ # key in pem format
61
+ # @option options [String] :ca_dir
62
+ # directory of trusted CA's. Needed for auth method, not for login.
63
+ def initialize(options={})
64
+ @options ||= X509_DEFAULTS
65
+ @options.merge!(options)
66
+
67
+ load_options(X509_AUTH_CONF_PATH)
68
+
69
+ @cert_chain = @options[:certs_pem].collect do |cert_pem|
70
+ OpenSSL::X509::Certificate.new(cert_pem)
71
+ end
72
+
73
+ if @options[:key_pem]
74
+ @key = OpenSSL::PKey::RSA.new(@options[:key_pem])
75
+ end
76
+ end
77
+
78
+ ###########################################################################
79
+ # Client side
80
+ ###########################################################################
81
+
82
+ # Creates the login file for x509 authentication at ~/.one/one_x509.
83
+ # By default it is valid as long as the certificate is valid. It can
84
+ # be changed to any number of seconds with expire parameter (sec.)
85
+ def login(user, expire=0)
86
+ write_login(login_token(user,expire))
87
+ end
88
+
89
+ # Returns a valid password string to create a user using this auth driver.
90
+ # In this case the dn of the user certificate.
91
+ def password
92
+ self.class.escape_dn(@cert_chain[0].subject.to_s)
93
+ end
94
+
95
+ # Generates a login token in the form:
96
+ # user_name:x509:user_name:time_expires:cert_chain
97
+ # - user_name:time_expires is encrypted with the user certificate
98
+ # - user_name:time_expires:cert_chain is base64 encoded
99
+ def login_token(user, expire)
100
+ if expire != 0
101
+ expires = Time.now.to_i + expire.to_i
102
+ else
103
+ expires = @cert_chain[0].not_after.to_i
104
+ end
105
+
106
+ text_to_sign = "#{user}:#{expires}"
107
+ signed_text = encrypt(text_to_sign)
108
+
109
+ certs_pem = @cert_chain.collect{|cert| cert.to_pem}.join(":")
110
+
111
+ token = "#{signed_text}:#{certs_pem}"
112
+ token64 = Base64::encode64(token).strip.delete("\n")
113
+
114
+ login_out = "#{user}:#{token64}"
115
+
116
+ login_out
117
+ end
118
+
119
+ ###########################################################################
120
+ # Server side
121
+ ###########################################################################
122
+ # auth method for auth_mad
123
+ def authenticate(user, pass, signed_text)
124
+ begin
125
+ # Decryption demonstrates that the user posessed the private key.
126
+ _user, expires = decrypt(signed_text).split(':')
127
+
128
+ return "User name missmatch" if user != _user
129
+
130
+ return "x509 proxy expired" if Time.now.to_i >= expires.to_i
131
+
132
+ # Some DN in the chain must match a DN in the password
133
+ dn_ok = @cert_chain.each do |cert|
134
+ if pass.split('|').include?(
135
+ self.class.escape_dn(cert.subject.to_s))
136
+ break true
137
+ end
138
+ end
139
+
140
+ unless dn_ok == true
141
+ return "Certificate subject missmatch"
142
+ end
143
+
144
+ validate
145
+
146
+ return true
147
+ rescue => e
148
+ return e.message
149
+ end
150
+ end
151
+
152
+ private
153
+ # Writes a login_txt to the login file as defined in LOGIN_PATH
154
+ # constant
155
+ def write_login(login_txt)
156
+ # Inits login file path and creates ~/.one directory if needed
157
+ # Set instance variables
158
+ login_dir = File.dirname(LOGIN_PATH)
159
+
160
+ begin
161
+ FileUtils.mkdir_p(login_dir)
162
+ rescue Errno::EEXIST
163
+ end
164
+
165
+ file = File.open(LOGIN_PATH, "w")
166
+ file.write(login_txt)
167
+ file.close
168
+
169
+ File.chmod(0600,LOGIN_PATH)
170
+ end
171
+
172
+ # Load class options form a configuration file (yaml syntax)
173
+ def load_options(conf_file)
174
+ if File.readable?(conf_file)
175
+ conf_txt = File.read(conf_file)
176
+ conf_opt = YAML::load(conf_txt)
177
+
178
+ @options.merge!(conf_opt) if conf_opt != false
179
+ end
180
+ end
181
+
182
+ ###########################################################################
183
+ # Methods to encrpyt/decrypt keys
184
+ ###########################################################################
185
+ # Encrypts data with the private key of the user and returns
186
+ # base 64 encoded output in a single line
187
+ def encrypt(data)
188
+ return nil if !@key
189
+ Base64::encode64(@key.private_encrypt(data)).delete("\n").strip
190
+ end
191
+
192
+ # Decrypts base 64 encoded data with pub_key (public key)
193
+ def decrypt(data)
194
+ @cert_chain[0].public_key.public_decrypt(Base64::decode64(data))
195
+ end
196
+
197
+ ###########################################################################
198
+ # Validate the user certificate
199
+ ###########################################################################
200
+ def validate
201
+ now = Time.now
202
+
203
+ # Check start time and end time of certificates
204
+ @cert_chain.each do |cert|
205
+ if cert.not_before > now || cert.not_after < now
206
+ raise failed + "Certificate not valid. Current time is " +
207
+ now.localtime.to_s + "."
208
+ end
209
+ end
210
+
211
+ begin
212
+ # Validate the proxy certifcates
213
+ signee = @cert_chain[0]
214
+
215
+ check_crl(signee)
216
+
217
+ @cert_chain[1..-1].each do |cert|
218
+ if !((signee.issuer.to_s == cert.subject.to_s) &&
219
+ (signee.verify(cert.public_key)))
220
+ raise failed + signee.subject.to_s + " with issuer " +
221
+ signee.issuer.to_s + " was not verified by " +
222
+ cert.subject.to_s + "."
223
+ end
224
+ signee = cert
225
+ end
226
+
227
+ # Validate the End Entity certificate
228
+ if !@options[:ca_dir]
229
+ raise failed + "No certifcate authority directory was specified."
230
+ end
231
+
232
+ begin
233
+ ca_hash = signee.issuer.hash.to_s(16)
234
+ ca_path = @options[:ca_dir] + '/' + ca_hash + '.0'
235
+
236
+ ca_cert = OpenSSL::X509::Certificate.new(File.read(ca_path))
237
+
238
+ if !((signee.issuer.to_s == ca_cert.subject.to_s) &&
239
+ (signee.verify(ca_cert.public_key)))
240
+ raise failed + signee.subject.to_s + " with issuer " +
241
+ signee.issuer.to_s + " was not verified by " +
242
+ ca_cert.subject.to_s + "."
243
+ end
244
+
245
+ signee = ca_cert
246
+ end while ca_cert.subject.to_s != ca_cert.issuer.to_s
247
+ rescue
248
+ raise
249
+ end
250
+ end
251
+
252
+ def check_crl(signee)
253
+ failed = "Could not validate user credentials: "
254
+
255
+ ca_hash = signee.issuer.hash.to_s(16)
256
+ ca_path = @options[:ca_dir] + '/' + ca_hash + '.0'
257
+
258
+ crl_path = @options[:ca_dir] + '/' + ca_hash + '.r0'
259
+
260
+ if !File.exist?(crl_path)
261
+ if @options[:check_crl]
262
+ raise failed + "CRL file #{crl_path} does not exist"
263
+ else
264
+ return
265
+ end
266
+ end
267
+
268
+ ca_cert = OpenSSL::X509::Certificate.new( File.read(ca_path) )
269
+ crl_cert = OpenSSL::X509::CRL.new( File.read(crl_path) )
270
+
271
+ # First verify the CRL itself with its signer
272
+ unless crl_cert.verify( ca_cert.public_key ) then
273
+ raise failed + "CRL is not verified by its Signer"
274
+ end
275
+
276
+ # Extract the list of revoked certificates from the CRL
277
+ rc_array = crl_cert.revoked
278
+
279
+ # Loop over the list and compare with the target personal
280
+ # certificate
281
+ rc_array.each do |e|
282
+ if e.serial.eql?(signee.serial) then
283
+ raise failed + "#{signee.subject.to_s} is found in the "<<
284
+ "CRL, i.e. it is revoked"
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,427 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+
18
+ module OpenNebula
19
+ # The XMLElement class provides an abstraction of the underlying
20
+ # XML parser engine. It provides XML-related methods for the Pool and
21
+ # PoolElement classes
22
+ class XMLElement
23
+
24
+ # xml:: _opaque xml object_ an xml object as returned by build_xml
25
+ def initialize(xml=nil)
26
+ @xml = xml
27
+ end
28
+
29
+ # Initialize a XML document for the element
30
+ # xml:: _String_ the XML document of the object
31
+ # root_element:: _String_ Base xml element
32
+ def initialize_xml(xml, root_element)
33
+ @xml = XMLElement.build_xml(xml, root_element)
34
+
35
+ if OpenNebula.is_error?(@xml)
36
+ @xml = nil
37
+ else
38
+ if NOKOGIRI
39
+ if @xml.size == 0
40
+ @xml = nil
41
+ end
42
+ else
43
+ if @xml.name != root_element
44
+ @xml = nil
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ # Builds a XML document
51
+ # xml:: _String_ the XML document of the object
52
+ # root_element:: _String_ Base xml element
53
+ # [return] _XML_ object for the underlying XML engine
54
+ def self.build_xml(xml, root_element)
55
+ begin
56
+ if NOKOGIRI
57
+ doc = Nokogiri::XML(xml).xpath("/#{root_element}")
58
+ else
59
+ doc = REXML::Document.new(xml).root
60
+ end
61
+ rescue Exception => e
62
+ return OpenNebula::Error.new(e.message)
63
+ end
64
+
65
+ return doc
66
+ end
67
+
68
+ # Extract a text element from the XML description of the PoolElement.
69
+ #
70
+ # @param [String] key Xpath expression
71
+ #
72
+ # @return [String, nil] If a text element is found, the element's
73
+ # text value. Otherwise, an empty string or nil, depending
74
+ # on the backend
75
+ #
76
+ # @example
77
+ # vm['VID'] # gets VM id
78
+ # vm['HISTORY/HOSTNAME'] # get the hostname from the history
79
+ def [](key)
80
+ if NOKOGIRI
81
+ element=@xml.xpath(key.to_s)
82
+
83
+ return nil if element.size == 0
84
+ else
85
+ element=@xml.elements[key.to_s]
86
+
87
+ return "" if element && !element.has_text?
88
+ end
89
+
90
+ element.text if element
91
+ end
92
+
93
+ # Delete an element from the xml
94
+ # xpath::_String_ xpath expression that selects the elemnts to be deleted
95
+ def delete_element(xpath)
96
+ if NOKOGIRI
97
+ @xml.xpath(xpath.to_s).remove
98
+ else
99
+ @xml.delete_element(xpath.to_s)
100
+ end
101
+ end
102
+
103
+ # Add a new element to the xml
104
+ # xpath::_String_ xpath xpression where the elemente will be added
105
+ # elems::_Hash_ Hash containing the pairs key-value to be included
106
+ # Examples:
107
+ # add_element('VM', 'NEW_ITEM' => 'NEW_VALUE')
108
+ # <VM><NEW_ITEM>NEW_VALUE</NEW_ITEM>...</VM>
109
+ #
110
+ # add_element('VM/TEMPLATE', 'V1' => {'X1' => 'A1', 'Y2' => 'A2'})
111
+ # <VM><TEMPLATE><V1><X1>A1</X1><Y2>A2</Y2>...</TEMPLATE></VM>
112
+ def add_element(xpath, elems)
113
+ elems.each { |key, value|
114
+ if value.instance_of?(Hash)
115
+ if NOKOGIRI
116
+ elem = Nokogiri::XML::Node.new key, @xml.document
117
+ value.each { |k2, v2|
118
+ child = Nokogiri::XML::Node.new k2, elem
119
+ child.content = v2
120
+ elem.add_child(child)
121
+ }
122
+ @xml.xpath(xpath.to_s).first.add_child(elem)
123
+ else
124
+ elem = REXML::Element.new(key)
125
+ value.each { |k2, v2|
126
+ elem.add_element(k2).text = v2
127
+ }
128
+ @xml.elements[xpath].add_element(elem)
129
+ end
130
+ else
131
+ if NOKOGIRI
132
+ elem = Nokogiri::XML::Node.new key, @xml.document
133
+ elem.content = value
134
+ @xml.xpath(xpath.to_s).first.add_child(elem)
135
+ else
136
+ @xml.elements[xpath].add_element(key).text = value
137
+ end
138
+ end
139
+ }
140
+ end
141
+
142
+ # Gets an array of text from elemenets extracted
143
+ # using the XPATH expression passed as filter
144
+ def retrieve_elements(filter)
145
+ elements_array = Array.new
146
+
147
+ if NOKOGIRI
148
+ @xml.xpath(filter.to_s).each { |pelem|
149
+ elements_array << pelem.text if pelem.text
150
+ }
151
+ else
152
+ @xml.elements.each(filter.to_s) { |pelem|
153
+ elements_array << pelem.text if pelem.text
154
+ }
155
+ end
156
+
157
+ if elements_array.size == 0
158
+ return nil
159
+ else
160
+ return elements_array
161
+ end
162
+
163
+ end
164
+
165
+ # Gets an attribute from an elemenT
166
+ # key:: _String_ xpath for the element
167
+ # name:: _String_ name of the attribute
168
+ def attr(key,name)
169
+ value = nil
170
+
171
+ if NOKOGIRI
172
+ element=@xml.xpath(key.to_s.upcase)
173
+ if element.size == 0
174
+ return nil
175
+ end
176
+
177
+ attribute = element.attr(name)
178
+
179
+ value = attribute.text if attribute != nil
180
+ else
181
+ element=@xml.elements[key.to_s.upcase]
182
+
183
+ value = element.attributes[name] if element != nil
184
+ end
185
+
186
+ return value
187
+ end
188
+
189
+ # Iterates over every Element in the XPath and calls the block with a
190
+ # a XMLElement
191
+ # block:: _Block_
192
+ def each(xpath_str,&block)
193
+ if NOKOGIRI
194
+ @xml.xpath(xpath_str).each { |pelem|
195
+ block.call XMLElement.new(pelem)
196
+ }
197
+ else
198
+ @xml.elements.each(xpath_str) { |pelem|
199
+ block.call XMLElement.new(pelem)
200
+ }
201
+ end
202
+ end
203
+
204
+ def each_xpath(xpath_str,&block)
205
+ if NOKOGIRI
206
+ @xml.xpath(xpath_str).each { |pelem|
207
+ block.call pelem.text
208
+ }
209
+ else
210
+ @xml.elements.each(xpath_str) { |pelem|
211
+ block.call pelem.text
212
+ }
213
+ end
214
+ end
215
+
216
+ def name
217
+ @xml.name
218
+ end
219
+
220
+ def text
221
+ if NOKOGIRI
222
+ @xml.content
223
+ else
224
+ @xml.text
225
+ end
226
+ end
227
+
228
+ # Returns wheter there are elements for a given XPath
229
+ # xpath_str:: _String_ XPath expression to locate the element
230
+ def has_elements?(xpath_str)
231
+ if NOKOGIRI
232
+ element = @xml.xpath(xpath_str.to_s.upcase)
233
+ return element != nil && element.children.size > 0
234
+ else
235
+ element = @xml.elements[xpath_str.to_s]
236
+ return element != nil && element.has_elements?
237
+ end
238
+ end
239
+
240
+ # Returns the <TEMPLATE> element in text form
241
+ # indent:: _Boolean_ indents the resulting string, default true
242
+ def template_str(indent=true)
243
+ template_like_str('TEMPLATE', indent)
244
+ end
245
+
246
+ # Returns the <TEMPLATE> element in XML form
247
+ def template_xml
248
+ if NOKOGIRI
249
+ @xml.xpath('TEMPLATE').to_s
250
+ else
251
+ @xml.elements['TEMPLATE'].to_s
252
+ end
253
+ end
254
+
255
+ # Returns the xml of an element
256
+ def element_xml(xpath)
257
+ if NOKOGIRI
258
+ @xml.xpath(xpath).to_s
259
+ else
260
+ @xml.elements[xpath].to_s
261
+ end
262
+ end
263
+
264
+ # Returns elements in text form
265
+ # root_element:: _String_ base element
266
+ # indent:: _Boolean_ indents the resulting string, default true
267
+ # xpath_exp:: _String_ filter elements with a XPath
268
+ def template_like_str(root_element, indent=true, xpath_exp=nil)
269
+ if NOKOGIRI
270
+ xml_template = @xml.xpath(root_element).to_s
271
+ rexml = REXML::Document.new(xml_template).root
272
+ else
273
+ rexml = @xml.elements[root_element]
274
+ end
275
+
276
+ if indent
277
+ ind_enter = "\n"
278
+ ind_tab = ' '
279
+ else
280
+ ind_enter = ''
281
+ ind_tab = ' '
282
+ end
283
+
284
+ str = rexml.elements.collect(xpath_exp) {|n|
285
+ next if n.class != REXML::Element
286
+
287
+ str_line = ""
288
+
289
+ if n.has_elements?
290
+ str_line << "#{n.name}=[#{ind_enter}" << n.collect { |n2|
291
+
292
+ next if n2.class != REXML::Element or !n2.has_text?
293
+
294
+ str = "#{ind_tab}#{n2.name}=#{attr_to_str(n2.text)}"
295
+
296
+ }.compact.join(",#{ind_enter}") << " ]"
297
+ else
298
+ next if !n.has_text?
299
+
300
+ str_line << "#{n.name}=#{attr_to_str(n.text)}"
301
+ end
302
+
303
+ str_line
304
+ }.compact.join("\n")
305
+
306
+ return str
307
+ end
308
+
309
+ #
310
+ #
311
+ #
312
+ def to_xml(pretty=false)
313
+ if NOKOGIRI && pretty
314
+ str = @xml.to_xml
315
+ elsif REXML_FORMATTERS && pretty
316
+ str = String.new
317
+
318
+ formatter = REXML::Formatters::Pretty.new
319
+ formatter.compact = true
320
+
321
+ formatter.write(@xml,str)
322
+ else
323
+ str = @xml.to_s
324
+ end
325
+
326
+ return str
327
+ end
328
+
329
+ # @return [Hash] a hash representing the resource
330
+ def to_hash
331
+ hash = {}
332
+
333
+ if NOKOGIRI
334
+ if @xml.instance_of?(Nokogiri::XML::NodeSet)
335
+ @xml.each { |c|
336
+ if c.element?
337
+ build_hash(hash, c)
338
+ end
339
+ }
340
+ else
341
+ build_hash(hash, @xml)
342
+ end
343
+ else
344
+ build_hash(hash, @xml)
345
+ end
346
+
347
+ hash
348
+ end
349
+
350
+ private
351
+
352
+ #
353
+ #
354
+ #
355
+ def build_hash(hash, element)
356
+ if NOKOGIRI
357
+ array = element.children
358
+ if array.length==1 and (array.first.text? or array.first.cdata?)
359
+ r = array.first.text
360
+ else
361
+ r = {}
362
+ array.each { |c|
363
+ if c.element?
364
+ build_hash(r, c)
365
+ end
366
+ }
367
+ end
368
+ else
369
+ r = {}
370
+ if element.has_elements?
371
+ element.each_element { |c| build_hash(r, c) }
372
+ elsif element.has_text?
373
+ r = element.text
374
+ end
375
+ end
376
+
377
+ key = element.name
378
+ if hash.has_key?(key)
379
+ if hash[key].instance_of?(Array)
380
+ hash[key] << r
381
+ else
382
+ hash[key] = [hash[key], r]
383
+ end
384
+ else
385
+ hash[key] = r
386
+ end
387
+
388
+ hash
389
+ end
390
+
391
+ #
392
+ #
393
+ #
394
+ def attr_to_str(attr)
395
+ attr.gsub!('"',"\\\"")
396
+ attr = "\"#{attr}\""
397
+
398
+ return attr
399
+ end
400
+ end
401
+
402
+ # The XMLUtilsPool module provides an abstraction of the underlying
403
+ # XML parser engine. It provides XML-related methods for the Pools
404
+ class XMLPool < XMLElement
405
+
406
+ def initialize(xml=nil)
407
+ super(xml)
408
+ end
409
+
410
+ #Executes the given block for each element of the Pool
411
+ #block:: _Block_
412
+ def each_element(block)
413
+ if NOKOGIRI
414
+ @xml.xpath(
415
+ "#{@element_name}").each {|pelem|
416
+ block.call self.factory(pelem)
417
+ }
418
+ else
419
+ @xml.elements.each(
420
+ "#{@element_name}") {|pelem|
421
+ block.call self.factory(pelem)
422
+ }
423
+ end
424
+ end
425
+ end
426
+
427
+ end