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