1# 2# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) 3# 4# $Id: create.rb 36958 2012-09-13 02:22:10Z zzak $ 5# 6 7require "date" 8require "xmlrpc/base64" 9 10module XMLRPC # :nodoc: 11 12 module XMLWriter 13 14 class Abstract 15 def ele(name, *children) 16 element(name, nil, *children) 17 end 18 19 def tag(name, txt) 20 element(name, nil, text(txt)) 21 end 22 end 23 24 25 class Simple < Abstract 26 27 def document_to_str(doc) 28 doc 29 end 30 31 def document(*params) 32 params.join("") 33 end 34 35 def pi(name, *params) 36 "<?#{name} " + params.join(" ") + " ?>" 37 end 38 39 def element(name, attrs, *children) 40 raise "attributes not yet implemented" unless attrs.nil? 41 if children.empty? 42 "<#{name}/>" 43 else 44 "<#{name}>" + children.join("") + "</#{name}>" 45 end 46 end 47 48 def text(txt) 49 cleaned = txt.dup 50 cleaned.gsub!(/&/, '&') 51 cleaned.gsub!(/</, '<') 52 cleaned.gsub!(/>/, '>') 53 cleaned 54 end 55 56 end # class Simple 57 58 59 class XMLParser < Abstract 60 61 def initialize 62 require "xmltreebuilder" 63 end 64 65 def document_to_str(doc) 66 doc.to_s 67 end 68 69 def document(*params) 70 XML::SimpleTree::Document.new(*params) 71 end 72 73 def pi(name, *params) 74 XML::SimpleTree::ProcessingInstruction.new(name, *params) 75 end 76 77 def element(name, attrs, *children) 78 XML::SimpleTree::Element.new(name, attrs, *children) 79 end 80 81 def text(txt) 82 XML::SimpleTree::Text.new(txt) 83 end 84 85 end # class XMLParser 86 87 Classes = [Simple, XMLParser] 88 89 # yields an instance of each installed XML writer 90 def self.each_installed_writer 91 XMLRPC::XMLWriter::Classes.each do |klass| 92 begin 93 yield klass.new 94 rescue LoadError 95 end 96 end 97 end 98 99 end # module XMLWriter 100 101 # Creates XML-RPC call/response documents 102 # 103 class Create 104 105 def initialize(xml_writer = nil) 106 @writer = xml_writer || Config::DEFAULT_WRITER.new 107 end 108 109 110 def methodCall(name, *params) 111 name = name.to_s 112 113 if name !~ /[a-zA-Z0-9_.:\/]+/ 114 raise ArgumentError, "Wrong XML-RPC method-name" 115 end 116 117 parameter = params.collect do |param| 118 @writer.ele("param", conv2value(param)) 119 end 120 121 tree = @writer.document( 122 @writer.pi("xml", 'version="1.0"'), 123 @writer.ele("methodCall", 124 @writer.tag("methodName", name), 125 @writer.ele("params", *parameter) 126 ) 127 ) 128 129 @writer.document_to_str(tree) + "\n" 130 end 131 132 133 134 # 135 # Generates a XML-RPC methodResponse document 136 # 137 # When +is_ret+ is +false+ then the +params+ array must 138 # contain only one element, which is a structure 139 # of a fault return-value. 140 # 141 # When +is_ret+ is +true+ then a normal 142 # return-value of all the given +params+ is created. 143 # 144 def methodResponse(is_ret, *params) 145 146 if is_ret 147 resp = params.collect do |param| 148 @writer.ele("param", conv2value(param)) 149 end 150 151 resp = [@writer.ele("params", *resp)] 152 else 153 if params.size != 1 or params[0] === XMLRPC::FaultException 154 raise ArgumentError, "no valid fault-structure given" 155 end 156 resp = @writer.ele("fault", conv2value(params[0].to_h)) 157 end 158 159 160 tree = @writer.document( 161 @writer.pi("xml", 'version="1.0"'), 162 @writer.ele("methodResponse", resp) 163 ) 164 165 @writer.document_to_str(tree) + "\n" 166 end 167 168 169 170 private 171 172 # 173 # Converts a Ruby object into a XML-RPC <code><value></code> tag 174 # 175 def conv2value(param) # :doc: 176 177 val = case param 178 when Fixnum, Bignum 179 # XML-RPC's int is 32bit int, and Fixnum also may be beyond 32bit 180 if Config::ENABLE_BIGINT 181 @writer.tag("i4", param.to_s) 182 else 183 if param >= -(2**31) and param <= (2**31-1) 184 @writer.tag("i4", param.to_s) 185 else 186 raise "Bignum is too big! Must be signed 32-bit integer!" 187 end 188 end 189 when TrueClass, FalseClass 190 @writer.tag("boolean", param ? "1" : "0") 191 192 when Symbol 193 @writer.tag("string", param.to_s) 194 195 when String 196 @writer.tag("string", param) 197 198 when NilClass 199 if Config::ENABLE_NIL_CREATE 200 @writer.ele("nil") 201 else 202 raise "Wrong type NilClass. Not allowed!" 203 end 204 205 when Float 206 raise "Wrong value #{param}. Not allowed!" unless param.finite? 207 @writer.tag("double", param.to_s) 208 209 when Struct 210 h = param.members.collect do |key| 211 value = param[key] 212 @writer.ele("member", 213 @writer.tag("name", key.to_s), 214 conv2value(value) 215 ) 216 end 217 218 @writer.ele("struct", *h) 219 220 when Hash 221 # TODO: can a Hash be empty? 222 223 h = param.collect do |key, value| 224 @writer.ele("member", 225 @writer.tag("name", key.to_s), 226 conv2value(value) 227 ) 228 end 229 230 @writer.ele("struct", *h) 231 232 when Array 233 # TODO: can an Array be empty? 234 a = param.collect {|v| conv2value(v) } 235 236 @writer.ele("array", 237 @writer.ele("data", *a) 238 ) 239 240 when Time, Date, ::DateTime 241 @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S")) 242 243 when XMLRPC::DateTime 244 @writer.tag("dateTime.iso8601", 245 format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a)) 246 247 when XMLRPC::Base64 248 @writer.tag("base64", param.encoded) 249 250 else 251 if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable 252 # convert Ruby object into Hash 253 ret = {"___class___" => param.class.name} 254 param.instance_variables.each {|v| 255 name = v[1..-1] 256 val = param.instance_variable_get(v) 257 258 if val.nil? 259 ret[name] = val if Config::ENABLE_NIL_CREATE 260 else 261 ret[name] = val 262 end 263 } 264 return conv2value(ret) 265 else 266 ok, pa = wrong_type(param) 267 if ok 268 return conv2value(pa) 269 else 270 raise "Wrong type!" 271 end 272 end 273 end 274 275 @writer.ele("value", val) 276 end 277 278 def wrong_type(value) 279 false 280 end 281 282 283 end # class Create 284 285end # module XMLRPC 286 287