1# validator.tcl - Copyright (C) 2001 Pat Thoyts <Pat.Thoyts@bigfoot.com> 2# 3# Implement the http://validator.soapware.org/ interoperability suite and 4# the http://validator1.xmlrpc.org/ XML-RPC interop suite. 5# 6# ------------------------------------------------------------------------- 7# This software is distributed in the hope that it will be useful, but 8# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 9# or FITNESS FOR A PARTICULAR PURPOSE. See the accompanying file `LICENSE' 10# for more details. 11# ------------------------------------------------------------------------- 12# 13# @(#)$Id: validator.tcl,v 1.3 2001/08/07 12:07:06 patthoyts Exp $ 14 15package require SOAP 16package require XMLRPC 17package require rpcvar 18namespace import -force rpcvar::* 19 20# ------------------------------------------------------------------------- 21 22# Export the SOAP webservices 23 24SOAP::export whichToolkit countTheEntities easyStructTest echoStructTest \ 25 manyTypesTest moderateSizeArrayCheck simpleStructReturnTest \ 26 nestedStructTest 27 28# Export the XML-RPC webservices. 29 30XMLRPC::export validator1.whichToolkit validator1.countTheEntities \ 31 validator1.easyStructTest validator1.echoStructTest \ 32 validator1.manyTypesTest validator1.moderateSizeArrayCheck \ 33 validator1.simpleStructReturnTest validator1.nestedStructTest \ 34 validator1.arrayOfStructsTest 35 36# ------------------------------------------------------------------------- 37 38# Optional feature used by the validator at http://validator.soapware.org/ 39# Helps them to work out what SOAP toolkit is providing the service. 40# 41proc validator1.whichToolkit {} { 42 if {[catch {package require SOAP} soapVersion]} { 43 set soapVersion {unknown} 44 } 45 set r(toolkitDocsUrl) "http://tclsoap.sourceforge.net/" 46 set r(toolkitName) "TclSOAP" 47 set r(toolkitVersion) $soapVersion 48 set r(toolkitOperatingSystem) "System Independent" 49 return [rpcvar struct r] 50} 51 52# ------------------------------------------------------------------------- 53 54# validator1.countTheEntities (s) returns struct 55# 56# This handler takes a single parameter named s, a string, that 57# contains any number of predefined entities, namely <, >, &, ' and ". 58# 59# Your handler must return a struct that contains five fields, all 60# numbers: ctLeftAngleBrackets, ctRightAngleBrackets, ctAmpersands, 61# ctApostrophes, ctQuotes. 62# 63# To validate, the numbers must be correct. 64# 65proc validator1.countTheEntities {s} { 66 array set a {< 0 > 0 & 0 ' 0 \" 0} 67 foreach c [split $s {}] { 68 if {[catch {incr a($c)}]} { 69 set a($c) 1 70 } 71 } 72 set r(ctLeftAngleBrackets) $a(<) 73 set r(ctRightAngleBrackets) $a(>) 74 set r(ctAmpersands) $a(&) 75 set r(ctApostrophes) $a(\') 76 set r(ctQuotes) $a(\") 77 return [rpcvar struct r] 78} 79 80# ------------------------------------------------------------------------- 81 82# validator1.easyStructTest (stooges) returns number 83# 84# This handler takes a single parameter named stooges, a struct, 85# containing at least three elements named moe, larry and curly, all 86# ints. Your handler must add the three numbers and return the result. 87# 88proc validator1.easyStructTest {stooges} { 89 array set stooge $stooges 90 set r [expr $stooge(larry) + $stooge(curly) + $stooge(moe)] 91 return $r 92} 93 94# ------------------------------------------------------------------------- 95 96# validator1.echoStructTest (myStruct) returns struct 97# 98# This handler takes a single parameter named myStruct, a struct. Your 99# handler must return the struct. 100# 101# This is a struct of structs (actually an array but with different names 102# for each item). 103# 104proc validator1.echoStructTest {myStruct} { 105 set r {} 106 foreach {name value} $myStruct { 107 lappend r $name [rpcvar struct $value] 108 } 109 110 return [rpcvar struct $r] 111} 112 113# ------------------------------------------------------------------------- 114 115# validator1.manyTypesTest (num, bool, state, doub, dat, bin) returns array 116# 117# This handler takes six parameters and returns an array containing 118# all the parameters. 119# 120proc validator1.manyTypesTest {num bool state doub dat bin} { 121 set r {} 122 if {$bool} {set bool true} else {set bool false} 123 set dat [rpcvar "dateTime.iso8601" $dat] 124 set bin [rpcvar "base64" $bin] 125 lappend r $num $bool $state $doub $dat $bin 126 return [rpcvar array $r] 127} 128 129# I need to do better handling of the type mismatching between SOAP and 130# XML-RPC, until then... 131proc soapvalidator.manyTypesTest {num bool state doub dat bin} { 132 set r {} 133 if {$bool} {set bool true} else {set bool false} 134 set dat [rpcvar "timeInstant" $dat] 135 lappend r $num $bool $state $doub $dat $bin 136 return [rpcvar array $r] 137} 138 139# ------------------------------------------------------------------------- 140 141# validator1.moderateSizeArrayCheck (myArray) returns string 142# 143# This handler takes a single parameter named myArray, which is an 144# array containing between 100 and 200 elements. Each of the items is 145# a string, your handler must return a string containing the 146# concatenated text of the first and last elements. 147 148proc validator1.moderateSizeArrayCheck {myArray} { 149 return "[lindex $myArray 0][lindex $myArray end]" 150} 151 152# ------------------------------------------------------------------------- 153 154# validator1.simpleStructReturnTest (myNumber) returns struct 155# 156# This handler takes one parameter a number named myNumber, and returns 157# a struct containing three elements, times10, times100 and times1000, 158# the result of multiplying the number by 10, 100 and 1000 159# 160proc validator1.simpleStructReturnTest {myNumber} { 161 set r(times10) [expr $myNumber * 10] 162 set r(times100) [expr $myNumber * 100] 163 set r(times1000) [expr $myNumber * 1000] 164 return [rpcvar struct r] 165} 166 167# ------------------------------------------------------------------------- 168 169# validator1.arrayOfStructsTest (array) returns number 170 171# This handler takes a single parameter, an array of structs, each of 172# which contains at least three elemenets names noe, larry and curly, 173# all <i4>'s. Your handler must add all the struct elements named curly 174# and return the result. 175# 176proc validator1.arrayOfStructsTest {myArray} { 177 set r 0 178 foreach itemdata $myArray { 179 array set item $itemdata 180 incr r $item(curly) 181 } 182 return $r 183} 184 185# ------------------------------------------------------------------------- 186 187# validator1.nestedStructTest (myStruct) returns number 188# 189# This handler takes a single parameter named myStruct, a struct, that 190# models a daily calendar. At the top level, there is one struct for 191# each year. Each year is broken down into months, and months into 192# days. Most of the days are empty in the struct you receive, but the 193# entry for April 1, 2000 contains a least three elements named moe, 194# larry and curly, all <i4>s. Your handler must add the three numbers 195# and return the result. 196# NB: month and day are two-digits with leading 0s, and January is 01 197# 198# First, the XML-RPC implementation. 199proc validator1.nestedStructTest {myStruct} { 200 array set ms $myStruct 201 array set y2k $ms(2000) 202 array set m4 $y2k(04) 203 array set d1 $m4(01) 204 return [expr $d1(larry) + $d1(moe) + $d1(curly)] 205} 206# The SOAP implementation receives different member names. 207proc soapvalidator.nestedStructTest {myStruct} { 208 array set ms $myStruct 209 array set y2k $ms(year2000) 210 array set m4 $y2k(month04) 211 array set d1 $m4(day01) 212 return [expr $d1(larry) + $d1(moe) + $d1(curly)] 213} 214 215# ------------------------------------------------------------------------- 216 217# Description: 218# Given the nested structure provided for the nestedStructTest, 219# echo the struct back to the caller. 220# Notes: 221# This is not one of the required tests, but writing this exposed some 222# issues in handling nested structures within the TclSOAP framework. It 223# works now. However, this implementation will not ensure that the structure 224# members are returned in the same order that they were provided. 225# 226proc validator1.echoNestedStructTest {myStruct} { 227 global years 228 array set years {} 229 foreach {name value} $myStruct { 230 set years($name) [year $value] 231 } 232 return [rpcvar struct years] 233} 234 235proc year {yearValue} { 236 array set months {} 237 foreach {name value} $yearValue { 238 set months($name) [month $value] 239 } 240 return [rpcvar struct months] 241} 242 243proc month {monthValue} { 244 array set days {} 245 foreach {name value} $monthValue { 246 set days($name) [day $value] 247 } 248 return [rpcvar struct days] 249} 250 251proc day {dayValue} { 252 array set stooges {} 253 foreach {name value} $dayValue { 254 set stooges($name) $value 255 } 256 return [rpcvar struct stooges] 257} 258 259# ------------------------------------------------------------------------- 260 261# Link the XMLRPC names to global names suitable for use with SOAP. 262# 263# XMLRPC expects to see the method names as defined in this file, but SOAP 264# expects methods to be in an XML namespace. For the validator test suite 265# here, that namespace is global, thus: 266# 267foreach procname [info proc validator1.*] { 268 set soapname [lindex [split $procname .] end] 269 if {[string match "nestedStructTest" $soapname]} { 270 set procname soapvalidator.nestedStructTest ;# redirect for SOAP 271 } 272 if {[string match "manyTypesTest" $soapname]} { 273 set procname soapvalidator.manyTypesTest ;# redirect for SOAP 274 } 275 interp alias {} $soapname {} $procname 276} 277 278# The whichToolkit method is called from http://www.soapware.org/ namespace 279# So expose it. 280namespace eval http://www.soapware.org/ { 281 SOAP::export whichToolkit 282 interp alias {} whichToolkit {} ::validator1.whichToolkit 283} 284 285# ------------------------------------------------------------------------- 286 287# 288# Local variables: 289# mode: tcl 290# End: 291