Changeset 24
- Timestamp:
- 03/20/01 23:17:56 (8 years ago)
- Files:
-
- trunk/lib/SOAP.rb (modified) (1 diff)
- trunk/lib/SOAPData.rb (modified) (1 diff)
- trunk/lib/SOAPElement.rb (modified) (1 diff)
- trunk/lib/SOAPProcessor.rb (modified) (1 diff)
- trunk/lib/SOAPProxy.rb (modified) (1 diff)
- trunk/lib/SOAPStreamHandler.rb (modified) (1 diff)
- trunk/lib/SOAPStreamHandler_without_http-access.rb (modified) (1 diff)
- trunk/lib/XMLSchemaDatatypes.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/lib/SOAP.rb
r2 r24 1 =begin 2 SOAP4R 3 Copyright (C) 2000 NAKAMURA Hiroshi. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 2 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT ANY 11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 PRATICULAR PURPOSE. See the GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass 16 Ave, Cambridge, MA 02139, USA. 17 =end 18 19 module SOAP 20 public 21 22 EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/' 23 EncodingNamespace = 'http://schemas.xmlsoap.org/soap/encoding/' 24 25 NextActor = 'http://schemas.xmlsoap.org/soap/actor/next' 26 27 AttrMustUnderstand = 'mustUnderstand' 28 AttrEncodingStyle = 'encodingStyle' 29 AttrActor = 'actor' 30 31 class Error < StandardError; end 32 33 class MethodDefinitionError < Error; end 34 class HTTPStreamError < Error; end 35 class PostUnavailableError < HTTPStreamError; end 36 class MPostUnavailableError < HTTPStreamError; end 37 38 class ArrayIndexOutOfBoundsError < Error; end 39 class ArrayStoreError < Error; end 40 41 class FaultError < Error 42 public 43 44 attr_reader :faultCode 45 attr_reader :faultString 46 attr_reader :faultActor 47 attr_reader :detail 48 49 def initialize( fault ) 50 @faultCode = fault.faultCode 51 @faultString = fault.faultString 52 @faultActor = fault.faultActor 53 @detail = fault.detail 54 end 55 end 56 57 class FormatDecodeError < Error; end 58 59 end 1 require 'soap/soap' trunk/lib/SOAPData.rb
r16 r24 1 =begin 2 SOAP4R 3 Copyright (C) 2000 NAKAMURA Hiroshi. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 2 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT ANY 11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 PRATICULAR PURPOSE. See the GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass 16 Ave, Cambridge, MA 02139, USA. 17 =end 18 19 require 'SOAP' 20 require 'XMLSchemaDatatypes' 21 require 'xmltreebuilder' 22 23 24 ### 25 ## SOAP utility module for classes( not instances! ) 26 # 27 class SOAPNS 28 public 29 30 attr_reader :defaultNamespace 31 attr_reader :namespaceTag 32 33 def initialize( initNamespace = {} ) 34 @namespaceTag = initNamespace 35 @defaultNamespace = nil 36 end 37 38 def assign( namespace, name = nil ) 39 if ( @namespaceTag.has_key?( namespace )) 40 false 41 elsif ( name == '' ) 42 @defaultNamespace = namespace 43 name 44 elsif ( @namespaceTag.has_value?( name )) 45 # Already assigned. Should raise Error? 46 name = SOAPNS.assign( namespace ) 47 @namespaceTag[ namespace ] = name 48 name 49 else 50 name ||= SOAPNS.assign( namespace ) 51 @namespaceTag[ namespace ] = name 52 name 53 end 54 end 55 56 def []( namespace ) 57 if ( @namespaceTag.has_key?( namespace )) 58 @namespaceTag[ namespace ] 59 else 60 nil 61 end 62 end 63 64 def clone() 65 SOAPNS.new( @namespaceTag.dup ) 66 end 67 68 def name( namespace, name ) 69 if ( namespace == @defaultNamespace ) 70 name 71 elsif @namespaceTag.has_key?( namespace ) 72 @namespaceTag[ namespace ] + ':' << name 73 else 74 raise FormatDecodeError.new( 'Namespace: ' << namespace << ' not defined yet.' ) 75 end 76 end 77 78 def compare( namespace, name, rhs ) 79 if ( namespace == @defaultNamespace ) 80 return true if ( name == rhs ) 81 end 82 83 if @namespaceTag.has_key?( namespace ) 84 return (( @namespaceTag[ namespace ] + ':' << name ) == rhs ) 85 end 86 87 return false 88 end 89 90 # $1 and $2 are necessary. 91 ParseRegexp = Regexp.new( '^([^:]+)(?::(.+))?$' ) 92 93 def parse( elem ) 94 namespace = nil 95 name = nil 96 ParseRegexp =~ elem 97 if $2 98 namespace = @namespaceTag.index( $1 ) 99 name = $2 100 if !namespace 101 raise FormatDecodeError.new( 'Unknown namespace qualifier: ' << $1 ) 102 end 103 elsif $1 104 namespace = @defaultNamespace 105 name = $1 106 end 107 if !name 108 raise FormatDecodeError.new( 'Illegal element format: ' << elem ) 109 end 110 return namespace, name 111 end 112 113 private 114 115 AssigningName = [ 0 ] 116 117 def self.assign( namespace ) 118 AssigningName[ 0 ] += 1 119 'n' << AssigningName[ 0 ].to_s 120 end 121 122 def self.reset() 123 AssigningName[ 0 ] = 0 124 end 125 end 126 127 128 ### 129 ## SOAP related datatypes. 130 # 131 module SOAPModuleUtils 132 include SOAP 133 include XML::SimpleTree 134 135 public 136 137 def decode( ns, elem ) 138 elem.normalize 139 value = if elem.childNodes[0] 140 elem.childNodes[0].nodeValue 141 else 142 '' 143 end 144 d = self.new( value ) 145 d.namespace, = ns.parse( elem.nodeName ) 146 d 147 end 148 149 private 150 151 def decodeChild( ns, elem ) 152 if isNull( ns, elem ) 153 return SOAPNull.decode( ns, elem ) 154 end 155 156 case getType( ns, elem ) 157 when 'int' 158 SOAPInt.decode( ns, elem ) 159 when 'integer' 160 SOAPInteger.decode( ns, elem ) 161 when 'boolean' 162 SOAPBoolean.decode( ns, elem ) 163 when 'string' 164 SOAPString.decode( ns, elem ) 165 when 'timeInstant' 166 SOAPTimeInstant.decode( ns, elem ) 167 when /\[\d*\]$/ 168 SOAPArray.decode( ns, elem ) 169 else 170 bOnlyText = true 171 elem.childNodes.each do | child | 172 next if ( isEmptyText( child )) 173 bOnlyText = false 174 break 175 end 176 if bOnlyText 177 # No type is set. Decode as SOAPString by default. 178 SOAPString.decode( ns, elem ) 179 else 180 SOAPStruct.decode( ns, elem ) 181 end 182 end 183 end 184 185 EmptyTextRegexp = Regexp.new( '\s*(?:\n\s*)*' ) 186 187 def isEmptyText( node ) 188 (( node.nodeName == '#text' ) and ( EmptyTextRegexp =~ node.nodeValue )) 189 end 190 191 def isNull( ns, elem ) 192 elem.attributes.each do | attr | 193 if ( ns.compare( XSD::InstanceNamespace, 'null', '1' )) 194 return true 195 end 196 end 197 false 198 end 199 200 def getType( ns, elem ) 201 elem.attributes.each do | attr | 202 if ( ns.compare( XSD::InstanceNamespace, 'type', attr.nodeName )) 203 return attr.nodeValue 204 end 205 end 206 nil 207 end 208 209 # $1 is necessary. 210 NSParseRegexp = Regexp.new( '^xmlns:?(.*)$' ) 211 212 def parseNS( ns, elem ) 213 return unless elem.attributes 214 elem.attributes.each do | attr | 215 next unless ( NSParseRegexp =~ attr.nodeName ) 216 # '' means 'default namespace'. 217 tag = $1 || '' 218 ns.assign( attr.nodeValue, tag ) 219 end 220 end 221 end 222 223 module SOAPBasetypeUtils 224 include SOAP 225 include XML::SimpleTree 226 227 public 228 229 def initialize( *vars ) 230 super( *vars ) 231 232 # SOAP Basetype is a XSD type. No need to reset @namespace. 233 # @namespace = EnvelopeNamespace 234 235 end 236 237 def encode( ns, name ) 238 attrs = [] 239 createNS( attrs, ns ) 240 attrs.push( datatypeAttr( ns )) 241 242 if ( self.to_s.empty? ) 243 Element.new( name, attrs ) 244 else 245 Element.new( name, attrs, Text.new( self.to_s )) 246 end 247 end 248 249 def ==( rhs ) 250 self.data == rhs 251 end 252 253 private 254 255 def datatypeAttr( ns ) 256 Attr.new( ns.name( XSD::InstanceNamespace, 'type' ), ns.name( @namespace, @typeName )) 257 end 258 259 def createNS( attrs, ns ) 260 unless ns[ XSD::Namespace ] 261 tag = ns.assign( XSD::Namespace ) 262 attrs.push( Attr.new( 'xmlns:' << tag, XSD::Namespace )) 263 end 264 end 265 end 266 267 268 ### 269 ## Basic datatypes. 270 # 271 class SOAPNull < XSDNull 272 extend SOAPModuleUtils 273 include SOAPBasetypeUtils 274 275 private 276 277 # Override the definition in SOAPBasetypeUtils. 278 def datatypeAttr( ns ) 279 Attr.new( ns.name( XSD::Namespace, 'null' ), '1' ) 280 end 281 282 # Override the definition in SOAPModuleUtils 283 def decode( ns, elem ) 284 d = self.new() 285 d.namespace, = ns.parse( elem.nodeName ) 286 d 287 end 288 end 289 290 class SOAPBoolean < XSDBoolean 291 extend SOAPModuleUtils 292 include SOAPBasetypeUtils 293 end 294 295 class SOAPString < XSDString 296 extend SOAPModuleUtils 297 include SOAPBasetypeUtils 298 end 299 300 class SOAPInteger < XSDInteger 301 extend SOAPModuleUtils 302 include SOAPBasetypeUtils 303 end 304 305 class SOAPInt < XSDInt 306 extend SOAPModuleUtils 307 include SOAPBasetypeUtils 308 end 309 310 class SOAPTimeInstant < XSDTimeInstant 311 extend SOAPModuleUtils 312 include SOAPBasetypeUtils 313 end 314 315 316 ### 317 ## Compound datatypes. 318 # 319 class SOAPCompoundBase < NSDBase 320 extend SOAPModuleUtils 321 322 public 323 324 def initialize( typeName ) 325 super( typeName, EnvelopeNamespace ) 326 end 327 end 328 329 330 class SOAPStruct < SOAPCompoundBase 331 include Enumerable 332 333 public 334 335 attr_reader :array 336 attr_reader :data 337 338 def initialize( typeName ) 339 super( typeName ) 340 @array = [] 341 @data = {} 342 end 343 344 def to_s() 345 str = '' 346 self.each do | key, data | 347 str << "#{ key }: #{ data }\n" 348 end 349 str 350 end 351 352 def add( name, newMember ) 353 addMember( name, newMember ) 354 end 355 356 def []( idx ) 357 if ( idx > array.size ) 358 raise ArrayIndexOutOfBoundsError.new( 'In ' << @typeName ) 359 end 360 @array[ idx ] 361 end 362 363 def has_key?( name ) 364 @data.has_key?( name ) 365 end 366 367 def each 368 @array.each do | key | 369 yield( key, @data[ key ] ) 370 end 371 end 372 373 def encode( ns, name ) 374 attrs = [] 375 createNS( attrs, ns ) 376 attrs.push( datatypeAttr( ns )) 377 378 children = @array.collect { | child | 379 @data[ child ].encode( ns.clone, child ) 380 } 381 382 Element.new( name, attrs, children ) 383 end 384 385 def self.decode( ns, elem ) 386 namespace, name = ns.parse( elem.nodeName ) 387 s = SOAPStruct.new( name ) 388 s.namespace = namespace 389 390 elem.childNodes.each do | child | 391 childNS = ns.clone 392 parseNS( childNS, child ) 393 next if ( isEmptyText( child )) 394 childName = ns.parse( child.nodeName )[1] 395 s.add( childName, decodeChild( childNS, child )) 396 end 397 s 398 end 399 400 private 401 402 def datatypeAttr( ns ) 403 Attr.new( ns.name( XSD::InstanceNamespace, 'type' ), ns.name( @namespace, @typeName )) 404 end 405 406 def createNS( attrs, ns ) 407 unless ns[ @namespace ] 408 tag = ns.assign( @namespace ) 409 attrs.push( Attr.new( 'xmlns:' << tag, @namespace )) 410 end 411 end 412 413 def addMember( name, initMember = nil ) 414 initMember = SOAPNull.new() unless initMember 415 416 instance_eval <<-EOS 417 def #{ name }() 418 @data[ '#{ name }' ] 419 end 420 421 def #{ name }=( newMember ) 422 @data[ '#{ name }' ] = newMember 423 end 424 EOS 425 426 @array.push( name ) 427 @data[ name ] = initMember 428 end 429 end 430 431 class SOAPArray < SOAPCompoundBase 432 include Enumerable 433 434 public 435 436 attr_reader :data 437 438 def initialize( typeName = nil ) 439 super( typeName ) 440 @data = [ [] ] 441 @variant = false 442 @rank = 1 443 end 444 445 def set( newArray ) 446 raise NotImplementError.new( 'Partially transmittion does not supported' ) 447 end 448 449 def add( newMember ) 450 if ( @rank != 1 ) 451 raise NotImplementError.new( 'Rank must be 1' ) 452 end 453 if ( @data[ 0 ].empty? and !@typeName ) 454 @typeName = SOAPArray.getAtype( newMember.typeName, @rank ) 455 @namespace = newMember.namespace # ?? 456 end 457 if ( @typeName != newMember.typeName ) 458 @variant = true 459 end 460 @data[ 0 ] << newMember 461 end 462 463 def []( idx ) 464 if ( @rank != 1 ) 465 raise NotImplementError.new( 'Rank must be 1' ) 466 end 467 if ( idx > @data[ 0 ].size ) 468 raise ArrayIndexOutOfBoundsError.new( 'In ' << @typeName ) 469 end 470 @data[ 0 ][ idx ] 471 end 472 473 def each 474 if ( @rank != 1 ) 475 raise NotImplementError.new( 'Rank must be 1' ) 476 end 477 @data[ 0 ].each do | datum | 478 yield( datum ) 479 end 480 end 481 482 def encode( ns, name ) 483 attrs = [] 484 createNS( attrs, ns ) 485 attrs.push( datatypeAttr( ns )) 486 487 children = @data[ 0 ].collect { | child | 488 childTypeName = contentsTypeName().gsub( /\[,*\]/, 'Array' ) 489 child.encode( ns.clone, childTypeName ) 490 } 491 Element.new( name, attrs, children ) 492 end 493 494 def isVariant? 495 @variant 496 end 497 498 private 499 500 def datatypeAttr( ns ) 501 Attr.new( ns.name( EncodingNamespace, 'arrayType' ), ns.name( @namespace, arrayTypeValue() )) 502 end 503 504 def createNS( attrs, ns ) 505 unless ns[ @namespace ] 506 tag = ns.assign( @namespace ) 507 attrs.push( Attr.new( 'xmlns:' << tag, @namespace )) 508 end 509 unless ns[ EncodingNamespace ] 510 tag = ns.assign( EncodingNamespace ) 511 attrs.push( Attr.new( 'xmlns:' << tag, EncodingNamespace )) 512 end 513 end 514 515 def contentsTypeName() 516 @typeName.dup.sub( /\[,*\]$/, '' ) 517 end 518 519 def arrayTypeValue() 520 contentsTypeName << '[' << @data.collect { |i| i.size }.join( ',' ) << ']' 521 end 522 523 # Module function 524 525 public 526 527 def self.decode( ns, elem ) 528 typeNamespace, typeNameString = ns.parse( getType( ns, elem )) 529 typeName, nofArray = parseType( typeNameString ) 530 s = SOAPArray.new( typeName ) 531 s.namespace, = ns.parse( elem.nodeName ) 532 533 i = 0 534 elem.childNodes.each do | child | 535 childNS = ns.clone 536 parseNS( childNS, child ) 537 next if ( isEmptyText( child )) 538 s.add( decodeChild( childNS, child )) 539 i += 1 540 if ( nofArray and ( i > nofArray.to_i )) 541 raise ArrayIndexOutOfBoundsError.new( 'In ' << elem.nodeName ) 542 end 543 end 544 s 545 end 546 547 private 548 549 def self.getAtype( typeName, rank ) 550 "#{ typeName }[" << ',' * ( rank - 1 ) << ']' 551 end 552 553 TypeParseRegexp = Regexp.new( '^(.+)\[(\d*)\]$' ) 554 555 def self.parseType( string ) 556 TypeParseRegexp =~ string 557 return $1, $2 558 end 559 end 1 require 'soap/baseData' trunk/lib/SOAPElement.rb
r17 r24 1 =begin 2 SOAP4R 3 Copyright (C) 2000 NAKAMURA Hiroshi. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 2 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT ANY 11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 PRATICULAR PURPOSE. See the GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass 16 Ave, Cambridge, MA 02139, USA. 17 =end 18 19 require 'SOAPData' 20 require 'xmltreebuilder' 21 22 23 ### 24 ## SOAP elements 25 # 26 class SOAPMethod < SOAPCompoundBase 27 public 28 29 attr_reader :namespace 30 attr_reader :name 31 attr_reader :paramDef 32 33 attr_accessor :paramNames 34 attr_reader :paramTypes 35 attr_reader :params 36 37 attr_reader :retName 38 attr_accessor :retVal 39 40 def initialize( namespace, name, paramDef = nil ) 41 super( self.type.to_s ) 42 43 @namespace = namespace 44 @name = name 45 @paramDef = paramDef 46 47 @paramNames = [] 48 @paramTypes = {} 49 @params = {} 50 @retName = nil 51 @retVal = nil 52 53 setParamDef() if @paramDef 54 end 55 56 def setParams( params ) 57 params.each do | param, data | 58 @params[ param ] = data 59 end 60 end 61 62 def encode( ns, forResponse = false ) 63 if !forResponse 64 paramElem = @paramNames.collect { | param | 65 @params[ param ].encode( ns.clone, param ) 66 } 67 Element.new( ns.name( @namespace, @name ), nil, paramElem ) 68 else 69 retElem = nil 70 if retVal.is_a?( SOAPStruct ) 71 children = retVal.collect { | param, data | 72 data.encode( ns.clone, param ) 73 } 74 retElem = Element.new( 'return', nil, children ) 75 else 76 retElem = retVal.encode( ns.clone, 'return' ) 77 end 78 Element.new( ns.name( @namespace, @name ), nil, retElem ) 79 end 80 end 81 82 private 83 84 def setParamDef() 85 @paramDef.each do | pair | 86 type, name = pair 87 type.scan( /[^,\s]+/ ).each do | typeToken | 88 case typeToken 89 when 'in' 90 @paramNames.push( name ) 91 @paramTypes[ name ] = 1 92 when 'out' 93 @paramNames.push( name ) 94 @paramTypes[ name ] = 2 95 when 'retval' 96 if ( @retName ) 97 raise MethodDefinitionError.new( 'Duplicated retval' ) 98 end 99 @retName = name 100 else 101 raise MethodDefinitionError.new( 'Unknown type: ' << typeToken ) 102 end 103 end 104 end 105 end 106 107 # Module function 108 109 public 110 111 def self.decode( ns, elem ) 112 retVal = nil 113 outParams = {} 114 elem.childNodes.each do | child | 115 next if ( isEmptyText( child )) 116 childNS = ns.clone 117 parseNS( childNS, child ) 118 if ( !retVal ) 119 retVal = decodeChild( childNS, child ) 120 else 121 # ToDo: [in/out] or [out] parameters here... 122 raise NotImplementError.new( '"out" parameters not supported.' ) 123 end 124 end 125 126 elemNamespace, elemName = ns.parse( elem.nodeName ) 127 m = SOAPMethod.new( elemNamespace, elemName ) 128 129 m.retVal = retVal 130 #m.setParams( outParams ) 131 m 132 end 133 end 134 135 136 class SOAPFault < SOAPCompoundBase 137 public 138 139 attr_reader :faultCode 140 attr_reader :faultString 141 attr_reader :faultActor 142 attr_reader :detail 143 attr_reader :options 144 145 def initialize( faultCode, faultString, faultActor, detail = nil, options = [] ) 146 super( self.type.to_s ) 147 @faultCode = faultCode 148 @faultString = faultString 149 @faultActor = faultActor 150 @detail = detail 151 @options = options 152 end 153 154 def encode( ns ) 155 # Caution: never been executed!! 156 faultElems = [ @faultCode.encode( ns, 'faultcode' ), 157 @faultString.encode( ns, 'faultstring' ), 158 @faultActor.encode( ns, 'faultactor' ) ] 159 faultElems.push( @detail.encode( ns, 'detail' )) if @detail 160 @options.each do | opt | 161 paramElem.push( opt.encode( ns )) 162 end 163 Element.new( ns.name( EnvelopeNamespace, 'Fault' ), nil, faultElems ) 164 end 165 166 # Module function 167 168 public 169 170 def self.decode( ns, elem ) 171 faultCode = nil 172 faultString = nil 173 faultActor = nil 174 detail = nil 175 options = [] 176 elem.childNodes.each do | child | 177 next if ( isEmptyText( child )) 178 childNS = ns.clone 179 parseNS( childNS, child ) 180 181 if ( childNS.compare( EnvelopeNamespace, 'faultcode', child.nodeName )) 182 raise FormatDecodeError.new( 'Duplicated faultcode in Fault' ) if faultCode 183 faultCode = SOAPInteger.decode( childNS, child ) 184 185 elsif ( childNS.compare( EnvelopeNamespace, 'faultstring', child.nodeName )) 186 raise FormatDecodeError.new( 'Duplicated faultstring in Fault' ) if faultString 187 faultString = SOAPString.decode( childNS, child ) 188 189 elsif ( childNS.compare( EnvelopeNamespace, 'faultactor', child.nodeName )) 190 raise FormatDecodeError.new( 'Duplicated faultactor in Fault' ) if faultActor 191 faultActor = SOAPString.decode( childNS, child ) 192 193 elsif ( childNS.compare( EnvelopeNamespace, 'detail', child.nodeName )) 194 raise FormatDecodeError.new( 'Duplicated detail in Fault' ) if detail 195 detail = decodeChild( childNS, child ) 196 197 else 198 options.push( decodeChild( childNS, child )) 199 end 200 end 201 202 SOAPFault.new( faultCode, faultString, faultActor, detail, options ) 203 end 204 end 205 206 207 class SOAPBody < SOAPCompoundBase 208 public 209 210 attr_reader :data 211 attr_reader :isFault 212 213 def initialize( data, isFault = false ) 214 super( self.type.to_s ) 215 @data = data 216 @isFault = isFault 217 end 218 219 def encode( ns, forResponse = false ) 220 attrs = [] 221 contents = nil 222 if @isFault 223 contents = @data.encode( ns ) 224 else 225 attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), EncodingNamespace )) 226 contents = @data.encode( ns, forResponse ) 227 end 228 229 Element.new( ns.name( EnvelopeNamespace, 'Body' ), attrs, contents ) 230 end 231 232 # Module function 233 234 public 235 236 def self.decode( ns, elem ) 237 data = nil 238 isFault = false 239 result = [] 240 241 elem.childNodes.each do | child | 242 childNS = ns.clone 243 parseNS( childNS, child ) 244 if ( isEmptyText( child )) 245 # Nothing to do. 246 elsif ( childNS.compare( EnvelopeNamespace, 'Fault', child.nodeName )) 247 data = SOAPFault.decode( childNS, child ) 248 isFault = true 249 elsif !data 250 data = SOAPMethod.decode( childNS, child ) 251 else 252 # ToDo: May be a pointer... 253 result.push( child ) 254 raise FormatDecodeError.new( 'Unknown node name: ' << child.nodeName ) 255 end 256 end 257 258 # ToDo: Must resolve pointers in result... 259 260 SOAPBody.new( data, isFault ) 261 end 262 end 263 264 265 class SOAPHeaderItem < SOAPCompoundBase 266 public 267 268 attr_reader :namespace 269 attr_reader :name 270 attr_accessor :content 271 attr_accessor :mustUnderstand 272 attr_accessor :encodingStyle 273 274 def initialize( namespace, name, content, mustUnderstand = false, encodingStyle = nil ) 275 super( self.type.to_s ) 276 @namespace = namespace 277 @name = name 278 @content = content 279 @mustUnderstand = mustUnderstand 280 @encodingStyle = encodingStyle 281 end 282 283 def encode( ns ) 284 return nil if @name.empty? 285 attrs = [] 286 attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrMustUnderstand ), ( @mustUnderstand ? '1' : '0' ))) 287 attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), @encodingStyle )) if @encodingStyle 288 Element.new( ns.name( @namespace, @name ), attrs, @content ) 289 end 290 291 # Module function 292 293 public 294 295 def self.decode( ns, elem ) 296 mustUnderstand = nil 297 encodingStyle = nil 298 elem.attributes.each do | attr | 299 name = attr.nodeName 300 if ( ns.compare( EnvelopeNamespace, AttrMustUnderstand, name )) 301 raise FormatDecodeError.new( 'Duplicated mustUnderstand in HeaderItem' ) if mustUnderstand 302 mustUnderstand = attr.nodeValue 303 elsif ( ns.compare( EnvelopeNamespace, AttrEncodingStyle, name )) 304 raise FormatDecodeError.new( 'Duplicated encodingStyle in HeaderItem' ) if encodingStyle 305 encodingStyle = attr.nodeValue 306 else 307 raise FormatDecodeError.new( 'Unknown attribute: ' << name ) 308 end 309 end 310 elemNamespace, elemName = ns.parse( elem.nodeName ) 311 312 # Convert NodeList to simple Array. 313 childArray = [] 314 elem.childNodes.each do | child | 315 childArray.push( child ) 316 end 317 318 SOAPHeaderItem.new( elemNamespace, elemName, childArray, mustUnderstand, encodingStyle ) 319 end 320 end 321 322 323 class SOAPHeader < SOAPArray 324 public 325 326 def initialize() 327 super( self.type.to_s ) 328 end 329 330 def encode( ns ) 331 children = @data.collect { | child | 332 child.encode( ns.clone ) 333 } 334 Element.new( ns.name( EnvelopeNamespace, 'Header' ), nil, children ) 335 end 336 337 def length 338 @data[ 0 ].length 339 end 340 341 # Module function 342 343 public 344 345 def self.decode( ns, elem ) 346 s = SOAPHeader.new() 347 elem.childNodes.each do | child | 348 childNS = ns.clone 349 parseNS( childNS, child ) 350 next if ( isEmptyText( child )) 351 s.add( SOAPHeaderItem.decode( childNS, child )) 352 end 353 s 354 end 355 end 356 357 358 class SOAPEnvelope < SOAPCompoundBase 359 public 360 361 attr_reader :header 362 attr_reader :body 363 364 def initialize( initHeader, initBody ) 365 super( self.type.to_s ) 366 @header = initHeader 367 @body = initBody 368 end 369 370 def encode( ns ) 371 # Namespace preloading. 372 attrs = ns.namespaceTag.collect { | namespace, tag | 373 if ( tag == '' ) 374 Attr.new( 'xmlns' , namespace ) 375 else 376 Attr.new( 'xmlns:' << tag, namespace ) 377 end 378 } 379 380 contents = [] 381 contents.push( @header.encode( ns )) if @header and @header.length > 0 382 contents.push( @body.encode( ns )) 383 384 Element.new( ns.name( EnvelopeNamespace, 'Envelope' ), attrs, contents ) 385 end 386 387 # Module function 388 389 public 390 391 def self.decode( ns, doc ) 392 if ( doc.childNodes.size != 1 ) 393 raise FormatDecodeError.new( 'Envelope must be a child.' ) 394 end 395 396 elem = doc.childNodes[ 0 ] 397 parseNS( ns, elem ) 398 399 if ( !ns.compare( EnvelopeNamespace, 'Envelope', elem.nodeName )) 400 raise FormatDecodeError.new( 'Envelope not found.' ) 401 end 402 403 header = nil 404 body = nil 405 elem.childNodes.each do | child | 406 childNS = ns.clone 407 parseNS( childNS, child ) 408 name = child.nodeName 409 if ( isEmptyText( child )) 410 # Nothing to do. 411 elsif ( childNS.compare( EnvelopeNamespace, 'Header', name )) 412 raise FormatDecodeError.new( 'Duplicated Header in Envelope' ) if header 413 header = SOAPHeader.decode( childNS, child ) 414 elsif ( childNS.compare( EnvelopeNamespace, 'Body', name )) 415 raise FormatDecodeError.new( 'Duplicated Body in Envelope' ) if body 416 body = SOAPBody.decode( childNS, child ) 417 else 418 raise FormatDecodeError.new( 'Unknown scoping element: ' << name ) 419 end 420 end 421 422 SOAPEnvelope.new( header, body ) 423 end 424 end 1 requre 'soap/element' trunk/lib/SOAPProcessor.rb
r21 r24 1 =begin 2 SOAP4R 3 Copyright (C) 2000 NAKAMURA Hiroshi. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 2 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT ANY 11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 PRATICULAR PURPOSE. See the GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass 16 Ave, Cambridge, MA 02139, USA. 17 =end 18 19 require 'SOAP' 20 require 'SOAPElement' 21 require 'XMLSchemaDatatypes' 22 23 module SOAPProcessor 24 public 25 26 ### 27 ## SOAP marshaling 28 # 29 def marshal( ns, header, body ) 30 31 # Namespace preparing. 32 ns.assign( SOAP::EnvelopeNamespace, SOAPNamespaceTag ) 33 ns.assign( XSD::Namespace, XSDNamespaceTag ) 34 ns.assign( XSD::InstanceNamespace, XSINamespaceTag ) 35 36 # Create SOAP envelope. 37 env = SOAPEnvelope.new( header, body ) 38 39 # XML tree construction. 40 XML::SimpleTree::Document.new( env.encode( ns )) 41 end 42 43 ### 44 ## SOAP unmarshaling 45 # 46 def unmarshal( stream ) 47 48 # Namespace preparing. 49 ns = SOAPNS.new() 50 51 # XML tree parsing. 52 builder = XML::SimpleTreeBuilder.new() 53 tree = builder.parse( stream ) 54 tree.documentElement.normalize 55 56 # Parse SOAP envelope. 57 env = SOAPEnvelope.decode( ns, tree ) 58 59 return ns, env.header, env.body 60 end 61 62 private 63 64 SOAPNamespaceTag = 'SOAP-ENV' 65 XSDNamespaceTag = 'xsd' 66 XSINamespaceTag = 'xsi' 67 end 1 require 'soap/processor' trunk/lib/SOAPProxy.rb
r20 r24 1 =begin 2 SOAP4R 3 Copyright (C) 2000 NAKAMURA Hiroshi. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 2 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT ANY 11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 PRATICULAR PURPOSE. See the GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass 16 Ave, Cambridge, MA 02139, USA. 17 =end 18 19 require 'SOAP' 20 require 'SOAPProcessor' 21 require 'SOAPStreamHandler' 22 23 24 class SOAPProxy 25 include SOAPProcessor 26 27 public 28 29 attr_reader :namespace 30 31 def initialize( namespace, streamHandler ) 32 @namespace = namespace 33 @handler = streamHandler 34 @method = {} 35 end 36 37 class Request 38 public 39 40 attr_reader :method 41 attr_reader :namespace 42 attr_reader :name 43 44 def initialize( modelMethod, values ) 45 @method = SOAPMethod.new( modelMethod.namespace, modelMethod.name, 46 modelMethod.paramDef ) 47 @namespace = @method.namespace 48 @name = @method.name 49 50 params = {} 51 52 if (( values.size == 1 ) and ( values[0].is_a?( Hash ))) 53 params = values[ 0 ] 54 else 55 0.upto( values.size - 1 ) do | i | 56 params[ @method.paramNames[ i ]] = values[ i ] || SOAPNull.new() 57 end 58 end 59 @method.setParams( params ) 60 end 61 end 62 63 # Method definition. 64 def addMethod( methodName, paramDef ) 65 @method[ methodName ] = SOAPMethod.new( @namespace, methodName, paramDef ) 66 end 67 68 # Create new request. 69 def createRequest( methodName, *values ) 70 if ( @method.has_key?( methodName )) 71 method = @method[ methodName ] 72 else 73 raise MethodDefinitionError.new( 'Method: ' << methodName << ' not defined.' ) 74 end 75 76 Request.new( method, values ) 77 end 78 79 # Method calling. 80 def call( ns, headers, methodName, *values ) 81 82 # Create new request 83 req = createRequest( methodName, *values ) 84 85 # SOAP tree construction. 86 tree = createTree( ns, headers, req ) 87 88 # Send request. 89 receiveString = sendRequest( req, tree ) 90 91 # SOAP tree parsing. 92 ns, header, body = unmarshal( receiveString ) 93 94 # Check Fault. 95 checkFault( ns, body ) 96 97 # Used namespaces, header element, and body element. 98 return ns, header, body 99 end 100 101 # SOAP tree construction. 102 def createTree( ns, headers, request ) 103 # Preparing headers. 104 header = SOAPHeader.new() 105 if headers 106 headers.each do | namespace, elem, content, mustUnderstand, encodingStyle | 107 header.add( SOAPHeaderItem.new( namespace, elem, content, mustUnderstand, encodingStyle )) 108 end 109 end 110 111 # Preparing body. 112 body = SOAPBody.new( request.method ) 113 114 # Tree construction. 115 soapTree = marshal( ns, header, body ) 116 117 return soapTree 118 end 119 120 # Send the request. 121 def sendRequest( request, tree ) 122 # Serialize. 123 sendString = tree.to_s 124 125 # Send request. 126 receiveString = @handler.send( request.namespace, request.name, sendString ) 127 128 receiveString 129 end 130 131 # SOAP Fault checking. 132 def checkFault( ns, body ) 133 if ( body.isFault ) 134 raise FaultError.new( body.data ) 135 end 136 end 137 end 1 require 'soap/proxy' trunk/lib/SOAPStreamHandler.rb
r19 r24 1 =begin 2 SOAP4R 3 Copyright (C) 2000 NAKAMURA Hiroshi. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 2 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT ANY 11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 PRATICULAR PURPOSE. See the GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass 16 Ave, Cambridge, MA 02139, USA. 17 =end 18 19 require 'socket' 20 require 'timeout' 21 22 require 'SOAP' 23 require 'http-access' 24 require 'uri' 25 26 class SOAPStreamHandler 27 public 28 29 attr_reader :endPoint 30 31 def initialize( endPoint ) 32 @endPoint = endPoint 33 end 34 end 35 36 37 class SOAPHTTPPostStreamHandler < SOAPStreamHandler 38 public 39 40 MediaType = 'text/xml' 41 42 NofRetry = 10 # [times] 43 CallTimeout = 3