#LyX 1.4.4 created this file. For more info see http://www.lyx.org/
\lyxformat 245
\begin_document
\begin_header
\textclass article
\begin_preamble
\usepackage{ae,aecompl}
\usepackage{html}
\end_preamble
\language english
\inputencoding auto
\fontscheme default
\graphics default
\paperfontsize default
\spacing single
\papersize default
\use_geometry true
\use_amsmath 1
\cite_engine basic
\use_bibtopic false
\paperorientation portrait
\leftmargin 2.5cm
\topmargin 2cm
\rightmargin 2cm
\bottommargin 2cm
\secnumdepth 3
\tocdepth 3
\paragraph_separation skip
\defskip medskip
\quotes_language english
\papercolumns 1
\papersides 1
\paperpagestyle default
\tracking_changes false
\output_changes true
\end_header
\begin_body
\begin_layout Title
Interoperable Python ZSI WSDL/SOAP Web Services tutorial
\end_layout
\begin_layout Author
Holger Joukl
\newline
LBBW Financial Markets Technologies
\end_layout
\begin_layout Abstract
This is the follow-up to
\begin_inset Quotes eld
\end_inset
Interoperable WSDL/SOAP web services introduction: Python ZSI, Excel XP,
gSOAP C/C++ & Applix SS
\begin_inset Quotes erd
\end_inset
\begin_inset LatexCommand \cite{InteropHOLGER}
\end_inset
, with a more explicit focus on Python ZSI Web Services.
\newline
\newline
Now that the
\begin_inset Quotes eld
\end_inset
services/SOA
\begin_inset Quotes erd
\end_inset
hype & buzzword-storm has calmed down, building SOAP web services servers
and clients is widely regarded to have become a commodity.
While the complexness of the actual protocols/specs remains, toolkit magic
is getting more robust so users seldom need to get down to the nitty-gritty
any more.
Also, toolkit documentation has broadened and matured.
We believe however that a) there can never be enough documentation and
b) the intention of this document to be a step-by-step tutorial in the
sense of a complete walkthrough still fills a gap.
\newline
It features
\end_layout
\begin_deeper
\begin_layout Itemize
as its focus the Python ZSI module (2.0 and 2.1alpha) that is used to build
the server side machinery and
\end_layout
\begin_layout Itemize
several clients that access the exposed services from
\end_layout
\begin_deeper
\begin_layout Itemize
Python (ZSI 2.0 + 2.1alpha)
\end_layout
\begin_layout Itemize
C/C++ (gSOAP 2.7.9)
\end_layout
\end_deeper
\end_deeper
\begin_layout Standard
Copyright Đ 2007-2008 Holger Joukl.
All rights reserved.
\end_layout
\begin_layout Standard
All trademarks mentioned in this document are the property of their respective
owners.
\end_layout
\begin_layout Standard
Redistribution and use in source (LyX, LaTeX) and 'compiled' forms (SGML,
HTML, PDF, PostScript, RTF and so forth) with or without modification,
are permitted provided that the following conditions are met:
\end_layout
\begin_layout Enumerate
Redistributions of source code (LyX, LaTeX) must retain the above copyright
notice, this list of conditions and the following disclaimer as the first
lines of this file unmodified.
\end_layout
\begin_layout Enumerate
Redistributions in compiled form (transformed to other DTDs, converted to
PDF, PostScript, RTF and other formats) must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the documentati
on and/or other materials provided with the distribution.
\end_layout
\begin_layout Standard
THIS DOCUMENTATION IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATIO
N, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\backslash
pagebreak
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset LatexCommand \tableofcontents{}
\end_inset
\end_layout
\begin_layout Section
Introduction
\end_layout
\begin_layout Standard
This is the follow-up to article
\begin_inset LatexCommand \cite{InteropHOLGER}
\end_inset
, mainly prompted by the need to get up-to-date with newer toolkit versions,
especially the many changes and improvements in ZSI.
While not explicitly stated, ZSI has been the strong focus of this installment
from the very beginning, easily noticeable by the fact that all the server
code has been Python ZSI-based.
Therefore, this document focuses on ZSI and reduces the number of discussed
Web Service client implementations in comparison to
\begin_inset LatexCommand \cite{InteropHOLGER}
\end_inset
.
\end_layout
\begin_layout Standard
The toolkit versions discussed here are:
\end_layout
\begin_layout Itemize
ZSI 2.0 + 2.1alpha1 (Python 2.4.4)
\end_layout
\begin_layout Itemize
gSOAP 2.7.9 (gcc 2.95.2, gcc 3.4.4)
\end_layout
\begin_layout Standard
These are being put to use for several example Web Services.
\end_layout
\begin_layout Standard
For legacy reference, the steps to instrument VistaSource Applixware 4.43
with Web Services capabilities (which is probably of minor interest to
the average ZSI/gSOAP user) have been updated for the few gSOAP handling
changes and still remain available in appendix
\begin_inset LatexCommand \ref{sec:VistaSource-Applixware-spreadsheets}
\end_inset
.
\end_layout
\begin_layout Standard
Appendix
\begin_inset LatexCommand \ref{sec:ZSI-hack}
\end_inset
features a (arguably nifty) way to make ZSI tracing more verbose.
\end_layout
\begin_layout Subsection
Goals & Concepts
\end_layout
\begin_layout Standard
This is a practice-report-gone-tutorial.
The content and code examples presented here have been developed with the
primary goal to
\begin_inset Quotes eld
\end_inset
make (fairly) simple examples work (at all)
\begin_inset Quotes erd
\end_inset
, in a learning-by-doing manner.
Thus there is lots of room for enhancements, e.g.
getting rid of hardcoded path names etc.
\end_layout
\begin_layout Standard
All code examples are complete, executable and delivered with all the necessary
command-line options to create and/or compile and/or run them.
\end_layout
\begin_layout Standard
Conceptually, we use a WSDL-centric approach, sometimes referred to as top-down
development: The starting point for all example service and client implementati
ons will be the WSDL description.
Note that this might differ from certain toolkits that start out with the
service implementation in the host language and generate the WSDL for you
to expose the implemented service.
We regard the latter to have a tendency to not promote interoperability
and to tie in implementation language details, which is certainly not what
we want.
\begin_inset Foot
status open
\begin_layout Standard
In the first place, this came up partly due to the fact that the chosen
server implementation (Python ZSI) offered no such tool and partly as a
gut feeling.
Since then, this opinion has grown stronger and has also been backed up
by several practitionersī readings at a conference (Stuttgarter Softwaretechnik
Forum 2005, Stuttgart-Vaihingen, Germany) as well as experience.
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Striving for interoperability, only the WS-I-compliant
\begin_inset Foot
status open
\begin_layout Standard
The
\series bold
W
\series default
eb
\series bold
S
\series default
ervices-
\series bold
I
\series default
nteroperability Organization (
\begin_inset ERT
status open
\begin_layout Standard
\backslash
htmladdnormallink{www.ws-i.org}{http://www.ws-i.org}
\end_layout
\end_inset
) provides so-called
\begin_inset Quotes eld
\end_inset
profile
\begin_inset Quotes erd
\end_inset
guidelines on using Web Services specifications in an interoperable manner.
\end_layout
\end_inset
rpc/literal and document/literal WSDL styles are presented here.
\end_layout
\begin_layout Standard
Throughout this document, certain host names or ports (
\begin_inset Quotes eld
\end_inset
8080
\begin_inset Quotes erd
\end_inset
) might used in the examples - you will have to substitute those with the
appropriate setup for your site, of course.
Naturally, this can affect URLs defined in the example WSDLs and used to
retrieve these WSDLs.
\end_layout
\begin_layout Standard
Whenever you see sample client or server output throughout this document
this is real output copied from live components but might have been reformatted
to fit into the document somewhat nicer.
\end_layout
\begin_layout Subparagraph
Acknowledgments:
\end_layout
\begin_layout Standard
Thank you to the ZSI developers for supporting a great product!
\end_layout
\begin_layout Standard
The DateService WSDL (sect.
\begin_inset LatexCommand \ref{sub:The-DateService-WSDL}
\end_inset
) and worker code (sect.
\begin_inset LatexCommand \ref{sub:A-Python-ZSI-DateService-server}
\end_inset
) are courtesy of Rainer Kluger (LBBW Financial Markets Technologies).
\end_layout
\begin_layout Subsection
Prerequisites
\end_layout
\begin_layout Standard
We assume the reader is familiar with Python and/or C/C++ to a certain degree.
The web service server components are implemented in Python, so to build
a working server with the code samples some Python knowledge is needed,
but any of the client side technologies can be skipped if not of particular
interest.
\end_layout
\begin_layout Standard
While some basic concepts regarding WSDL, SOAP, HTTP servers are presented
here implicitly, this document is not a tutorial on these.
If you want to know more thereīs plenty of stuff on the web.
\end_layout
\begin_layout Subsection
A glance at the toolkits
\end_layout
\begin_layout Subsubsection
ZSI
\end_layout
\begin_layout Standard
The Python ZSI package
\begin_inset LatexCommand \cite{ZSIrefdoc2.0}
\end_inset
is the actively maintained one of two
\begin_inset Quotes eld
\end_inset
pywebsvcs
\begin_inset Quotes erd
\end_inset
\begin_inset Foot
status open
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\backslash
htmladdnormallink{http://pywebsvcs.sourceforge.net/}{http://pywebsvcs.sourceforge.ne
t/}
\end_layout
\end_inset
\end_layout
\begin_layout Standard
SourceForge project page:
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\backslash
htmladdnormallink{http://sourceforge.net/projects/pywebsvcs}{http://sourceforge.ne
t/projects/pywebsvcs}
\end_layout
\end_inset
\end_layout
\end_inset
packages
\begin_inset Foot
status open
\begin_layout Standard
The other being SOAPpy.
\end_layout
\end_inset
implementing web services for Python, namely SOAP 1.1 messaging and WSDL
capabilities.
It is powerful and easy to get started with.
With the arrival of ZSI 2.0 not only have the ZSI developers honed the features
and ease-of-use of their fine product but also the documentation has enhanced
quite a bit (see especially the ZSI user guide
\begin_inset LatexCommand \cite{ZSIuserguide2.0}
\end_inset
).
As always, thereīs still room for improvement, and we hope to provide some
added value by presenting simple, concise examples here.
\end_layout
\begin_layout Standard
At the time of writing, ZSI is in flux again with regard to a planned move
to WSGI
\begin_inset Foot
status open
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\backslash
htmladdnormallink{Python Web Server Gateway Interface v1.0}{http://www.python.org/d
ev/peps/pep-0333/}
\end_layout
\end_inset
\end_layout
\end_inset
support, which 2.1alpha1 already gives a notion of, and certain code generation/
naming conventions.
For the time being, we rely on
\begin_inset Quotes eld
\end_inset
classic
\begin_inset Quotes erd
\end_inset
ZSI usage here, presenting both 2.0 and 2.1alpha code versions in our examples.
All code denoted as ZSI 2.1 refers to 2.1alpha1-compatible code, as of release
2.1alpha1 (2007-11-01).
As a side note, ZSI 2.1 gains a massive performance boost from switching
to minidom as default parser, removing the dependency on PyXML.
\end_layout
\begin_layout Subsubsection
gSOAP
\end_layout
\begin_layout Standard
gSOAP is an impressive open source web services development toolkit for
C/C++.
It seems to be very mature and complete and has an extensive record of
being used in real-world applications by major companies.
One of its key-features is the support for XML-to-C/C++ mapping for native
C and C++ data types.
It claims to be the fastest SOAP 1.1/1.2 compliant C/C++ implementation out
there and comes with good documentation.
\end_layout
\begin_layout Section
Simple datatypes: The rpc/literal SquareService
\end_layout
\begin_layout Standard
This first example will implement an overly simple service that exposes
a function which takes a
\family typewriter
double
\family default
argument and returns the square of it (
\begin_inset Formula $x{}^{\textrm{2}}$
\end_inset
) as a
\family typewriter
double
\family default
.
I.e.
this examples uses simple scalar datatypes, one single argument and one
single return value.
\end_layout
\begin_layout Subsection
The SquareService WSDL
\end_layout
\begin_layout Standard
This is the WSDL file that determines the contract for the SquareService,
called
\family typewriter
SquareService.wsdl
\family default
:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
the square method
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Returns x^2 (x**2, square(x)) for a given float x
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
The
\family typewriter
style
\family default
\begin_inset Quotes eld
\end_inset
rpc
\begin_inset Quotes erd
\end_inset
and the
\family typewriter
use
\family default
\begin_inset Quotes eld
\end_inset
literal
\begin_inset Quotes erd
\end_inset
are used, to be WS-I-compliant.
WS-I only supports rpc/literal and document/literal.
\end_layout
\begin_layout Itemize
A custom port 8080 is used instead of the usual HTTP port 80.
\end_layout
\begin_layout Itemize
The server name is a
\begin_inset Quotes eld
\end_inset
symbolic
\begin_inset Quotes erd
\end_inset
name, not a real known name in our site.
This can cause the need to give explicit URLs from time to time.
\end_layout
\begin_layout Subsection
A Python ZSI server for the SquareService
\end_layout
\begin_layout Subsubsection
Generating stubs from WSDL
\end_layout
\begin_layout Paragraph
ZSI 2.1
\end_layout
\begin_layout Standard
ZSI 2.1 comes with a python script
\family typewriter
wsdl2py
\family default
to generate code from a WSDL file.
It creates
\end_layout
\begin_layout Itemize
python bindings for the service and data structures and
\end_layout
\begin_layout Itemize
a server skeleton for service dispatch where the actual service worker code
will be hooked into.
\end_layout
\begin_layout Standard
If you have installed ZSI on top of your python installation you can invoke
the scripts like this (change your installation base path according to
your setup):
\begin_inset Foot
status open
\begin_layout Standard
The installation base path for all ZSI 2.1 examples here is /apps/pydev/hjoukl.
\end_layout
\end_inset
\end_layout
\begin_layout LyX-Code
/apps/pydev/hjoukl/bin/wsdl2py SquareService.wsdl
\end_layout
\begin_layout Standard
This will generate the files
\end_layout
\begin_layout Itemize
\family typewriter
SquareService_client.py,
\end_layout
\begin_layout Itemize
\family typewriter
SquareService_server.py
\family default
and
\family typewriter
\end_layout
\begin_layout Itemize
\family typewriter
SquareService_types.py
\family default
.
\end_layout
\begin_layout Paragraph
ZSI 2.0
\end_layout
\begin_layout Standard
ZSI 2.0 uses the two scripts
\family typewriter
wsdl2py
\family default
and
\family typewriter
wsdl2dispatch
\family default
for code generation and uses different names for the generated files:
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/bin/wsdl2py --file SquareService.wsdl
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/bin/wsdl2dispatch --file SquareService.wsdl
\end_layout
\begin_layout LyX-Code
$ $ ls
\end_layout
\begin_layout LyX-Code
SquareService.wsdl@ SquareService_services_server.py
\end_layout
\begin_layout LyX-Code
SquareService_services.py SquareService_services_types.py
\end_layout
\begin_layout Standard
What do we have now? We have bindings to work with the services in python
and a skeleton for dispatching to the actual worker methods.
What we still need is
\end_layout
\begin_layout Itemize
the main program that runs a (HTTP-) server with a request handler for the
services and
\end_layout
\begin_layout Itemize
the hooks to invoke the worker methods.
\end_layout
\begin_layout Standard
Luckily, ZSI includes the ZSI.ServiceContainer module which implements all
this machinery for us.
\end_layout
\begin_layout Subsubsection
Writing the SquareService web server
\begin_inset LatexCommand \label{sub:SquareService-web-server}
\end_inset
\end_layout
\begin_layout Standard
This is our main program
\family typewriter
mySquareServer.py
\family default
.
It basically imports the necessary ZSI stuff, adds minimal command line
configurability for logging purposes and lets us choose a server HTTP port:
\end_layout
\begin_layout Paragraph
ZSI 2.1
\end_layout
\begin_layout LyX-Code
#!/apps/pydev/hjoukl/bin/python2.4
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# *** ZSI 2.1 ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the ZSI stuff you'd need no matter what
\end_layout
\begin_layout LyX-Code
from ZSI.wstools import logging
\end_layout
\begin_layout LyX-Code
from ZSI.ServiceContainer import AsServer
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
from SquareService_server import SquareService
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Create a Server implementation by inheritance
\end_layout
\begin_layout LyX-Code
class MySquareService(SquareService):
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Make WSDL available for HTTP GET
\end_layout
\begin_layout LyX-Code
_wsdl = "".join(open("SquareService.wsdl").readlines())
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def soap_getSquare(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = SquareService.soap_getSquare(self, ps, **kw)
\end_layout
\begin_layout LyX-Code
response._return = self.getSquare(request._x)
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def getSquare(self, x):
\end_layout
\begin_layout LyX-Code
return x**2
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-l", "--loglevel", help="loglevel (DEBUG, WARN)",
\end_layout
\begin_layout LyX-Code
metavar="LOGLEVEL")
\end_layout
\begin_layout LyX-Code
op.add_option("-p", "--port", help="HTTP port",
\end_layout
\begin_layout LyX-Code
metavar="PORT", default=8080, type="int")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# set the loglevel according to cmd line arg
\end_layout
\begin_layout LyX-Code
if options.loglevel:
\end_layout
\begin_layout LyX-Code
loglevel = eval(options.loglevel, logging.__dict__)
\end_layout
\begin_layout LyX-Code
logger = logging.getLogger("")
\end_layout
\begin_layout LyX-Code
logger.setLevel(loglevel)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Run the server with a given list services
\end_layout
\begin_layout LyX-Code
AsServer(port=options.port, services=[MySquareService(),])
\end_layout
\begin_layout Standard
ZSI 2.0
\end_layout
\begin_layout LyX-Code
#!/apps/pydev/bin/python2.4
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# *** ZSI 2.0 ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the ZSI stuff you'd need no matter what
\end_layout
\begin_layout LyX-Code
from ZSI.wstools import logging
\end_layout
\begin_layout LyX-Code
from ZSI.ServiceContainer import AsServer
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
from SquareService_services_server import SquareService
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Create a Server implementation by inheritance
\end_layout
\begin_layout LyX-Code
class MySquareService(SquareService):
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Make WSDL available for HTTP GET
\end_layout
\begin_layout LyX-Code
_wsdl = "".join(open("SquareService.wsdl").readlines())
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def soap_getSquare(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
response = SquareService.soap_getSquare(self, ps, **kw)
\end_layout
\begin_layout LyX-Code
request = self.request
\end_layout
\begin_layout LyX-Code
response._return = self.getSquare(request._x)
\end_layout
\begin_layout LyX-Code
return response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def getSquare(self, x):
\end_layout
\begin_layout LyX-Code
return x**2
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-l", "--loglevel", help="loglevel (DEBUG, WARN)",
\end_layout
\begin_layout LyX-Code
metavar="LOGLEVEL")
\end_layout
\begin_layout LyX-Code
op.add_option("-p", "--port", help="HTTP port",
\end_layout
\begin_layout LyX-Code
metavar="PORT", default=8080, type="int")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# set the loglevel according to cmd line arg
\end_layout
\begin_layout LyX-Code
if options.loglevel:
\end_layout
\begin_layout LyX-Code
loglevel = eval(options.loglevel, logging.__dict__)
\end_layout
\begin_layout LyX-Code
logger = logging.getLogger("")
\end_layout
\begin_layout LyX-Code
logger.setLevel(loglevel)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Run the server with a given list services
\end_layout
\begin_layout LyX-Code
AsServer(port=options.port, services=[MySquareService(),])
\end_layout
\begin_layout Standard
Apart from the command line parsing stuff which is only usability sugar,
ZSI provides us with everything we need.
All we have to do is
\end_layout
\begin_layout Enumerate
Create a class
\family typewriter
MySquareService
\family default
that inherits from the generated
\family typewriter
SquareService
\family default
class, to hook in the worker code.
This is done with the overridden
\family typewriter
soap_getSquare()
\family default
method, which
\end_layout
\begin_deeper
\begin_layout Itemize
calls its base class method to retrieve the (input and) output data structure
(i.e.
request & response) and
\end_layout
\begin_layout Itemize
invokes the worker code that performs the actual calculation, and populates
the response data structure.
Note that the names in these data structure differ from the names in the
WSDL in that they use leading underscores.
This is done with good reason (e.g., you can not use the name
\begin_inset Quotes eld
\end_inset
return
\begin_inset Quotes erd
\end_inset
for the result message part
\family typewriter
\family default
as a valid Python attribute name) due to XML allowing a far wider range
of element names than the Python language.
You can find details on ZSI naming concepts (
\begin_inset Quotes eld
\end_inset
aname
\begin_inset Quotes erd
\end_inset
) in the ZSI User Guide
\begin_inset LatexCommand \cite{ZSIuserguide2.0}
\end_inset
.
\end_layout
\begin_layout Standard
Hereīs the only difference between the 2.0 & 2.1 implementations, as 2.1 slightly
changes the soap_<...> methods signature and return value.
\end_layout
\begin_layout Standard
We also add a _wsdl attribute that contains the WSDL, to be served when
some client issues a HTTP GET (on
\family typewriter
?wsdl
\family default
), which is actually common behaviour to get the service description (apart
from UDDI).
\begin_inset Foot
status open
\begin_layout Standard
The service invocation itself uses HTTP POST.
You might want to take a look at the ZSI ServiceContainer module and its
\family typewriter
SOAPRequestHandler
\family default
class for more inside information.
\end_layout
\end_inset
ZSI 2.0 wouldnīt need this additional step as its code generation mechanisms
put all the WSDL source into the generated files anyway, but 2.1 does not
(and we consider 2.1 behaviour cleaner).
\end_layout
\end_deeper
\begin_layout Enumerate
Put an instance of our class into the
\family typewriter
services
\family default
argument of the
\family typewriter
AsServer()
\family default
function.
\end_layout
\begin_layout Standard
Thatīs it.
We can now run a full-fledged WS-Server that hosts our SquareService.
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
The dispatch to the appropriate service operation is handled in the
\family typewriter
soapAction
\family default
dictionary in the generated code.
This dictionary maps the action that is requested to the method that gets
invoked.
The ZSI standard request handler takes the HTTP header field soapAction
and propagates its value to this dispatch mechanism.
Thus, everything works out-of-the-box if you use the
\begin_inset Quotes eld
\end_inset
soapAction
\begin_inset Quotes erd
\end_inset
operation-attribute in your WSDL file (and if your service client actually
provides this header field with its request).
Weīll see another way to drive the ZSI request handler in section
\begin_inset LatexCommand \ref{sub:Python-ZSI-FinancialService-server}
\end_inset
.
\end_layout
\begin_layout Itemize
Command-line options allow us to make use of ZSIīs logging capabilities,
to print out more information on ZSI server workings (unfortunately, not
the incoming XML request.
See section
\begin_inset LatexCommand \ref{sub:Logging-the-client-request}
\end_inset
for help on this).
\end_layout
\begin_layout Subsection
A Python ZSI client for the SquareService
\begin_inset LatexCommand \label{sub:ZSI-SquareService-client}
\end_inset
\end_layout
\begin_layout Subsubsection
Using generated client code
\begin_inset LatexCommand \label{sub:ZSI-SquareService-client-generated}
\end_inset
\end_layout
\begin_layout Standard
We implement a client that calls getSquare from the SquareService in
\family typewriter
mySquareClient.py
\family default
as follows:
\end_layout
\begin_layout Paragraph
ZSI 2.1
\end_layout
\begin_layout LyX-Code
#!/apps/pydev/hjoukl/bin/python2.4
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# *** ZSI 2.1 ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
import sys
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated client code
\end_layout
\begin_layout LyX-Code
from SquareService_client import *
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-u", "--url", help="service URL", metavar="URL")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
service = SquareServiceLocator().getSquarePort(url=options.url, tracefile=sys.stdou
t)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
nAccessing service SquareService, method getSquare...'
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
x = float(raw_input("Enter x: "))
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
request = getSquareRequest(x=x)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
response = service.getSquare(request)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print "x**2 =", response._return
\end_layout
\begin_layout Paragraph
ZSI 2.0
\end_layout
\begin_layout LyX-Code
#!/apps/pydev/bin/python2.4
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# *** ZSI 2.0 ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
import sys
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated client code
\end_layout
\begin_layout LyX-Code
from SquareService_services import *
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-u", "--url", help="service URL", metavar="URL")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
service = SquareServiceLocator().getSquarePortType(url=options.url, tracefile=sys.s
tdout)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
nAccessing service SquareService, method getSquare...'
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
x = float(raw_input("Enter x: "))
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
request = getSquareRequest()
\end_layout
\begin_layout LyX-Code
request._x = x
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
response = service.getSquare(request)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print "x**2 =", response._return
\end_layout
\begin_layout Standard
This is pretty straightforward.
Some of the code handles command line stuff which has nothing to do with
web services in the first place.
The things we have to do is to
\end_layout
\begin_layout Enumerate
Import the generated code we need, from either the
\family typewriter
SquareService_client
\family default
(ZSI 2.1) /
\family typewriter
SquareService_services
\family default
(ZSI 2.0) module,
\end_layout
\begin_layout Enumerate
Create a
\family typewriter
SquareServiceLocator
\family default
,
\end_layout
\begin_layout Enumerate
Invoke its
\family typewriter
getSquarePort()
\family default
(ZSI 2.1) /
\family typewriter
getSquarePortType()
\family default
(ZSI 2.0)method to retrive the square service binding,
\end_layout
\begin_layout Enumerate
populate the request data structure
\end_layout
\begin_deeper
\begin_layout Itemize
using keyword-arguments (ZSI 2.1)
\end_layout
\begin_layout Itemize
by explicitly setting request instance attributes (ZSI 2.0)
\end_layout
\end_deeper
\begin_layout Enumerate
call the service bindingīs
\family typewriter
getSquare()
\family default
method with the request data as input parameter and
\end_layout
\begin_layout Enumerate
read the result data structure.
\end_layout
\begin_layout Standard
Again, the naming concepts of ZSI as noted in section
\begin_inset LatexCommand \ref{sub:SquareService-web-server}
\end_inset
apply.
\end_layout
\begin_layout Standard
This is a sample session of our new client:
\end_layout
\begin_layout LyX-Code
$ ./mySquareClient.py -u "http://adevp02:8080/SquareService"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Accessing service SquareService, method getSquare...
\end_layout
\begin_layout LyX-Code
Enter x: 3
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 10:16:23 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
3.000000
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 10:16:23 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Wed, 02 Jan 2008 09:16:23 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 497
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
9.000000
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
x**2 = 9.0
\end_layout
\begin_layout LyX-Code
Enter x:
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
We use an explicit URL to access the service, as our WSDL contains only
the
\begin_inset Quotes eld
\end_inset
symbolic
\begin_inset Quotes erd
\end_inset
server name not known by our siteīs naming services.
In a real-world application, you'd not even need to do so, as the generated
client code knows the service URL as given in the WSDL.
\end_layout
\begin_layout Itemize
The client does not issue any HTTP GET for service access, because all the
necessary data structures have been pre-generated from the WSDL service
description.
\end_layout
\begin_layout Subsubsection
Using ServiceProxy
\begin_inset LatexCommand \label{sub:SquareService-ZSI-ServiceProxy}
\end_inset
\end_layout
\begin_layout Standard
ZSI also offers an option to implement a client without using the pre-generated
stub code: Everything can be accessed through the
\family typewriter
ServiceProxy
\family default
object that gets all the necessary information from the WSDL, on the fly.
This is an example of a ServiceProxy-client (the very same code works with
both ZSI 2.1 & 2.0):
\end_layout
\begin_layout LyX-Code
#!/apps/pydev/bin/python2.4
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
import sys
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.ServiceProxy import ServiceProxy
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-u", "--url", help="service URL (mandatory)", metavar="URL")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
if not options.url:
\end_layout
\begin_layout LyX-Code
op.print_help()
\end_layout
\begin_layout LyX-Code
sys.exit(1)
\end_layout
\begin_layout LyX-Code
else:
\end_layout
\begin_layout LyX-Code
# "Canonicalize" WSDL URL
\end_layout
\begin_layout LyX-Code
options.url = options.url.replace("?WSDL", "?wsdl")
\end_layout
\begin_layout LyX-Code
if not options.url.endswith("?wsdl"):
\end_layout
\begin_layout LyX-Code
options.url += "?wsdl"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
service = ServiceProxy(wsdl=options.url, tracefile=sys.stdout)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
nAccessing service SquareService, method getSquare...'
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
x = float(raw_input("Enter x: "))
\end_layout
\begin_layout LyX-Code
resultDict = service.getSquare(x=x)
\end_layout
\begin_layout LyX-Code
print "x**2 =", resultDict['return']
\end_layout
\begin_layout Standard
Basically, all you need to do is to create a
\family typewriter
ServiceProxy
\family default
instance with the information where to get the WSDL.
You can then simply access its getSquare method; only make sure you give
its argument as a keyword argument.
\end_layout
\begin_layout Standard
This is the output of an example ServiceProxy-client run:
\end_layout
\begin_layout LyX-Code
$ ./mySquareSPclient.py -u "http://adevp02:8080/SquareService?wsdl"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Accessing service SquareService, method getSquare...
\end_layout
\begin_layout LyX-Code
Enter x: 4
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 10:30:17 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
4.000000
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 10:30:18 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Wed, 02 Jan 2008 09:30:17 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 498
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
16.000000
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
x**2 = 16.0
\end_layout
\begin_layout LyX-Code
Enter x:
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
When running the ServiceProxy-notion of a ZSI WS-client, take a good look
at your ZSI server.
You will then see that the ServiceProxy client issues an HTTP GET first,
to retrieve the WSDL information and create the necessary code and data
structures.
\end_layout
\begin_layout Itemize
To tell the whole truth, ServiceProxy basically does much the same code
generation like
\family typewriter
wsdl2py
\family default
under the hood, and creates a cache dir
\family typewriter
~/.zsi_service_proxy_dir
\family default
(ZSI 2.1) resp.
\family typewriter
./.service_proxy_dir
\family default
(ZSI 2.0) for the generated files.
This cache dir is then appended to
\family typewriter
sys.path
\family default
for module import.
\begin_inset Foot
status open
\begin_layout Standard
The attentive reader might observe that this may have an implication on
ServiceProxy-client behaviour depending on where you run it.
As the local directory is the 1st
\family typewriter
sys.path
\family default
entry per default, existing pre-generated (from
\family typewriter
wsdl2py
\family default
) code might beat the cache-dir modules in import order - depending on module
naming.
\end_layout
\end_inset
\end_layout
\begin_layout Subsection
A gSOAP C++ client for the SquareService
\end_layout
\begin_layout Subsubsection
Generation from WSDL
\end_layout
\begin_layout Standard
With our SquareService server running, we can generate the client stubs:
\end_layout
\begin_layout Enumerate
First, gSOAP needs to create a header file for the service using the
\family typewriter
wsdl2h
\family default
generator:
\end_layout
\begin_deeper
\begin_layout LyX-Code
/apps/pydev/bin/wsdl2h -o squareService.h
\end_layout
\begin_layout LyX-Code
http://adevp02:8080/SquareService?wsdl
\end_layout
\begin_layout Standard
Just specify the name for the header file and the URL where the WSDL can
be received with a HTTP GET request.
The
\family typewriter
squareService.h
\family default
header will be created:
\end_layout
\begin_layout LyX-Code
/apps/pydev/bin/wsdl2h -o squareService.h http://adevp02:8080/SquareService?wsdl
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
** The gSOAP WSDL parser for C and C++ 1.2.9l
\end_layout
\begin_layout LyX-Code
** Copyright (C) 2000-2007 Robert van Engelen, Genivia Inc.
\end_layout
\begin_layout LyX-Code
** All Rights Reserved.
This product is provided "as is", without any warranty.
\end_layout
\begin_layout LyX-Code
** The gSOAP WSDL parser is released under one of the following two licenses:
\end_layout
\begin_layout LyX-Code
** GPL or the commercial license by Genivia Inc.
Use option -l for more info.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Saving squareService.h
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Cannot open file 'typemap.dat'
\end_layout
\begin_layout LyX-Code
Problem reading type map file typemap.dat.
\end_layout
\begin_layout LyX-Code
Using internal type definitions for C++ instead.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Connecting to 'http://adevp02:8080/SquareService?wsdl' to retrieve WSDL/XSD...
connected, receiving...
\end_layout
\begin_layout LyX-Code
Warning: part 'return' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'x' uses literal style and should refer to an element rather
than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'x' uses literal style and should refer to an element rather
than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'x' uses literal style and should refer to an element rather
than a type
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
To complete the process, compile with:
\end_layout
\begin_layout LyX-Code
soapcpp2 squareService.h
\end_layout
\begin_layout Standard
Note that gSOAP tells us about what it thinks might cause problems in our
WSDL; we ignore that for this example.
\end_layout
\end_deeper
\begin_layout Enumerate
Next we let gSOAP create the stub code for us, using the newly-created header:
\end_layout
\begin_deeper
\begin_layout LyX-Code
$ /apps/pydev/bin/soapcpp2 -I /data/pydev/DOWNLOADS/WebServices/C++/gsoap-2.7/soa
pcpp2/import squareService.h
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
** The gSOAP Stub and Skeleton Compiler for C and C++ 2.7.9l
\end_layout
\begin_layout LyX-Code
** Copyright (C) 2000-2007, Robert van Engelen, Genivia Inc.
\end_layout
\begin_layout LyX-Code
** All Rights Reserved.
This product is provided "as is", without any warranty.
\end_layout
\begin_layout LyX-Code
** The gSOAP compiler is released under one of the following three licenses:
\end_layout
\begin_layout LyX-Code
** GPL, the gSOAP public license, or the commercial license by Genivia
Inc.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Saving soapStub.h
\end_layout
\begin_layout LyX-Code
Saving soapH.h
\end_layout
\begin_layout LyX-Code
Saving soapC.cpp
\end_layout
\begin_layout LyX-Code
Saving soapClient.cpp
\end_layout
\begin_layout LyX-Code
Saving soapClientLib.cpp
\end_layout
\begin_layout LyX-Code
Saving soapServer.cpp
\end_layout
\begin_layout LyX-Code
Saving soapServerLib.cpp
\end_layout
\begin_layout LyX-Code
Using ns1 service name: SquareBinding
\end_layout
\begin_layout LyX-Code
Using ns1 service style: document
\end_layout
\begin_layout LyX-Code
Using ns1 service encoding: literal
\end_layout
\begin_layout LyX-Code
Using ns1 service location: http://adevp02:8080/SquareService
\end_layout
\begin_layout LyX-Code
Using ns1 schema namespace: http://services.zsiserver.net/SquareService
\end_layout
\begin_layout LyX-Code
Saving soapSquareBindingProxy.h client proxy
\end_layout
\begin_layout LyX-Code
Saving soapSquareBindingObject.h server object
\end_layout
\begin_layout LyX-Code
Saving SquareBinding.getSquare.req.xml sample SOAP/XML request
\end_layout
\begin_layout LyX-Code
Saving SquareBinding.getSquare.res.xml sample SOAP/XML response
\end_layout
\begin_layout LyX-Code
Saving SquareBinding.nsmap namespace mapping table
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Compilation successful
\end_layout
\begin_layout Standard
We must explicitly give the
\family typewriter
gSOAP/soapcpp2
\family default
directory as include directory.
This is not being installed with the gSOAP installation (in the
\begin_inset Quotes eld
\end_inset
make install
\begin_inset Quotes erd
\end_inset
step) but resides in the path where you extracted the gSOAP tarball.
It contains some special header files gSOAP does not install on your system.
\end_layout
\begin_layout Standard
You might have noticed that
\family typewriter
soapcpp2
\family default
says it is using service style
\begin_inset Quotes eld
\end_inset
document
\begin_inset Quotes erd
\end_inset
as opposed to whatīs defined in the WSDL (
\begin_inset Quotes eld
\end_inset
rpc
\begin_inset Quotes erd
\end_inset
); this seems to be a cosmetic issue only and does not affect the usability
of the generated code.
\end_layout
\begin_layout Standard
The above command produces the following client stubs (server skeleton code
also by the way, but we will not use it here):
\end_layout
\begin_layout LyX-Code
$ ls -l
\end_layout
\begin_layout LyX-Code
total 105
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 444 Jan 2 10:48 SquareBinding.getSquare.req.xml
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 470 Jan 2 10:48 SquareBinding.getSquare.res.xml
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 556 Jan 2 10:48 SquareBinding.nsmap
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 57364 Jan 2 10:48 soapC.cpp
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 2326 Jan 2 10:48 soapClient.cpp
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 464 Jan 2 10:48 soapClientLib.cpp
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 15694 Jan 2 10:48 soapH.h
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 3152 Jan 2 10:48 soapServer.cpp
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 464 Jan 2 10:48 soapServerLib.cpp
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 2470 Jan 2 10:48 soapSquareBindingObject.h
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 1826 Jan 2 10:48 soapSquareBindingProxy.h
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 6915 Jan 2 10:48 soapStub.h
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 6662 Jan 2 10:38 squareService.h
\end_layout
\end_deeper
\begin_layout Standard
Whatīs left now is to implement the client program and make use of the generated
code.
\end_layout
\begin_layout Subsubsection
Client implementation
\begin_inset LatexCommand \label{sub:gsoap-square-client}
\end_inset
\end_layout
\begin_layout Standard
This is a sample client to access the SquareService:
\end_layout
\begin_layout LyX-Code
$ cat myCSquareClient.cpp
\end_layout
\begin_layout LyX-Code
#include "soapH.h"
\end_layout
\begin_layout LyX-Code
#include "SquareBinding.nsmap"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
#include
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
int main(void)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
struct soap soap;
\end_layout
\begin_layout LyX-Code
double x = 0;
\end_layout
\begin_layout LyX-Code
struct ns1__getSquareResponse response;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
soap_init(&soap);
\end_layout
\begin_layout LyX-Code
while (1) {
\end_layout
\begin_layout LyX-Code
std::cout << "Enter x value: ";
\end_layout
\begin_layout LyX-Code
std::cin >> x;
\end_layout
\begin_layout LyX-Code
if (soap_call_ns1__getSquare(&soap, NULL, NULL, x, response) ==
SOAP_OK) {
\end_layout
\begin_layout LyX-Code
std::cout << "Result: " << response.return_ << std::endl;
\end_layout
\begin_layout LyX-Code
} else {
\end_layout
\begin_layout LyX-Code
soap_print_fault(&soap, stderr);
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
soap_destroy(&soap);
\end_layout
\begin_layout LyX-Code
soap_end(&soap);
\end_layout
\begin_layout LyX-Code
soap_done(&soap);
\end_layout
\begin_layout LyX-Code
return 0;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
Note gSOAPīs renaming of the WSDL result message part
\family typewriter
\family default
to
\family typewriter
return_
\family default
in the response data structure
\family typewriter
struct ns1__getSquareResponse
\family default
to cater for conflicts with reserved C/C++ words, similar to the ZSI
\begin_inset Quotes eld
\end_inset
aname
\begin_inset Quotes erd
\end_inset
concept
\end_layout
\begin_layout Itemize
There are also other ways to invoke this service with the gSOAP mechanisms,
namely the
\family typewriter
SquareBinding
\family default
class defined in
\family typewriter
soapSquareBindingProxy.h
\family default
, which would take care of the initialization & destruction activities needed
in the above client code.
We will use this (better) approach in the next examples.
\end_layout
\begin_layout Subsubsection
gSOAP client compilation
\end_layout
\begin_layout Paragraph
gcc 2.95.2
\end_layout
\begin_layout LyX-Code
$ g++ -o myCSquareClient -R/apps/prod/lib -I/apps/pydev/include
\end_layout
\begin_layout LyX-Code
-L/apps/pydev/lib soapC.cpp soapClient.cpp myCSquareClient.cpp -lgsoap++ -lsocket
\end_layout
\begin_layout Paragraph
gcc 3.4.4
\end_layout
\begin_layout Standard
Note: Compiling with gcc 3.4.4, the nsl library had to be added to the linked
libraries:
\end_layout
\begin_layout LyX-Code
/apps/local/gcc/3.4.4/bin/g++ -o myCSquareClient -R /apps/prod/gcc/3.4.4/lib
-I/apps/pydev/gcc/3.4.4/include -L/apps/pydev/gcc/3.4.4/lib soapC.cpp soapClient.cpp
myCSquareClient.cpp -lgsoap++ -lsocket -lnsl
\end_layout
\begin_layout Standard
You can then run this simple C++ Web Service client:
\end_layout
\begin_layout LyX-Code
$ ./myCSquareClient
\end_layout
\begin_layout LyX-Code
Enter x value: 3
\end_layout
\begin_layout LyX-Code
Result: 9
\end_layout
\begin_layout LyX-Code
Enter x value: ^C
\end_layout
\begin_layout Section
Structured datatypes: The rpc/literal DateService
\end_layout
\begin_layout Standard
Letīs move on to a more elaborate service, elaborate in the sense of using
structured datatypes now (not that the service example itself was particularly
ingenious).
Anyway, we will now implement the DateService service that exposes two
methods:
\end_layout
\begin_layout Itemize
getCurrentDate() takes a string argument and returns
the current date as a datetime structure
\end_layout
\begin_layout Itemize
getDate(, ) takes an integer offset
and a date structure as arguments and returns the given date plus the offset
(in days) as a date structure
\end_layout
\begin_layout Subsection
The DateService WSDL
\begin_inset LatexCommand \label{sub:The-DateService-WSDL}
\end_inset
\end_layout
\begin_layout Standard
The DateService is described in
\family typewriter
DateService.wsdl
\family default
:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Date Web Service
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
Again, rpc/literal has been chosen.
\end_layout
\begin_layout Itemize
A ComplexType
\begin_inset Quotes eld
\end_inset
Date
\begin_inset Quotes erd
\end_inset
is defined in the section.
This type is being used as a return type (getCurrentDate, getDate) and
as a method argument type (getDate).
\end_layout
\begin_layout Subsection
A Python ZSI DateService server
\begin_inset LatexCommand \label{sub:A-Python-ZSI-DateService-server}
\end_inset
\end_layout
\begin_layout Standard
The tasks at hand are the same as for the SquareService example.
\end_layout
\begin_layout Subsubsection
Code generation from WSDL
\end_layout
\begin_layout Paragraph
ZSI 2.1
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/hjoukl/bin/wsdl2py DateService.wsdl
\end_layout
\begin_layout LyX-Code
$ ls -l
\end_layout
\begin_layout LyX-Code
total 15
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 3180 Jan 2 14:12 DateService.wsdl
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 3935 Jan 2 14:12 DateService_client.py
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 3209 Jan 2 14:12 DateService_server.py
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 2896 Jan 2 14:12 DateService_types.py
\end_layout
\begin_layout Paragraph
ZSI 2.0
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/bin/wsdl2py -f DateService.wsdl
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/bin/wsdl2dispatch -f DateService.wsdl
\end_layout
\begin_layout LyX-Code
$ ls -l
\end_layout
\begin_layout LyX-Code
total 34
\end_layout
\begin_layout LyX-Code
lrwxrwxrwx 1 lb54320 intern 28 Jan 3 17:45 DateService.wsdl -> ../2.1alpha/DateS
ervice.wsdl
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 3525 Jan 7 09:56 DateService_services.py
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 4428 Jan 7 09:56 DateService_services_server.py
\end_layout
\begin_layout LyX-Code
-rw-r--r-- 1 lb54320 intern 2818 Jan 7 09:56 DateService_services_types.py
\end_layout
\begin_layout Subsubsection
The DateService server-side implementation
\begin_inset LatexCommand \label{sub:The-DateService-server-side-impl}
\end_inset
\end_layout
\begin_layout Standard
The server implementation needs exactly the same steps as seen in section
\begin_inset LatexCommand \ref{sub:SquareService-web-server}
\end_inset
, with the difference of putting a DateService instance into the ServiceContaine
r now.
We create a server
\family typewriter
myDateServer.py
\family default
like this:
\end_layout
\begin_layout Paragraph
ZSI 2.1
\end_layout
\begin_layout LyX-Code
#!/apps/pydev/hjoukl/bin/python2.4
\end_layout
\begin_layout LyX-Code
import time
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the ZSI stuff you'd need no matter what
\end_layout
\begin_layout LyX-Code
from ZSI.wstools import logging
\end_layout
\begin_layout LyX-Code
from ZSI.ServiceContainer import AsServer
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
from DateService_server import *
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Create a Server implementation by inheritance
\end_layout
\begin_layout LyX-Code
class MyDateService(simple_Date_Service):
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Make WSDL available for HTTP GET
\end_layout
\begin_layout LyX-Code
_wsdl = "".join(open("DateService.wsdl").readlines())
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def soap_getCurrentDate(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = simple_Date_Service.soap_getCurrentDate(self,
ps, **kw)
\end_layout
\begin_layout LyX-Code
print "Client says:", request._input
\end_layout
\begin_layout LyX-Code
dt = time.localtime(time.time())
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Use a structurally equivalent (to the WSDL complex type structure)
\end_layout
\begin_layout LyX-Code
# python class object
\end_layout
\begin_layout LyX-Code
class today:
\end_layout
\begin_layout LyX-Code
_year = dt[0]
\end_layout
\begin_layout LyX-Code
_month = dt[1]
\end_layout
\begin_layout LyX-Code
_day = dt[2]
\end_layout
\begin_layout LyX-Code
_hour = dt[3]
\end_layout
\begin_layout LyX-Code
_minute = dt[4]
\end_layout
\begin_layout LyX-Code
_second = dt[5]
\end_layout
\begin_layout LyX-Code
_weekday = dt[6]
\end_layout
\begin_layout LyX-Code
_dayOfYear = dt[7]
\end_layout
\begin_layout LyX-Code
_dst = dt[8]
\end_layout
\begin_layout LyX-Code
response._today = today
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def soap_getDate(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = simple_Date_Service.soap_getDate(self, ps, **kw)
\end_layout
\begin_layout LyX-Code
date = request._someday
\end_layout
\begin_layout LyX-Code
offset = request._offset
\end_layout
\begin_layout LyX-Code
if not offset:
\end_layout
\begin_layout LyX-Code
offset = 0
\end_layout
\begin_layout LyX-Code
if not date:
\end_layout
\begin_layout LyX-Code
raise RuntimeError("missing input data")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# actual worker code, add give offset to given input date
\end_layout
\begin_layout LyX-Code
sec = 3600 * 24 # seconds/hour * 24h
\end_layout
\begin_layout LyX-Code
providedDate_tuple = (date._year, date._month, date._day,
\end_layout
\begin_layout LyX-Code
date._hour, date._minute, date._second,
\end_layout
\begin_layout LyX-Code
date._weekday, date._dayOfYear, date._dst)
\end_layout
\begin_layout LyX-Code
providedDate_sec = time.mktime(providedDate_tuple)
\end_layout
\begin_layout LyX-Code
offset_sec = sec * offset
\end_layout
\begin_layout LyX-Code
newDate_sec = providedDate_sec + offset_sec
\end_layout
\begin_layout LyX-Code
newDate_tuple = time.localtime(newDate_sec)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
response = getDateResponse()
\end_layout
\begin_layout LyX-Code
# Use a structurally equivalent (to the WSDL complex type structure)
\end_layout
\begin_layout LyX-Code
# python class object
\end_layout
\begin_layout LyX-Code
class day:
\end_layout
\begin_layout LyX-Code
_year = newDate_tuple[0]
\end_layout
\begin_layout LyX-Code
_month = newDate_tuple[1]
\end_layout
\begin_layout LyX-Code
_day = newDate_tuple[2]
\end_layout
\begin_layout LyX-Code
_hour = newDate_tuple[3]
\end_layout
\begin_layout LyX-Code
_minute = newDate_tuple[4]
\end_layout
\begin_layout LyX-Code
_second = newDate_tuple[5]
\end_layout
\begin_layout LyX-Code
_weekday = newDate_tuple[6]
\end_layout
\begin_layout LyX-Code
_dayOfYear = newDate_tuple[7]
\end_layout
\begin_layout LyX-Code
_dst = newDate_tuple[8]
\end_layout
\begin_layout LyX-Code
response._day = day
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-l", "--loglevel", help="loglevel (DEBUG, WARN)",
\end_layout
\begin_layout LyX-Code
metavar="LOGLEVEL")
\end_layout
\begin_layout LyX-Code
op.add_option("-p", "--port", help="HTTP port",
\end_layout
\begin_layout LyX-Code
metavar="PORT", default=8080, type="int")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# set the loglevel according to cmd line arg
\end_layout
\begin_layout LyX-Code
if options.loglevel:
\end_layout
\begin_layout LyX-Code
loglevel = eval(options.loglevel, logging.__dict__)
\end_layout
\begin_layout LyX-Code
logger = logging.getLogger("")
\end_layout
\begin_layout LyX-Code
logger.setLevel(loglevel)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Run the server with a given list services
\end_layout
\begin_layout LyX-Code
AsServer(port=options.port, services=[MyDateService(),])
\end_layout
\begin_layout Standard
As in the previous example, the actual implementation has been hooked into
the server skeleton, by inheriting from the generated service class.
\end_layout
\begin_layout Standard
If you take a closer look at the two method implementations, you will notice
that the data structures used for the returned date are just (nested) python
classes.
ZSI handles the serialization of that class into the actual SOAP message
for us.
\begin_inset Foot
status open
\begin_layout Standard
The python object must be
\begin_inset Quotes eld
\end_inset
structurally equivalent
\begin_inset Quotes erd
\end_inset
to the XML datatype that is defined in the WSDL and that constitutes ZSIīs
typecodes.
\end_layout
\end_inset
In
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
This time, we did not strictly separate the worker code from the
\family typewriter
soap_<...>
\family default
methods.
\end_layout
\begin_layout Itemize
The handling of complex types can be made more convenient by using the --complex
Type option of wsdl2py.
This is the recommended way to go and weīll see how it works in section
\begin_inset LatexCommand \ref{sec:FinancialService-document/literal-service}
\end_inset
, but it requires metaclass magic and thus new-style classes to work, so
you will require Python >= 2.2.
\end_layout
\begin_layout Paragraph
ZSI 2.0
\end_layout
\begin_layout Standard
Remembering the SquareService example, the ZSI 2.1 and 2.0 server code differed
only in the return value and method signature of the
\family typewriter
soap_<...>()
\family default
-method implementation-wise.
We can exploit this to reuse the code written for ZSI 2.1, by help of an
adapter module that provides some facilities to auto-wrap these methods.
Using this adapter module, we can now implement a working ZSI 2.0 server
like this:
\end_layout
\begin_layout LyX-Code
import time
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the ZSI stuff you'd need no matter what
\end_layout
\begin_layout LyX-Code
from ZSI.wstools import logging
\end_layout
\begin_layout LyX-Code
from ZSI.ServiceContainer import AsServer
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
# 2.1alpha
\end_layout
\begin_layout LyX-Code
from DateService_server import simple_Date_Service
\end_layout
\begin_layout LyX-Code
# Dummy implementation
\end_layout
\begin_layout LyX-Code
def adapt(method):
\end_layout
\begin_layout LyX-Code
return method
\end_layout
\begin_layout LyX-Code
except ImportError, e:
\end_layout
\begin_layout LyX-Code
# 2.0final
\end_layout
\begin_layout LyX-Code
from DateService_services_server import simple_Date_Service
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from service_adaptor import ServiceAdaptor21
\end_layout
\begin_layout LyX-Code
adapt = ServiceAdaptor21.adapt
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Wrap generated 2.0 class to 2.1 soap_ method behaviour
\end_layout
\begin_layout LyX-Code
simple_Date_Service = ServiceAdaptor21(simple_Date_Service)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Create a Server implementation by inheritance
\end_layout
\begin_layout LyX-Code
# 2.1alpha implementation
\end_layout
\begin_layout LyX-Code
class MyDateService(simple_Date_Service):
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Make WSDL available for HTTP GET
\end_layout
\begin_layout LyX-Code
_wsdl = "".join(open("DateService.wsdl").readlines())
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@adapt
\end_layout
\begin_layout LyX-Code
def soap_getCurrentDate(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = simple_Date_Service.soap_getCurrentDate(self,
ps, **kw)
\end_layout
\begin_layout LyX-Code
print "Client says:", request._input
\end_layout
\begin_layout LyX-Code
dt = time.localtime(time.time())
\end_layout
\begin_layout LyX-Code
# Use a structurally equivalent (to the WSDL complex type structure)
\end_layout
\begin_layout LyX-Code
# python class object
\end_layout
\begin_layout LyX-Code
class today:
\end_layout
\begin_layout LyX-Code
_year = dt[0]
\end_layout
\begin_layout LyX-Code
_month = dt[1]
\end_layout
\begin_layout LyX-Code
_day = dt[2]
\end_layout
\begin_layout LyX-Code
_hour = dt[3]
\end_layout
\begin_layout LyX-Code
_minute = dt[4]
\end_layout
\begin_layout LyX-Code
_second = dt[5]
\end_layout
\begin_layout LyX-Code
_weekday = dt[6]
\end_layout
\begin_layout LyX-Code
_dayOfYear = dt[7]
\end_layout
\begin_layout LyX-Code
_dst = dt[8]
\end_layout
\begin_layout LyX-Code
response._today = today
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@adapt
\end_layout
\begin_layout LyX-Code
def soap_getDate(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = simple_Date_Service.soap_getDate(self, ps, **kw)
\end_layout
\begin_layout LyX-Code
date = request._someday
\end_layout
\begin_layout LyX-Code
offset = request._offset
\end_layout
\begin_layout LyX-Code
if not offset:
\end_layout
\begin_layout LyX-Code
offset = 0
\end_layout
\begin_layout LyX-Code
if not date:
\end_layout
\begin_layout LyX-Code
raise RuntimeError("missing input data")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# actual worker code, add give offset to given input date
\end_layout
\begin_layout LyX-Code
sec = 3600 * 24 # seconds/hour * 24h
\end_layout
\begin_layout LyX-Code
providedDate_tuple = (date._year, date._month, date._day,
\end_layout
\begin_layout LyX-Code
date._hour, date._minute, date._second,
\end_layout
\begin_layout LyX-Code
date._weekday, date._dayOfYear, date._dst)
\end_layout
\begin_layout LyX-Code
providedDate_sec = time.mktime(providedDate_tuple)
\end_layout
\begin_layout LyX-Code
offset_sec = sec * offset
\end_layout
\begin_layout LyX-Code
newDate_sec = providedDate_sec + offset_sec
\end_layout
\begin_layout LyX-Code
newDate_tuple = time.localtime(newDate_sec)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Use a structurally equivalent (to the WSDL complex type structure)
\end_layout
\begin_layout LyX-Code
# python class object
\end_layout
\begin_layout LyX-Code
class day:
\end_layout
\begin_layout LyX-Code
_year = newDate_tuple[0]
\end_layout
\begin_layout LyX-Code
_month = newDate_tuple[1]
\end_layout
\begin_layout LyX-Code
_day = newDate_tuple[2]
\end_layout
\begin_layout LyX-Code
_hour = newDate_tuple[3]
\end_layout
\begin_layout LyX-Code
_minute = newDate_tuple[4]
\end_layout
\begin_layout LyX-Code
_second = newDate_tuple[5]
\end_layout
\begin_layout LyX-Code
_weekday = newDate_tuple[6]
\end_layout
\begin_layout LyX-Code
_dayOfYear = newDate_tuple[7]
\end_layout
\begin_layout LyX-Code
_dst = newDate_tuple[8]
\end_layout
\begin_layout LyX-Code
response._day = day
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-l", "--loglevel", help="loglevel (DEBUG, WARN)",
\end_layout
\begin_layout LyX-Code
metavar="LOGLEVEL")
\end_layout
\begin_layout LyX-Code
op.add_option("-p", "--port", help="HTTP port",
\end_layout
\begin_layout LyX-Code
metavar="PORT", default=8080, type="int")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# set the loglevel according to cmd line arg
\end_layout
\begin_layout LyX-Code
if options.loglevel:
\end_layout
\begin_layout LyX-Code
loglevel = eval(options.loglevel, logging.__dict__)
\end_layout
\begin_layout LyX-Code
logger = logging.getLogger("")
\end_layout
\begin_layout LyX-Code
logger.setLevel(loglevel)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Run the server with a given list services
\end_layout
\begin_layout LyX-Code
AsServer(port=options.port, services=[MyDateService(),])
\end_layout
\begin_layout Standard
Now, this code will actually work with
\emph on
both
\emph default
ZSI 2.0 and 2.1, as it provides a ZSI-2.1-dummy for the
\family typewriter
@adapt
\family default
-decoration.
However, as we have seen in the SquareService example, it is very feasible
to manually make the changes needed for the different library versions,
without depending on the
\begin_inset Quotes eld
\end_inset
magic
\begin_inset Quotes erd
\end_inset
\family typewriter
service_adaptor
\family default
provides.
\end_layout
\begin_layout Standard
Hereīs the implementation of the
\family typewriter
service_adaptor
\family default
module (you can skip this section if you're running 2.1 anyway or if you
are not interested in the inner workings of this
\begin_inset Foot
status open
\begin_layout Standard
You might want to look at the Python cookbook recipee
\begin_inset ERT
status open
\begin_layout Standard
\backslash
htmladdnormallink{"Method enhancement" by Ken Seehof (http://aspn.activestate.com/
ASPN/Cookbook/Python/Recipe/81982)}{http://www.python.org/dev/peps/pep-0333/}
\end_layout
\end_inset
for background
\end_layout
\end_inset
):
\end_layout
\begin_layout LyX-Code
$ cat service_adaptor.py
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
import types
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Based on "Method enhancement" Python cookbook recipee by Ken Seehof
\end_layout
\begin_layout LyX-Code
# (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81982)}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
class ServiceAdaptor21(object):
\end_layout
\begin_layout LyX-Code
"""Helper class factory to provide ZSI 2.1 code compatibility.
\end_layout
\begin_layout LyX-Code
Takes a ZSI 2.0 service class and returns a class derived from this service
\end_layout
\begin_layout LyX-Code
class, that uses the ZSI 2.1 soap_method signature + return value
\end_layout
\begin_layout LyX-Code
conventions.
\end_layout
\begin_layout LyX-Code
Can be used to make a ZSI 2.1-based service class implementation work
with
\end_layout
\begin_layout LyX-Code
the ZSI 2.0 library.
\end_layout
\begin_layout LyX-Code
Parameters:
\end_layout
\begin_layout LyX-Code
ZSI20ServiceClass: Service class, as imported from ZSI 2.0-generated
\end_layout
\begin_layout LyX-Code
module code
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@staticmethod
\end_layout
\begin_layout LyX-Code
def enhanced_method(method, replacement):
\end_layout
\begin_layout LyX-Code
"""Return a callable wrapped with a replacement callable"""
\end_layout
\begin_layout LyX-Code
def _f(*args, **kwargs):
\end_layout
\begin_layout LyX-Code
return replacement(method, *args, **kwargs)
\end_layout
\begin_layout LyX-Code
_f.__name__ = method.__name__
\end_layout
\begin_layout LyX-Code
return _f
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@staticmethod
\end_layout
\begin_layout LyX-Code
def _adaptTo21_soap_(orig_method, self, ps, **kwargs):
\end_layout
\begin_layout LyX-Code
"""Wrapper method implementation, ZSI 2.0 soap_ method to ZSI 2.1
soap_
\end_layout
\begin_layout LyX-Code
method interface
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
response = orig_method(self, ps)
\end_layout
\begin_layout LyX-Code
return self.request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@staticmethod
\end_layout
\begin_layout LyX-Code
def _adaptTo20_soap_(orig_method, self, ps, **kwargs):
\end_layout
\begin_layout LyX-Code
"""Wrapper method implementation, ZSI 2.1 soap_ method to ZSI 2.0
soap_
\end_layout
\begin_layout LyX-Code
method interface
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
request, response = orig_method(self, ps)
\end_layout
\begin_layout LyX-Code
return response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@staticmethod
\end_layout
\begin_layout LyX-Code
def adapt(method):
\end_layout
\begin_layout LyX-Code
"""Method decorator to decorate ZSI 2.1-conforming soap_ method to
ZSI
\end_layout
\begin_layout LyX-Code
2.0 method interface
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
return ServiceAdaptor21.enhanced_method(
\end_layout
\begin_layout LyX-Code
method, ServiceAdaptor21._adaptTo20_soap_)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def __new__(cls, ZSI20ServiceClass):
\end_layout
\begin_layout LyX-Code
derived_dict = {}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
for methodName in ZSI20ServiceClass.__dict__:
\end_layout
\begin_layout LyX-Code
if methodName.startswith("soap_"):
\end_layout
\begin_layout LyX-Code
method = ZSI20ServiceClass.__dict__[methodName]
\end_layout
\begin_layout LyX-Code
derived_dict[methodName] = cls.enhanced_method(
\end_layout
\begin_layout LyX-Code
method, cls._adaptTo21_soap_)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
return types.ClassType(ZSI20ServiceClass.__name__,
\end_layout
\begin_layout LyX-Code
bases=(ZSI20ServiceClass,), dict=derived_dict)
\end_layout
\begin_layout Subsection
A Python ZSI client for the DateService
\begin_inset LatexCommand \label{sub:A-Python-ZSI-client-DateService}
\end_inset
\end_layout
\begin_layout Subsubsection
Using generated type mapping
\end_layout
\begin_layout Standard
As seen before, we use the ZSI-generated code to write a client that calls
both service methods:
\end_layout
\begin_layout Paragraph
ZSI 2.1
\end_layout
\begin_layout LyX-Code
#! /apps/pydev/hjoukl/bin/python2.4
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# *** ZSI 2.1 ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
import sys, time
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from DateService_client import *
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def main():
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-u", "--url", help="service URL", metavar="URL")
\end_layout
\begin_layout LyX-Code
op.add_option("-i", "--input", type="string",
\end_layout
\begin_layout LyX-Code
help="input string for getCurrentDate WS method",
\end_layout
\begin_layout LyX-Code
metavar="INPUT")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
loc = simple_Date_ServiceLocator()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
service = loc.getDateService_Port(url=options.url, tracefile=sys.stdout)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
offset = raw_input("Enter offset as int [0]: ")
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
offset = int(offset)
\end_layout
\begin_layout LyX-Code
except ValueError:
\end_layout
\begin_layout LyX-Code
offset = 0
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
currentRequest = getCurrentDateRequest()
\end_layout
\begin_layout LyX-Code
currentRequest._input = options.input
\end_layout
\begin_layout LyX-Code
currentResponse = service.getCurrentDate(currentRequest)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# We use the current date as input to getDate
\end_layout
\begin_layout LyX-Code
dateRequest = getDateRequest(offset=offset, someday=currentResponse._toda
y)
\end_layout
\begin_layout LyX-Code
response = service.getDate(dateRequest)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
n
\backslash
nRESULT'
\end_layout
\begin_layout LyX-Code
print '%10s = %s' % ('today', make_asctime(currentResponse._today))
\end_layout
\begin_layout LyX-Code
print '%6s + %d = %s' % ('today', dateRequest._offset, make_asctime(respo
nse._day))
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# just a helper
\end_layout
\begin_layout LyX-Code
def make_asctime(date_object):
\end_layout
\begin_layout LyX-Code
timeTuple = (date_object._year, date_object._month, date_object._day,
\end_layout
\begin_layout LyX-Code
date_object._hour, date_object._minute, date_object._second,
\end_layout
\begin_layout LyX-Code
date_object._weekday, date_object._dayOfYear, date_object._dst
\end_layout
\begin_layout LyX-Code
)
\end_layout
\begin_layout LyX-Code
return time.asctime(timeTuple)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
if __name__ == '__main__':
\end_layout
\begin_layout LyX-Code
main()
\end_layout
\begin_layout Standard
As can be seen, ZSI provides us with the
\family typewriter
getCurrentDateRequest
\family default
and
\family typewriter
getDateRequest
\family default
classes.
These handle the serialization transparently and we use them to set the
argument values.
Then, we hand them into the corresponding methods of the service port object
retrieved with the
\family typewriter
simple_Date_ServiceLocator\SpecialChar \-
.getDate\SpecialChar \-
Service\SpecialChar \-
_Port()
\family default
method.
\end_layout
\begin_layout Standard
Running this client gives the following output:
\end_layout
\begin_layout LyX-Code
$ ./myDateClient.py -u "http://adevp02:8080/DateService?wsdl" -i HALLO
\end_layout
\begin_layout LyX-Code
*** ZSI version (2, 1, 0) ***
\end_layout
\begin_layout LyX-Code
Enter offset as int [0]: 0
\end_layout
\begin_layout LyX-Code
_________________________________ Thu Jan 3 08:40:56 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
HALLO
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Thu Jan 3 08:40:56 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Thu, 03 Jan 2008 07:40:56 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 627
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
200813
\end_layout
\begin_layout LyX-Code
84056
\end_layout
\begin_layout LyX-Code
330
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Thu Jan 3 08:40:56 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
0
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
200813
\end_layout
\begin_layout LyX-Code
84056
\end_layout
\begin_layout LyX-Code
330
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Thu Jan 3 08:40:56 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Thu, 03 Jan 2008 07:40:56 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 609
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
200813
\end_layout
\begin_layout LyX-Code
84056
\end_layout
\begin_layout LyX-Code
330
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
RESULT
\end_layout
\begin_layout LyX-Code
today = Thu Jan 3 08:40:56 2008
\end_layout
\begin_layout LyX-Code
today + 0 = Thu Jan 3 08:40:56 2008
\end_layout
\begin_layout LyX-Code
Enter offset as int [0]: ^C
\end_layout
\begin_layout Standard
Note that we gave an explicit URL of
\begin_inset Quotes eld
\end_inset
http://adevp02:8080/DateService?wsdl
\begin_inset Quotes erd
\end_inset
.
ZSI transparently uses the relevant part of this URL for service invocation,
silently ignoring the
\begin_inset Quotes eld
\end_inset
?wsdl
\begin_inset Quotes erd
\end_inset
suffix.
\end_layout
\begin_layout Paragraph
ZSI 2.0
\end_layout
\begin_layout LyX-Code
#! /apps/pydev/bin/python2.4
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# *** ZSI 2.0 ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
import sys, time
\end_layout
\begin_layout LyX-Code
from copy import copy
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from DateService_services import *
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def main():
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-u", "--url", help="service URL", metavar="URL")
\end_layout
\begin_layout LyX-Code
op.add_option("-i", "--input", type="string",
\end_layout
\begin_layout LyX-Code
help="input string for getCurrentDate WS method",
\end_layout
\begin_layout LyX-Code
metavar="INPUT")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
loc = simple_Date_ServiceLocator()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
service = loc.getDateService_PortType(url=options.url, tracefile=sys.stdout)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
offset = raw_input("Enter offset as int [0]: ")
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
offset = int(offset)
\end_layout
\begin_layout LyX-Code
except ValueError:
\end_layout
\begin_layout LyX-Code
offset = 0
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
currentRequest = getCurrentDateRequest()
\end_layout
\begin_layout LyX-Code
currentRequest._input = options.input
\end_layout
\begin_layout LyX-Code
currentResponse = service.getCurrentDate(currentRequest)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# We use the current date as input to getDate
\end_layout
\begin_layout LyX-Code
dateRequest = getDateRequest()
\end_layout
\begin_layout LyX-Code
dateRequest._offset = offset
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Workaround for ZSI 2.0 bug #1755740:
\end_layout
\begin_layout LyX-Code
# Multiple calls to method _get_type_or_substitute erroneously changes
\end_layout
\begin_layout LyX-Code
# attributes of a substitute typecode without making a (shallow)
copy
\end_layout
\begin_layout LyX-Code
currentResponse._today.typecode = copy(currentResponse._today.typecode)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
dateRequest._someday = currentResponse._today
\end_layout
\begin_layout LyX-Code
response = service.getDate(dateRequest)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
n
\backslash
nRESULT'
\end_layout
\begin_layout LyX-Code
print '%10s = %s' % ('today', make_asctime(currentResponse._today))
\end_layout
\begin_layout LyX-Code
print '%6s + %d = %s' % ('today', dateRequest._offset, make_asctime(respo
nse._day))
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# just a helper
\end_layout
\begin_layout LyX-Code
def make_asctime(date_object):
\end_layout
\begin_layout LyX-Code
timeTuple = (date_object._year, date_object._month, date_object._day,
\end_layout
\begin_layout LyX-Code
date_object._hour, date_object._minute, date_object._second,
\end_layout
\begin_layout LyX-Code
date_object._weekday, date_object._dayOfYear, date_object._dst
\end_layout
\begin_layout LyX-Code
)
\end_layout
\begin_layout LyX-Code
return time.asctime(timeTuple)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
if __name__ == '__main__':
\end_layout
\begin_layout LyX-Code
main()
\end_layout
\begin_layout Standard
Again the ZSI 2.0 implementation differs only in details:
\end_layout
\begin_layout Itemize
import the generated code from
\family typewriter
DateService_services
\family default
(rather than
\family typewriter
DateService_client
\family default
in ZSI 2.1)
\end_layout
\begin_layout Itemize
retrieve the service binding through the
\family typewriter
simple_Date_ServiceLocator.getDateService_PortType()
\family default
method (rather than
\family typewriter
simple_Date_ServiceLocator.getDateService_Port()
\family default
in ZSI 2.1
\end_layout
\begin_layout Itemize
instantiate the
\family typewriter
getDateRequest
\family default
structure and then populate it (as opposed to using keyword args in ZSI
2.1)
\end_layout
\begin_layout Standard
Unfortunately, ZSI 2.0 has a bug that bites us so we need to use a workaround
here (see code comments).
\end_layout
\begin_layout Subsubsection
Using a ServiceProxy client
\end_layout
\begin_layout Standard
Alternatively, we can implement a client with the ServiceProxy class without
using the generated code.
This version works for both ZSI 2.0 & 2.1:
\end_layout
\begin_layout LyX-Code
# *** ZSI 2.0 & 2.1 ***
\end_layout
\begin_layout LyX-Code
import sys, time
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
from ZSI.ServiceProxy import ServiceProxy
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-u", "--url", help="service URL (mandatory)", metavar="URL")
\end_layout
\begin_layout LyX-Code
op.add_option("-i", "--input", type="string",
\end_layout
\begin_layout LyX-Code
help="input string for getCurrentDate WS method",
\end_layout
\begin_layout LyX-Code
metavar="INPUT")
\end_layout
\begin_layout LyX-Code
# just a helper
\end_layout
\begin_layout LyX-Code
def make_asctime(date_dict):
\end_layout
\begin_layout LyX-Code
timeTuple = (date_dict["year"], date_dict["month"], date_dict["day"],
\end_layout
\begin_layout LyX-Code
date_dict["hour"], date_dict["minute"], date_dict["second"],
\end_layout
\begin_layout LyX-Code
date_dict["weekday"], date_dict["dayOfYear"],
\end_layout
\begin_layout LyX-Code
date_dict["dst"])
\end_layout
\begin_layout LyX-Code
return time.asctime(timeTuple)
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
if not options.url:
\end_layout
\begin_layout LyX-Code
op.print_help()
\end_layout
\begin_layout LyX-Code
sys.exit(1)
\end_layout
\begin_layout LyX-Code
else:
\end_layout
\begin_layout LyX-Code
# "Canonicalize" WSDL URL
\end_layout
\begin_layout LyX-Code
options.url = options.url.replace("?WSDL", "?wsdl")
\end_layout
\begin_layout LyX-Code
if not options.url.endswith("?wsdl"):
\end_layout
\begin_layout LyX-Code
options.url += "?wsdl"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
service = ServiceProxy(wsdl=options.url, tracefile=sys.stdout)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
nAccessing service DateService...'
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
offset = raw_input("Enter offset as int [0]: ")
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
offset = int(offset)
\end_layout
\begin_layout LyX-Code
except ValueError:
\end_layout
\begin_layout LyX-Code
offset = 0
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
currentResponse = service.getCurrentDate(input=options.input)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# We get back a dictionaray
\end_layout
\begin_layout LyX-Code
print "currentResponse:", currentResponse
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Manually fill the argument dict for demonstration purposes only
\end_layout
\begin_layout LyX-Code
somedayDict = {
\end_layout
\begin_layout LyX-Code
'year': currentResponse['today']['year'],
\end_layout
\begin_layout LyX-Code
'month': currentResponse['today']['month'],
\end_layout
\begin_layout LyX-Code
'day': currentResponse['today']['day'],
\end_layout
\begin_layout LyX-Code
'hour': currentResponse['today']['hour'],
\end_layout
\begin_layout LyX-Code
'minute': currentResponse['today']['minute'],
\end_layout
\begin_layout LyX-Code
'second': currentResponse['today']['second'],
\end_layout
\begin_layout LyX-Code
'weekday': currentResponse['today']['weekday'],
\end_layout
\begin_layout LyX-Code
'dayOfYear': currentResponse['today']['dayOfYear'],
\end_layout
\begin_layout LyX-Code
'dst': currentResponse['today']['dst'],
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# We use the current date as input to getDate
\end_layout
\begin_layout LyX-Code
response = service.getDate(offset=offset,
\end_layout
\begin_layout LyX-Code
someday=currentResponse["today"])
\end_layout
\begin_layout LyX-Code
responseFromDict = service.getDate(offset=offset, someday=somedayDict)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
n
\backslash
nRESULT'
\end_layout
\begin_layout LyX-Code
print '%10s = %s' % ('today', make_asctime(currentResponse["today"]))
\end_layout
\begin_layout LyX-Code
print '%6s + %d = %s' % ('today', offset, make_asctime(response["day"]))
\end_layout
\begin_layout Standard
This is the output of a sample client sesssion of the ServiceProxy solution:
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/bin/python2.4 ./myDateSPclient.py -u "http://adevp02:8080/DateService
?wsdl" -i HALLO
\end_layout
\begin_layout LyX-Code
*** ZSI version (2, 0, 0) ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Accessing service DateService...
\end_layout
\begin_layout LyX-Code
Enter offset as int [0]: 1
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 17:46:50 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
HALLO
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 17:46:50 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Wed, 02 Jan 2008 16:46:50 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 628
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
2008
\end_layout
\begin_layout LyX-Code
1
\end_layout
\begin_layout LyX-Code
2174650
\end_layout
\begin_layout LyX-Code
220
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
currentResponse: {'today': {'second': 50, 'dayOfYear': 2, 'day': 2, 'month':
1, 'minute': 46, 'dst': 0, 'weekday': 2, 'hour': 17, 'year': 2008}}
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 17:46:50 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
1
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
200812
\end_layout
\begin_layout LyX-Code
174650
\end_layout
\begin_layout LyX-Code
220
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 17:46:50 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Wed, 02 Jan 2008 16:46:50 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 610
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
200813
\end_layout
\begin_layout LyX-Code
174650
\end_layout
\begin_layout LyX-Code
330
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 17:46:50 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
1
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
200812
\end_layout
\begin_layout LyX-Code
174650
\end_layout
\begin_layout LyX-Code
220
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Wed Jan 2 17:46:50 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Wed, 02 Jan 2008 16:46:50 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 610
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
200813
\end_layout
\begin_layout LyX-Code
174650
\end_layout
\begin_layout LyX-Code
330
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
RESULT
\end_layout
\begin_layout LyX-Code
today = Wed Jan 2 17:46:50 2008
\end_layout
\begin_layout LyX-Code
today + 1 = Thu Jan 3 17:46:50 2008
\end_layout
\begin_layout LyX-Code
Enter offset as int [0]:
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
We have hinted so and now this becomes important: For ZSI 2.1, the presented
code will only work if it is run from a directory that
\emph on
does not
\emph default
contain
\family typewriter
wsdl2py
\family default
-generated code, see section
\begin_inset LatexCommand \ref{sub:SquareService-ZSI-ServiceProxy}
\end_inset
.
This is because the ServiceProxy cache code, as opposed to the
\family typewriter
wsdl2py
\family default
-generated code, does not use
\begin_inset Quotes eld
\end_inset
ZSI aname modification
\begin_inset Quotes erd
\end_inset
.
\begin_inset Foot
status open
\begin_layout Standard
So one module will e.g.
expect names not to start with
\begin_inset Quotes eld
\end_inset
_
\begin_inset Quotes erd
\end_inset
while the other one will.
\end_layout
\end_inset
This is not a problem for ZSI 2.0 as it uses different cache module naming.
We consider this a bug in ZSI 2.1alpha.
\end_layout
\begin_layout Itemize
For demonstration purposes only, the
\family typewriter
getDate()
\family default
method gets actually invoked twice, the second time with manually created
dictionary input data.
\end_layout
\begin_layout Subsection
A gSOAP C++ client for the DateService
\end_layout
\begin_layout Subsubsection
Code generation from WSDL
\begin_inset LatexCommand \label{sub:Code-generation-gsoap_DateService}
\end_inset
\end_layout
\begin_layout Enumerate
Header:
\end_layout
\begin_deeper
\begin_layout LyX-Code
$ /apps/pydev/bin/wsdl2h -o dateService.h http://adevp02:8080/DateService?wsdl
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
** The gSOAP WSDL parser for C and C++ 1.2.9l
\end_layout
\begin_layout LyX-Code
** Copyright (C) 2000-2007 Robert van Engelen, Genivia Inc.
\end_layout
\begin_layout LyX-Code
** All Rights Reserved.
This product is provided "as is", without any warranty.
\end_layout
\begin_layout LyX-Code
** The gSOAP WSDL parser is released under one of the following two licenses:
\end_layout
\begin_layout LyX-Code
** GPL or the commercial license by Genivia Inc.
Use option -l for more info.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Saving dateService.h
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Cannot open file 'typemap.dat'
\end_layout
\begin_layout LyX-Code
Problem reading type map file typemap.dat.
\end_layout
\begin_layout LyX-Code
Using internal type definitions for C++ instead.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Connecting to 'http://adevp02:8080/DateService?wsdl' to retrieve WSDL/XSD...
connected, receiving...
\end_layout
\begin_layout LyX-Code
Warning: part 'today' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'input' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'input' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'input' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'day' uses literal style and should refer to an element rather
than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'offset' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'someday' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'offset' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'someday' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'offset' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
Warning: part 'someday' uses literal style and should refer to an element
rather than a type
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
To complete the process, compile with:
\end_layout
\begin_layout LyX-Code
soapcpp2 dateService.h
\end_layout
\begin_layout Standard
gSOAP allows you to modify code generation e.g.
with regard to schema namespace bindings (names of prefixes, \SpecialChar \ldots{}
) or type
mappings.
Take a look at the comments in the generated
\family typewriter
dateService.h
\family default
for instructions.
\end_layout
\end_deeper
\begin_layout Enumerate
Stub code:
\end_layout
\begin_deeper
\begin_layout LyX-Code
$ /apps/pydev/bin/soapcpp2 -I /data/pydev/DOWNLOADS/WebServices/C++/gsoap-2.7/soa
pcpp2/import dateService.h
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
** The gSOAP Stub and Skeleton Compiler for C and C++ 2.7.9l
\end_layout
\begin_layout LyX-Code
** Copyright (C) 2000-2007, Robert van Engelen, Genivia Inc.
\end_layout
\begin_layout LyX-Code
** All Rights Reserved.
This product is provided "as is", without any warranty.
\end_layout
\begin_layout LyX-Code
** The gSOAP compiler is released under one of the following three licenses:
\end_layout
\begin_layout LyX-Code
** GPL, the gSOAP public license, or the commercial license by Genivia
Inc.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Saving soapStub.h
\end_layout
\begin_layout LyX-Code
Saving soapH.h
\end_layout
\begin_layout LyX-Code
Saving soapC.cpp
\end_layout
\begin_layout LyX-Code
Saving soapClient.cpp
\end_layout
\begin_layout LyX-Code
Saving soapClientLib.cpp
\end_layout
\begin_layout LyX-Code
Saving soapServer.cpp
\end_layout
\begin_layout LyX-Code
Saving soapServerLib.cpp
\end_layout
\begin_layout LyX-Code
Using ns3 service name: DateService_USCOREBinding
\end_layout
\begin_layout LyX-Code
Using ns3 service style: document
\end_layout
\begin_layout LyX-Code
Using ns3 service encoding: literal
\end_layout
\begin_layout LyX-Code
Using ns3 service location: http://adevp02:8080/DateService
\end_layout
\begin_layout LyX-Code
Using ns3 schema namespace: urn:DateService.wsdl
\end_layout
\begin_layout LyX-Code
Saving soapDateService_USCOREBindingProxy.h client proxy
\end_layout
\begin_layout LyX-Code
Saving soapDateService_USCOREBindingObject.h server object
\end_layout
\begin_layout LyX-Code
Saving DateService_USCOREBinding.getCurrentDate.req.xml sample SOAP/XML request
\end_layout
\begin_layout LyX-Code
Saving DateService_USCOREBinding.getCurrentDate.res.xml sample SOAP/XML response
\end_layout
\begin_layout LyX-Code
Saving DateService_USCOREBinding.getDate.req.xml sample SOAP/XML request
\end_layout
\begin_layout LyX-Code
Saving DateService_USCOREBinding.getDate.res.xml sample SOAP/XML response
\end_layout
\begin_layout LyX-Code
Saving DateService_USCOREBinding.nsmap namespace mapping table
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Compilation successful
\end_layout
\end_deeper
\begin_layout Subsubsection
Client implementation
\end_layout
\begin_layout Standard
As already announced in section
\begin_inset LatexCommand \ref{sub:gsoap-square-client}
\end_inset
weīll now access the service a bit more elegantly through the
\family typewriter
DateService_USCOREBinding
\family default
proxy class, which can be found in
\family typewriter
soapDateService_USCOREBindingProxy.h
\family default
.
We use it to call the two WS-methods in our sample client:
\end_layout
\begin_layout LyX-Code
// Contents of file "myclient_use_proxy.cpp"
\end_layout
\begin_layout LyX-Code
//#include "soapH.h";
\end_layout
\begin_layout LyX-Code
#include "soapDateService_USCOREBindingProxy.h"
\end_layout
\begin_layout LyX-Code
#include "DateService_USCOREBinding.nsmap"
\end_layout
\begin_layout LyX-Code
int main()
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
DateService_USCOREBinding ds;
\end_layout
\begin_layout LyX-Code
ns2__Date *today, *someday;
\end_layout
\begin_layout LyX-Code
ns3__getCurrentDateResponse today_response;
\end_layout
\begin_layout LyX-Code
ns3__getDateResponse someday_response;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
std::string text, input;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
text="TEST";
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
std::cout << "(1) Calling 'getCurrentDate()'- Web Service method:" <<
std::endl;
\end_layout
\begin_layout LyX-Code
if(ds.ns3__getCurrentDate(text, today_response) == SOAP_OK)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
today = today_response.today;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
nCurrent date:" << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tyear: " << *today->year << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tmonth: " << *today->month << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tday: " << *today->day << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
thour: " << *today->hour << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tminute: " << *today->minute << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tsecond: " << *today->second << std::endl;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
else
\end_layout
\begin_layout LyX-Code
soap_print_fault(ds.soap, stderr);
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
n(2) Calling 'getDate()'- Web Service method:" << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
n(2)Please enter an integer for the 'offset'"<< std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
toffset = ";
\end_layout
\begin_layout LyX-Code
std::cin >> input;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
someday = today;
\end_layout
\begin_layout LyX-Code
if(ds.ns3__getDate(input, someday, someday_response) == SOAP_OK)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
someday = someday_response.day;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
nSome Day:" << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tyear: " << *someday->year << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tmonth: "<< *someday->month << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tday: " << *someday->day << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
thour: " << *today->hour << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tminute: " << *today->minute << std::endl;
\end_layout
\begin_layout LyX-Code
std::cout << "
\backslash
tsecond: " << *today->second << std::endl;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
else
\end_layout
\begin_layout LyX-Code
return 0;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
You can find the classes/structs that represent the WSDL input and output
datatypes in the generated file
\family typewriter
soapStub.h
\family default
.
This file is really pretty much self-explaining, so the usage in client
implementations should be straightforward.
\end_layout
\begin_layout Subsubsection
gSOAP Client compilation
\end_layout
\begin_layout Paragraph
gcc 2.95.2
\end_layout
\begin_layout LyX-Code
$ g++ -o myClient_use_proxy -I/apps/pydev/include -L/apps/pydev/lib
\end_layout
\begin_layout LyX-Code
-R /apps/prod/lib myClient_use_proxy.cpp soapC.cpp soapClient.cpp
\end_layout
\begin_layout LyX-Code
-lsocket -lgsoap++
\end_layout
\begin_layout Paragraph
gcc 3.4.4
\end_layout
\begin_layout LyX-Code
$ /apps/local/gcc/3.4.4/bin/g++ -o myClient_use_proxy -R /apps/prod/gcc/3.4.4/lib
-I/apps/pydev/gcc/3.4.4/include -L/apps/pydev/gcc/3.4.4/lib soapC.cpp soapClient.cpp
myClient_use_proxy.cpp -lgsoap++ -lsocket -lnsl
\end_layout
\begin_layout Standard
Running the client gives the following output:
\end_layout
\begin_layout LyX-Code
$ ./myClient_use_proxy
\end_layout
\begin_layout LyX-Code
(1) Calling 'getCurrentDate()'- Web Service method:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Current date:
\end_layout
\begin_layout LyX-Code
year: 2008
\end_layout
\begin_layout LyX-Code
month: 1
\end_layout
\begin_layout LyX-Code
day: 8
\end_layout
\begin_layout LyX-Code
hour: 17
\end_layout
\begin_layout LyX-Code
minute: 13
\end_layout
\begin_layout LyX-Code
second: 30
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
(2) Calling 'getDate()'- Web Service method:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
(2)Please enter an integer for the 'offset'
\end_layout
\begin_layout LyX-Code
offset = 88
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Some Day:
\end_layout
\begin_layout LyX-Code
year: 2008
\end_layout
\begin_layout LyX-Code
month: 4
\end_layout
\begin_layout LyX-Code
day: 5
\end_layout
\begin_layout LyX-Code
hour: 17
\end_layout
\begin_layout LyX-Code
minute: 13
\end_layout
\begin_layout LyX-Code
second: 30
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout Section
A document/literal service: The FinancialService
\begin_inset LatexCommand \label{sec:FinancialService-document/literal-service}
\end_inset
\end_layout
\begin_layout Standard
The previous example services had in common that they used rpc/literal binding.
While this is WS-I-compliant, there is a tendency to propagate the usage
of the document/literal fashion.
With rpc/literal, you might define types or elements to be used in the
request and response messages, in the
\family typewriter
\family default
section.
We did that for the DateService, see section
\begin_inset LatexCommand \ref{sub:The-DateService-WSDL}
\end_inset
.
You use these elements or types as arguments or receive them as return
value of the service call.
They are
\begin_inset Quotes eld
\end_inset
packed
\begin_inset Quotes erd
\end_inset
into the request or the response tags in the actual SOAP message, as can
be seen in the sample client output in
\begin_inset LatexCommand \ref{sub:A-Python-ZSI-client-DateService}
\end_inset
.
\end_layout
\begin_layout Standard
The difference with document/literal binding is that the
\emph on
complete
\emph default
message inside
\family typewriter
\family default
is described in the
\family typewriter
\family default
section, as an XML schema - not only the call parameters/return values.
The big advantage is obvious: Such a message can be XML Schema-validated.
\end_layout
\begin_layout Standard
As it is quite possible with document/literal to leave the service method
name out of the request/response message at all, depending on your
\family typewriter
\family default
definitions, there can also be a downside to this.
Because if you do so, it might be difficult for the server implementation
to dispatch correctly.
\begin_inset Foot
status open
\begin_layout Standard
At least if dispatching does not rely on the SOAPAction header field.
\end_layout
\end_inset
To avoid this, we explicitly model the method name into our request, as
a toplevel element.
This is called
\begin_inset Quotes eld
\end_inset
document-wrapped
\begin_inset Quotes erd
\end_inset
style.
\end_layout
\begin_layout Standard
Most of the steps from WSDL to implementation should be familiar by now;
we will thus concentrate on the doc/literal differences and mainly present
the (commented) code.
\end_layout
\begin_layout Subsection
The FinancialService WSDL
\end_layout
\begin_layout Standard
The FinancialService is described in
\family typewriter
FinancialService.wsdl
\family default
:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Financial Web Service.
Methods: -getPV(irate, CFSequence):
\end_layout
\begin_layout LyX-Code
Return present value for given interest rate and Cash Flows.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout Standard
Notes:
\end_layout
\begin_layout Itemize
The FinancialServiceīs getPV operation returns the net present value for
a given interest rate
\begin_inset Formula $r$
\end_inset
and a series of cash flows.
It uses document/literal binding, so the full ingoing and outgoing message
structure is defined in the WSDL
\family typewriter
\family default
XML Schema section.
\end_layout
\begin_layout Itemize
The
\family typewriter
soapAction
\family default
attribute is empty (
\family typewriter
\family default
).
This means the server will have to use a different way to dispatch to the
method implementation.
\end_layout
\begin_layout Itemize
Note the use of
\family typewriter
elementFormDefault=
\begin_inset Quotes erd
\end_inset
qualified
\begin_inset Quotes erd
\end_inset
\family default
in the XML Schema root element.
This basically means that local elements (you might say sub-elements) must
be namespace-qualified.
The XML Schema default for this attribute is
\begin_inset Quotes eld
\end_inset
unqualified
\begin_inset Quotes erd
\end_inset
but we ran into interoperability problems when not setting this to
\begin_inset Quotes eld
\end_inset
qualified
\begin_inset Quotes erd
\end_inset
, which seems to be a ZSI 2.0/2.1alpha bug.
\emph on
Note: By the time of this writing, this has already been fixed with ZSI
svn revision r1440.
\end_layout
\begin_layout Subsection
A Python ZSI FinancialService server
\begin_inset LatexCommand \label{sub:Python-ZSI-FinancialService-server}
\end_inset
\end_layout
\begin_layout Subsubsection
Code generation from WSDL
\end_layout
\begin_layout Standard
We now take advantage of ZSIīs
\family typewriter
--complexType
\family default
option for code generation, to get some convenience getters, setters and
factories:
\end_layout
\begin_layout Paragraph
ZSI 2.1
\end_layout
\begin_layout LyX-Code
/apps/pydev/hjoukl/bin/wsdl2py --complexType FinancialService.wsdl
\end_layout
\begin_layout LyX-Code
==> FinancialService_client.py
\end_layout
\begin_layout LyX-Code
==> FinancialService_server.py
\end_layout
\begin_layout LyX-Code
==> FinancialService_types.py
\end_layout
\begin_layout Paragraph
ZSI 2.0
\end_layout
\begin_layout Enumerate
\family typewriter
wsdl2py
\family default
:
\end_layout
\begin_deeper
\begin_layout LyX-Code
/apps/pydev/bin/wsdl2py --complexType -f FinancialService.wsdl
\end_layout
\begin_layout LyX-Code
==> FinancialService_services.py
\end_layout
\begin_layout LyX-Code
==> FinancialService_services_types.py
\end_layout
\end_deeper
\begin_layout Enumerate
\family typewriter
wsdl2dispatch:
\end_layout
\begin_deeper
\begin_layout LyX-Code
/apps/pydev/bin/wsdl2dispatch -f FinancialService.wsdl
\end_layout
\begin_layout LyX-Code
==> FinancialService_services_server.py
\end_layout
\end_deeper
\begin_layout Subsubsection
The FinancialService server implementation
\end_layout
\begin_layout Paragraph
ZSI 2.0 & 2.1
\end_layout
\begin_layout Standard
Following the DateService example (
\begin_inset LatexCommand \ref{sub:A-Python-ZSI-DateService-server}
\end_inset
), we create a server implementation that runs with both ZSI version 2.0
and 2.1:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the ZSI stuff you'd need no matter what
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.wstools import logging
\end_layout
\begin_layout LyX-Code
from ZSI import ServiceContainer
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
# 2.1alpha
\end_layout
\begin_layout LyX-Code
from FinancialService_server import *
\end_layout
\begin_layout LyX-Code
# Dummy implementation
\end_layout
\begin_layout LyX-Code
def adapt(method):
\end_layout
\begin_layout LyX-Code
return method
\end_layout
\begin_layout LyX-Code
except ImportError, e:
\end_layout
\begin_layout LyX-Code
# 2.0final
\end_layout
\begin_layout LyX-Code
from FinancialService_services_server import *
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from service_adaptor import ServiceAdaptor21
\end_layout
\begin_layout LyX-Code
adapt = ServiceAdaptor21.adapt
\end_layout
\begin_layout LyX-Code
# Wrap generated 2.0 class to 2.1 soap_ method behaviour
\end_layout
\begin_layout LyX-Code
FinancialService = ServiceAdaptor21(FinancialService)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Create a Server implementation by inheritance
\end_layout
\begin_layout LyX-Code
# 2.1alpha implementation
\end_layout
\begin_layout LyX-Code
class MyFinancialService(FinancialService):
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Make WSDL available for HTTP GET
\end_layout
\begin_layout LyX-Code
_wsdl = "".join(open("FinancialService.wsdl").readlines())
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@adapt
\end_layout
\begin_layout LyX-Code
def soap_getPV(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = FinancialService.soap_getPV(self, ps, **kw)
\end_layout
\begin_layout LyX-Code
# Comment that out if need be to see what API these objects offer:
\end_layout
\begin_layout LyX-Code
#print help(request)
\end_layout
\begin_layout LyX-Code
#print help(response)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Using getters/setters
\end_layout
\begin_layout LyX-Code
irate = request.get_element_irate()
\end_layout
\begin_layout LyX-Code
CFs = request.get_element_CFSequence().get_element_CF()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Alternative way to access the input data
\end_layout
\begin_layout LyX-Code
#irate = request._irate
\end_layout
\begin_layout LyX-Code
#CFs = request._CFSequence._CF
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Invoke the service worker code
\end_layout
\begin_layout LyX-Code
PV = self.getPV(irate, CFs)
\end_layout
\begin_layout LyX-Code
#print "PV:", PV
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# assign return value to response object
\end_layout
\begin_layout LyX-Code
response = getPVResponse(PV)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Another way to create a serializable response object
\end_layout
\begin_layout LyX-Code
#class SimpleTypeWrapper(float):
\end_layout
\begin_layout LyX-Code
# typecode = response.typecode
\end_layout
\begin_layout LyX-Code
#response = SimpleTypeWrapper(PV)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def getPV(self, irate, cashFlows):
\end_layout
\begin_layout LyX-Code
# worker code method
\end_layout
\begin_layout LyX-Code
t = 0
\end_layout
\begin_layout LyX-Code
PV = 0.0
\end_layout
\begin_layout LyX-Code
for CF in cashFlows:
\end_layout
\begin_layout LyX-Code
PV += (CF or 0.0) * ((irate / 100.0 + 1) ** (-t))
\end_layout
\begin_layout LyX-Code
t += 1
\end_layout
\begin_layout LyX-Code
return PV
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-l", "--loglevel", help="loglevel (DEBUG, WARN)",
\end_layout
\begin_layout LyX-Code
metavar="LOGLEVEL")
\end_layout
\begin_layout LyX-Code
op.add_option("-p", "--port", help="HTTP port",
\end_layout
\begin_layout LyX-Code
metavar="PORT", default=8080, type="int")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# set the loglevel according to cmd line arg
\end_layout
\begin_layout LyX-Code
if options.loglevel:
\end_layout
\begin_layout LyX-Code
loglevel = eval(options.loglevel, logging.__dict__)
\end_layout
\begin_layout LyX-Code
logger = logging.getLogger("")
\end_layout
\begin_layout LyX-Code
logger.setLevel(loglevel)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Run the server with a given list of services
\end_layout
\begin_layout LyX-Code
ServiceContainer.AsServer(port=options.port, services=[MyFinancialService(),])
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
The service input data is now retrieved from the
\family typewriter
request
\family default
object with
\family typewriter
request.get_element_()
\family default
getter methods.
An alternative is presented in the code comments.
\end_layout
\begin_layout Itemize
If you need information on an objects attributes and can not find it in
the docs, it can be quite helpful to make use of the power of introspection,
and of docstrings, e.g.
putting things like
\end_layout
\begin_deeper
\begin_layout LyX-Code
print help(request)
\end_layout
\begin_layout LyX-Code
print help(response)
\end_layout
\begin_layout Standard
into the server code.
\end_layout
\end_deeper
\begin_layout Itemize
Remember we left out the
\family typewriter
soapACTION
\family default
field from the WSDL file (we left it empty, to be precise).
So the dispatch to a serviceīs service method must now happen another way.
And indeed, ZSI is capable of dispatching by making use of the name of
the toplevel in-message element name.
Thatīs the benefit of following the
\begin_inset Quotes eld
\end_inset
document-wrapped
\begin_inset Quotes erd
\end_inset
style, see above.
\end_layout
\begin_layout Subsection
A Python ZSI client for the FinancialService
\end_layout
\begin_layout Standard
Making use of the generated stub code, this is a client implementation that
works with both ZSI 2.0 & 2.1:
\end_layout
\begin_layout LyX-Code
import sys, time
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
# 2.1alpha
\end_layout
\begin_layout LyX-Code
from FinancialService_client import *
\end_layout
\begin_layout LyX-Code
portMethodName = "getFinancialService_Port"
\end_layout
\begin_layout LyX-Code
except ImportError, e:
\end_layout
\begin_layout LyX-Code
# 2.0final
\end_layout
\begin_layout LyX-Code
from FinancialService_services import *
\end_layout
\begin_layout LyX-Code
portMethodName = "getFinancialService_PortType"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def main():
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-u", "--url", help="service URL", metavar="URL")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
loc = FinancialServiceLocator()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
service = getattr(loc, portMethodName)(url=options.url, tracefile=sys.stdout)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
print '
\backslash
nAccessing service FinancialService, method getPV...'
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
irate = None
\end_layout
\begin_layout LyX-Code
while not (0.0 <= irate <= 100.0):
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
irate = float(raw_input("Enter interest rate in percent:
"))
\end_layout
\begin_layout LyX-Code
except ValueError, e:
\end_layout
\begin_layout LyX-Code
print e
\end_layout
\begin_layout LyX-Code
CFs = []
\end_layout
\begin_layout LyX-Code
period = 0
\end_layout
\begin_layout LyX-Code
while 1:
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
CFs.append(float(raw_input("Enter CF(t=%s) [Ctrl-C to end]:
" % (period,))))
\end_layout
\begin_layout LyX-Code
period += 1
\end_layout
\begin_layout LyX-Code
except ValueError, e:
\end_layout
\begin_layout LyX-Code
print e
\end_layout
\begin_layout LyX-Code
except KeyboardInterrupt:
\end_layout
\begin_layout LyX-Code
print "...done."
\end_layout
\begin_layout LyX-Code
break
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
#print "CFs list is:", CFs
\end_layout
\begin_layout LyX-Code
#print "Calculation interest rate is:", irate
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
getPV = getPVRequest()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
getPV.set_element_irate(irate)
\end_layout
\begin_layout LyX-Code
CFSequence = getPV.new_CFSequence()
\end_layout
\begin_layout LyX-Code
CFSequence.set_element_CF(CFs)
\end_layout
\begin_layout LyX-Code
getPV.set_element_CFSequence(CFSequence)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Alternatively, a valid request data structure can be provided
like
\end_layout
\begin_layout LyX-Code
# this (e.g.
you do not want to use --complexType getters/setters)
\end_layout
\begin_layout LyX-Code
#class CFSequence_class:
\end_layout
\begin_layout LyX-Code
# _CF = CFs
\end_layout
\begin_layout LyX-Code
#getPV._irate = irate
\end_layout
\begin_layout LyX-Code
#getPV._CFSequence = CFSequence_class
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
result = service.getPV(getPV)
\end_layout
\begin_layout LyX-Code
print 'result:', result
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
if __name__ == '__main__':
\end_layout
\begin_layout LyX-Code
main()
\end_layout
\begin_layout Standard
After the necessary data has been read from the user, the appropriate attributes
of the
\family typewriter
getPVRequest
\family default
instance are set.
This is done by heavy use of the getters, setters and factory methods ZSI
adds when using
\family typewriter
--complexType
\family default
code generation.
\end_layout
\begin_layout Standard
An alternative is to model the sequence of cash flow elements with a the
local class
\family typewriter
CFSequence_class
\family default
, see code comments.
This class is
\begin_inset Quotes eld
\end_inset
structurally equivalent
\begin_inset Quotes erd
\end_inset
to the XML Schema
\family typewriter
CFSequence
\family default
complexType as defined in the WSDL.
ZSI then handles all the type mapping and serialization issues for us.
\end_layout
\begin_layout Standard
Sample client session output:
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/hjoukl/bin/python2.4 ./myFinancialClient.py -u "http://adevp02:8080/F
inancialService"
\end_layout
\begin_layout LyX-Code
*** ZSI version (2, 1, 0) ***
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Accessing service FinancialService, method getPV...
\end_layout
\begin_layout LyX-Code
Enter interest rate in percent: 7
\end_layout
\begin_layout LyX-Code
Enter CF(t=0) [Ctrl-C to end]: -100
\end_layout
\begin_layout LyX-Code
Enter CF(t=1) [Ctrl-C to end]: 8
\end_layout
\begin_layout LyX-Code
Enter CF(t=2) [Ctrl-C to end]: 8
\end_layout
\begin_layout LyX-Code
Enter CF(t=3) [Ctrl-C to end]: 108
\end_layout
\begin_layout LyX-Code
Enter CF(t=4) [Ctrl-C to end]: ^C...done.
\end_layout
\begin_layout LyX-Code
_________________________________ Thu Jan 10 13:07:38 2008 REQUEST:
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
7.000000
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
-100.000000
\end_layout
\begin_layout LyX-Code
8.000000
\end_layout
\begin_layout LyX-Code
8.000000
\end_layout
\begin_layout LyX-Code
108.000000
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
_________________________________ Thu Jan 10 13:07:38 2008 RESPONSE:
\end_layout
\begin_layout LyX-Code
200
\end_layout
\begin_layout LyX-Code
OK
\end_layout
\begin_layout LyX-Code
-------
\end_layout
\begin_layout LyX-Code
Server: ZSI/1.1 BaseHTTP/0.3 Python/2.4.4
\end_layout
\begin_layout LyX-Code
Date: Thu, 10 Jan 2008 12:07:38 GMT
\end_layout
\begin_layout LyX-Code
Content-type: text/xml; charset="utf-8"
\end_layout
\begin_layout LyX-Code
Content-Length: 456
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
2.624316
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
result: 2.624316
\end_layout
\begin_layout LyX-Code
Enter interest rate in percent:
\end_layout
\begin_layout Subsection
A gSOAP C++ client for the FinancialService
\end_layout
\begin_layout Subsubsection
Code generation from WSDL
\end_layout
\begin_layout Enumerate
Header:
\end_layout
\begin_deeper
\begin_layout LyX-Code
$ /apps/pydev/bin/wsdl2h -o financialService.h http://adevp02:8080/FinancialServi
ce?wsdl
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
** The gSOAP WSDL parser for C and C++ 1.2.9l
\end_layout
\begin_layout LyX-Code
** Copyright (C) 2000-2007 Robert van Engelen, Genivia Inc.
\end_layout
\begin_layout LyX-Code
** All Rights Reserved.
This product is provided "as is", without any warranty.
\end_layout
\begin_layout LyX-Code
** The gSOAP WSDL parser is released under one of the following two licenses:
\end_layout
\begin_layout LyX-Code
** GPL or the commercial license by Genivia Inc.
Use option -l for more info.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Saving financialService.h
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Cannot open file 'typemap.dat'
\end_layout
\begin_layout LyX-Code
Problem reading type map file typemap.dat.
\end_layout
\begin_layout LyX-Code
Using internal type definitions for C++ instead.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Connecting to 'http://adevp02:8080/FinancialService?wsdl' to retrieve WSDL/XSD...
connected, receiving...
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
To complete the process, compile with:
\end_layout
\begin_layout LyX-Code
soapcpp2 financialService.h
\end_layout
\begin_layout LyX-Code
\end_layout
\end_deeper
\begin_layout Enumerate
Stub code:
\end_layout
\begin_deeper
\begin_layout LyX-Code
$ /apps/pydev/bin/soapcpp2 -I /data/pydev/DOWNLOADS/WebServices/C++/gsoap-2.7/soa
pcpp2/import financialService.h
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
** The gSOAP Stub and Skeleton Compiler for C and C++ 2.7.9l
\end_layout
\begin_layout LyX-Code
** Copyright (C) 2000-2007, Robert van Engelen, Genivia Inc.
\end_layout
\begin_layout LyX-Code
** All Rights Reserved.
This product is provided "as is", without any warranty.
\end_layout
\begin_layout LyX-Code
** The gSOAP compiler is released under one of the following three licenses:
\end_layout
\begin_layout LyX-Code
** GPL, the gSOAP public license, or the commercial license by Genivia
Inc.
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Saving soapStub.h
\end_layout
\begin_layout LyX-Code
Saving soapH.h
\end_layout
\begin_layout LyX-Code
Saving soapC.cpp
\end_layout
\begin_layout LyX-Code
Saving soapClient.cpp
\end_layout
\begin_layout LyX-Code
Saving soapClientLib.cpp
\end_layout
\begin_layout LyX-Code
Saving soapServer.cpp
\end_layout
\begin_layout LyX-Code
Saving soapServerLib.cpp
\end_layout
\begin_layout LyX-Code
Using ns1 service name: FinancialService_USCOREBinding
\end_layout
\begin_layout LyX-Code
Using ns1 service style: document
\end_layout
\begin_layout LyX-Code
Using ns1 service encoding: literal
\end_layout
\begin_layout LyX-Code
Using ns1 service location: http://adevp02:8080/FinancialService
\end_layout
\begin_layout LyX-Code
Using ns1 schema namespace: http://services.zsiserver.net/FinancialService.wsdl
\end_layout
\begin_layout LyX-Code
Saving soapFinancialService_USCOREBindingProxy.h client proxy
\end_layout
\begin_layout LyX-Code
Saving soapFinancialService_USCOREBindingObject.h server object
\end_layout
\begin_layout LyX-Code
Saving FinancialService_USCOREBinding.getPV.req.xml sample SOAP/XML request
\end_layout
\begin_layout LyX-Code
Saving FinancialService_USCOREBinding.getPV.res.xml sample SOAP/XML response
\end_layout
\begin_layout LyX-Code
Saving FinancialService_USCOREBinding.nsmap namespace mapping table
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Compilation successful
\end_layout
\end_deeper
\begin_layout Subsubsection
Client implementation
\end_layout
\begin_layout LyX-Code
// Contents of file "myclient_use_proxy.cpp"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
#include "soapFinancialService_USCOREBindingProxy.h"
\end_layout
\begin_layout LyX-Code
#include "FinancialService_USCOREBinding.nsmap"
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
int main()
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
FinancialService_USCOREBinding fs;
\end_layout
\begin_layout LyX-Code
_ns2__getPV getPV;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
float PV;
\end_layout
\begin_layout LyX-Code
float irate;
\end_layout
\begin_layout LyX-Code
float CFval;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
std::string input;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
while (1) {
\end_layout
\begin_layout LyX-Code
std::cout << "Enter interest rate in %: ";
\end_layout
\begin_layout LyX-Code
std::cin >> irate;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
std::vector CF;
\end_layout
\begin_layout LyX-Code
for (int t=0;; t++) {
\end_layout
\begin_layout LyX-Code
std::cout << "Enter CF(t=" << t << ")[e to exit]: ";
\end_layout
\begin_layout LyX-Code
std::cin >> input;
\end_layout
\begin_layout LyX-Code
if (input != "e") {
\end_layout
\begin_layout LyX-Code
CFval = atof(input.c_str());
\end_layout
\begin_layout LyX-Code
CF.push_back(CFval);
\end_layout
\begin_layout LyX-Code
} else {
\end_layout
\begin_layout LyX-Code
break;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
getPV.irate = irate;
\end_layout
\begin_layout LyX-Code
getPV.CFSequence.CF = CF;
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
if (fs.__ns1__getPV(&getPV, PV) == SOAP_OK) {
\end_layout
\begin_layout LyX-Code
std::cout << "PV=" << PV << std::endl;
\end_layout
\begin_layout LyX-Code
} else
\end_layout
\begin_layout LyX-Code
soap_print_fault(fs.soap, stderr);
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout Subsubsection
gSOAP Client compilation
\end_layout
\begin_layout Paragraph
gcc 2.95.2
\end_layout
\begin_layout LyX-Code
g++ -o myClient -R/apps/prod/lib -I/apps/pydev/include -L/apps/pydev/lib
soapC.cpp soapClient.cpp myClient_use_proxy.cpp -lgsoap++ -lsocket
\end_layout
\begin_layout Paragraph
gcc 3.4.4
\end_layout
\begin_layout LyX-Code
/apps/local/gcc/3.4.4//bin/g++ -o myClient -R/apps/prod/gcc/3.4.4/lib -I/apps/pydev
/gcc/3.4.4/include -L/apps/pydev/gcc/3.4.4/lib soapC.cpp soapClient.cpp myClient_use_p
roxy.cpp -lgsoap++ -lsocket -lnsl
\end_layout
\begin_layout Section
Afterthoughts
\end_layout
\begin_layout Standard
With ZSI 2.0 and even more so the upcoming 2.1 version, ZSI has made important
steps towards better usability, performance and functionality.
When the original example code base presented here was developed with ZSI
1.6.1, several patches were necessary to get everything working, and a custom
request handler was used to implement non-SOAPAction-based service dispatch.
This time, ZSI 2.0 and 2.1 handled everything out-of-the-box, with little
odds and ends.
Still on the wish-list is more verbose built-in tracing capabilities; for
the time being, it is necessary to either modify ZSI library code or to
use some network sniffer to peek at the actual XML workload (or even the
full HTTP header & body).
\end_layout
\begin_layout Standard
A weaker point of ZSI still is documentation, though some nice 3rd party
resources are available these days, notably
\begin_inset LatexCommand \cite{HobbsCookbook}
\end_inset
and
\begin_inset LatexCommand \cite{LokadTutorial}
\end_inset
.
Hopefully, this is a valuable addition to the list.
\end_layout
\begin_layout LyX-Code
\newpage
\end_layout
\begin_layout Section
\start_of_appendix
VistaSource Applixware spreadsheets as DateService clients
\begin_inset LatexCommand \label{sec:VistaSource-Applixware-spreadsheets}
\end_inset
\end_layout
\begin_layout Standard
While Applixware 4.43 does not come with built-in web services support it
is extensible with C shared libraries and its ELF macro extension language.
We can use this feature to wrap gSOAP client code, making web services
accessible from within Applix spreadsheets.
\end_layout
\begin_layout Paragraph
Note:
\end_layout
\begin_layout Standard
Example compiled with gcc 2.95.2.
A short try with gcc 3.4.4 showed some compilation errors which werenīt
\end_layout
\begin_layout Subsubsection
Code generation from WSDL
\end_layout
\begin_layout Standard
The C/C++ client stubs must be generated as described in section
\begin_inset LatexCommand \ref{sub:Code-generation-gsoap_DateService}
\end_inset
.
\end_layout
\begin_layout Subsubsection
Applix client implementation
\begin_inset LatexCommand \label{sub:Applix-client-implementation}
\end_inset
\end_layout
\begin_layout Paragraph
ELF C extension
\end_layout
\begin_layout Standard
To make the DateService callable from Applix we need to write an ELF shared
library C extension.
The
\family typewriter
ax_DateService.cpp
\family default
extension implements the gSOAP web services access:
\end_layout
\begin_layout LyX-Code
#include "elfapi.h"
\end_layout
\begin_layout LyX-Code
#include "soapDateService_USCOREBindingProxy.h"
\end_layout
\begin_layout LyX-Code
#include "DateService_USCOREBinding.nsmap"
\end_layout
\begin_layout LyX-Code
#define TRUE 1
\end_layout
\begin_layout LyX-Code
extern "C" elfData getCurrentDate();
\end_layout
\begin_layout LyX-Code
extern "C" elfData getCurrentDate_2();
\end_layout
\begin_layout LyX-Code
extern "C" elfData getDate();
\end_layout
\begin_layout LyX-Code
extern "C" elfData getDate_2();
\end_layout
\begin_layout LyX-Code
/*
\end_layout
\begin_layout LyX-Code
* Define the function table
\end_layout
\begin_layout LyX-Code
*/
\end_layout
\begin_layout LyX-Code
AxCallInfo_t funcTable[]={
\end_layout
\begin_layout LyX-Code
{ "Web Services", /* func type ...
"financial", "math" ...
*/
\end_layout
\begin_layout LyX-Code
getCurrentDate, /* The C routine to call */
\end_layout
\begin_layout LyX-Code
"getCurrentDate", /* name to use in Applixware (usually
identical to the function name) */
\end_layout
\begin_layout LyX-Code
"string getCurrentDate(string)", /* shows the function
name and its arguments */ TRUE /* An integer
that governs the treatment of ERROR and NA values,
and whether the function is displayed in the Spreadsheets
Functions dialog box.
*/
\end_layout
\begin_layout LyX-Code
},
\end_layout
\begin_layout LyX-Code
{ "Web Services", /* func type ...
"financial", "math" ...
*/
\end_layout
\begin_layout LyX-Code
getCurrentDate_2, /* The C routine to call */
\end_layout
\begin_layout LyX-Code
"getCurrentDate_2", /* name to use in Applixware
(usually identical to the function name) */
\end_layout
\begin_layout LyX-Code
"date getCurrentDate_2(string)", /* shows the function
name and its arguments */ TRUE /* An integer
that governs the treatment of ERROR and NA values,
and whether the function is displayed in the Spreadsheets
Functions dialog box.
*/
\end_layout
\begin_layout LyX-Code
},
\end_layout
\begin_layout LyX-Code
{ "Web Services", /* func type ...
"financial", "math" ...
*/
\end_layout
\begin_layout LyX-Code
getDate, /* The C routine to call */
\end_layout
\begin_layout LyX-Code
"getDate", /* name to use in Applixware (usually
identical to the function name) */
\end_layout
\begin_layout LyX-Code
"date_string getDate(int, date)", /* shows the function
name and its arguments */
\end_layout
\begin_layout LyX-Code
TRUE /* An integer that governs the treatment
of ERROR and NA values, and whether
the function is displayed in the Spreadsheets Functions dialog box.
*/
\end_layout
\begin_layout LyX-Code
},
\end_layout
\begin_layout LyX-Code
{ "Web Services", /* func type ...
"financial", "math" ...
*/
\end_layout
\begin_layout LyX-Code
getDate_2, /* The C routine to call */
\end_layout
\begin_layout LyX-Code
"getDate_2", /* name to use in Applixware (usually
identical to the function name) */
\end_layout
\begin_layout LyX-Code
"date getDate_2(int, date)", /* shows the function name
and its arguments */
\end_layout
\begin_layout LyX-Code
TRUE /* An integer that governs the treatment
of ERROR and NA values, and whether
the function is displayed in the Spreadsheets Functions dialog box.
*/
\end_layout
\begin_layout LyX-Code
},
\end_layout
\begin_layout LyX-Code
{ NULL,
\end_layout
\begin_layout LyX-Code
NULL,
\end_layout
\begin_layout LyX-Code
NULL,
\end_layout
\begin_layout LyX-Code
NULL,
\end_layout
\begin_layout LyX-Code
NULL
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
};
\end_layout
\begin_layout LyX-Code
/*
\end_layout
\begin_layout LyX-Code
* Function AxGetCallInfo returns the function table.
\end_layout
\begin_layout LyX-Code
* This function is called by Applixware when you run the macro
\end_layout
\begin_layout LyX-Code
* RPC_CONNECT@ or INSTALL_C_LIBRARY@.
This function must exist
\end_layout
\begin_layout LyX-Code
* in the RPC program or Shared Library.
\end_layout
\begin_layout LyX-Code
*/
\end_layout
\begin_layout LyX-Code
DLL_EXPORT AxCallInfo_t *AxGetCallInfo()
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
return(funcTable);
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
/*=========================================*/
\end_layout
\begin_layout LyX-Code
/* func */
\end_layout
\begin_layout LyX-Code
/*=========================================*/
\end_layout
\begin_layout LyX-Code
extern "C" elfData getCurrentDate(elfData args) /* args is an array
of arguments passed from ELF */
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
elfData arrayElem;
\end_layout
\begin_layout LyX-Code
elfData retValue;
\end_layout
\begin_layout LyX-Code
char *val;
\end_layout
\begin_layout LyX-Code
/* Check argument number & types */
\end_layout
\begin_layout LyX-Code
if (AxArraySize(args) != 1) {
\end_layout
\begin_layout LyX-Code
AxError(1, "function takes one single argument", "getCurrentDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
arrayElem = AxArrayElement(args, 0);
\end_layout
\begin_layout LyX-Code
if (!AxIsString(arrayElem)) AxError(1, "argument must be a string",
"getCurrentDate");
\end_layout
\begin_layout LyX-Code
DateService_USCOREBinding ds;
\end_layout
\begin_layout LyX-Code
ns2__Date *today;
\end_layout
\begin_layout LyX-Code
ns3__getCurrentDateResponse today_response;
\end_layout
\begin_layout LyX-Code
val = AxStrFromDataPtr(arrayElem);
\end_layout
\begin_layout LyX-Code
std::string text(val);
\end_layout
\begin_layout LyX-Code
std::string soapError = "SOAP Error";
\end_layout
\begin_layout LyX-Code
std::string result = "";
\end_layout
\begin_layout LyX-Code
if(ds.ns3__getCurrentDate(text, today_response) == SOAP_OK)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
today = today_response.today;
\end_layout
\begin_layout LyX-Code
result = *today->year
\end_layout
\begin_layout LyX-Code
+ "/" + *today->month
\end_layout
\begin_layout LyX-Code
+ "/" + *today->day
\end_layout
\begin_layout LyX-Code
+ " " + *today->hour
\end_layout
\begin_layout LyX-Code
+ ":" + *today->minute
\end_layout
\begin_layout LyX-Code
+ ":" + *today->second;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
else
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
//soap_print_fault(ds.soap, stderr); // gSOAP error
\end_layout
\begin_layout LyX-Code
soapError = "SOAP error";
\end_layout
\begin_layout LyX-Code
AxError(1, soapError.c_str(), "getCurrentDate");
\end_layout
\begin_layout LyX-Code
//AxError(1, "SOAP error", "getCurrentDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
retValue = AxMakeStrData(result.length(), result.c_str());
\end_layout
\begin_layout LyX-Code
return retValue;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
extern "C" elfData getCurrentDate_2(elfData args) /* args is an array
of arguments passed from ELF */
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
elfData arrayElem;
\end_layout
\begin_layout LyX-Code
elfData retArray;
\end_layout
\begin_layout LyX-Code
char *val;
\end_layout
\begin_layout LyX-Code
/* Check argument number & types */
\end_layout
\begin_layout LyX-Code
if (AxArraySize(args) != 1) {
\end_layout
\begin_layout LyX-Code
AxError(1, "function takes one single argument", "getCurrentDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
arrayElem = AxArrayElement(args, 0);
\end_layout
\begin_layout LyX-Code
if (!AxIsString(arrayElem)) AxError(1, "argument must be a string",
"getCurrentDate");
\end_layout
\begin_layout LyX-Code
DateService_USCOREBinding ds;
\end_layout
\begin_layout LyX-Code
ns2__Date *today;
\end_layout
\begin_layout LyX-Code
ns3__getCurrentDateResponse today_response;
\end_layout
\begin_layout LyX-Code
val = AxStrFromDataPtr(arrayElem);
\end_layout
\begin_layout LyX-Code
std::string text(val);
\end_layout
\begin_layout LyX-Code
std::string soapError = "";
\end_layout
\begin_layout LyX-Code
if(ds.ns3__getCurrentDate(text, today_response) == SOAP_OK)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
today = today_response.today;
\end_layout
\begin_layout LyX-Code
retArray = AxMakeArray(0);
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 0, atoi((*today->year).c_str()))
;
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 1, atoi((*today->month).c_str())
);
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 2, atoi((*today->day).c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 3, atoi((*today->hour).c_str()))
;
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 4, atoi((*today->minute).c_str()
));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 5, atoi((*today->second).c_str()
));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 6, atoi((*today->weekday).c_str(
)));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 7, atoi((*today->dayOfYear).c_st
r()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 8, atoi((*today->dst).c_str()));
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
else
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
//soap_print_fault(ds.soap, stderr); // gSOAP error
\end_layout
\begin_layout LyX-Code
soapError = "SOAP error";
\end_layout
\begin_layout LyX-Code
AxError(1, soapError.c_str(), "getCurrentDate");
\end_layout
\begin_layout LyX-Code
//AxError(1, "SOAP error", "getCurrentDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
return retArray;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
extern "C" elfData getDate(elfData args) /* args is an array of arguments
passed from ELF */ {
\end_layout
\begin_layout LyX-Code
elfData elf_offset, elf_date, retValue;
\end_layout
\begin_layout LyX-Code
/* Check argument number & types */
\end_layout
\begin_layout LyX-Code
if (AxArraySize(args) != 2) {
\end_layout
\begin_layout LyX-Code
AxError(1, "function takes 2 arguments", "getDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
elf_offset = AxArrayElement(args, 0);
\end_layout
\begin_layout LyX-Code
if (!AxIsInt(elf_offset)) AxError(1, "argument must be an integer",
"getDate");
\end_layout
\begin_layout LyX-Code
elf_date = AxArrayElement(args, 1);
\end_layout
\begin_layout LyX-Code
if (!AxIsArray(elf_date)) AxError(1, "argument must be an array", "getDate")
;
\end_layout
\begin_layout LyX-Code
DateService_USCOREBinding ds;
\end_layout
\begin_layout LyX-Code
//ns2__Date someday, date;
\end_layout
\begin_layout LyX-Code
ns2__Date *someday, date;
\end_layout
\begin_layout LyX-Code
ns3__getDateResponse someday_response;
\end_layout
\begin_layout LyX-Code
std::string offset(AxStrFromDataPtr(elf_offset));
\end_layout
\begin_layout LyX-Code
std::string year(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
0), 0)));
\end_layout
\begin_layout LyX-Code
std::string month(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
1), 0)));
\end_layout
\begin_layout LyX-Code
std::string day(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
2), 0)));
\end_layout
\begin_layout LyX-Code
std::string hour(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
3), 0)));
\end_layout
\begin_layout LyX-Code
std::string minute(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
4), 0)));
\end_layout
\begin_layout LyX-Code
std::string second(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
5), 0)));
\end_layout
\begin_layout LyX-Code
std::string weekday(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
6), 0)));
\end_layout
\begin_layout LyX-Code
std::string dayOfYear(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_dat
e, 7), 0)));
\end_layout
\begin_layout LyX-Code
std::string dst(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
8), 0)));
\end_layout
\begin_layout LyX-Code
date.year = &year;
\end_layout
\begin_layout LyX-Code
date.month = &month;
\end_layout
\begin_layout LyX-Code
date.day = &day;
\end_layout
\begin_layout LyX-Code
date.hour = &hour;
\end_layout
\begin_layout LyX-Code
date.minute = &minute;
\end_layout
\begin_layout LyX-Code
date.second = &second;
\end_layout
\begin_layout LyX-Code
date.weekday = &weekday;
\end_layout
\begin_layout LyX-Code
date.dayOfYear = &dayOfYear;
\end_layout
\begin_layout LyX-Code
date.dst = &dst;
\end_layout
\begin_layout LyX-Code
std::string result = "";
\end_layout
\begin_layout LyX-Code
//retValue = AxMakeStrData(offset.length(), offset.c_str());
\end_layout
\begin_layout LyX-Code
//return retValue;
\end_layout
\begin_layout LyX-Code
//std::cout << "(1) Calling 'getCurrentDate()'- Web Service method:"
<< std::endl;
\end_layout
\begin_layout LyX-Code
if(ds.ns3__getDate(offset, &date, someday_response) == SOAP_OK)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
someday = someday_response.day;
\end_layout
\begin_layout LyX-Code
//someday = *(someday_response.o_USCOREsomeday);
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
nCurrent date:" << std::endl;
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
tyear: " << *someday->year << std::endl;
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
tmonth: " << *someday->month << std::endl;
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
tday: " << *someday->day << std::endl;
\end_layout
\begin_layout LyX-Code
result = *someday->year
\end_layout
\begin_layout LyX-Code
+ "/" + *someday->month
\end_layout
\begin_layout LyX-Code
+ "/" + *someday->day
\end_layout
\begin_layout LyX-Code
+ " " + *someday->hour
\end_layout
\begin_layout LyX-Code
+ ":" + *someday->minute
\end_layout
\begin_layout LyX-Code
+ ":" + *someday->second;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
else
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
//soap_print_fault(ds.soap, stderr); // gSOAP error
\end_layout
\begin_layout LyX-Code
AxError(1, "SOAP error", "getDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
retValue = AxMakeStrData(result.length(), result.c_str());
\end_layout
\begin_layout LyX-Code
return retValue;
\end_layout
\begin_layout LyX-Code
// return retArray;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
extern "C" elfData getDate_2(elfData args) /* args is an array of arguments
passed from ELF */
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
elfData elf_offset, elf_date, retArray;
\end_layout
\begin_layout LyX-Code
/* Check argument number & types */
\end_layout
\begin_layout LyX-Code
if (AxArraySize(args) != 2) {
\end_layout
\begin_layout LyX-Code
AxError(1, "function takes 2 arguments", "getCurrentDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
elf_offset = AxArrayElement(args, 0);
\end_layout
\begin_layout LyX-Code
if (!AxIsInt(elf_offset)) AxError(1, "argument must be an integer",
"getDate");
\end_layout
\begin_layout LyX-Code
elf_date = AxArrayElement(args, 1);
\end_layout
\begin_layout LyX-Code
if (!AxIsArray(elf_date)) AxError(1, "argument must be an array", "getDate")
;
\end_layout
\begin_layout LyX-Code
DateService_USCOREBinding ds;
\end_layout
\begin_layout LyX-Code
//ns2__Date someday, date;
\end_layout
\begin_layout LyX-Code
ns2__Date *someday, date;
\end_layout
\begin_layout LyX-Code
ns3__getDateResponse someday_response;
\end_layout
\begin_layout LyX-Code
std::string offset(AxStrFromDataPtr(elf_offset));
\end_layout
\begin_layout LyX-Code
std::string year(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
0), 0)));
\end_layout
\begin_layout LyX-Code
std::string month(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
1), 0)));
\end_layout
\begin_layout LyX-Code
std::string day(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
2), 0)));
\end_layout
\begin_layout LyX-Code
std::string hour(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
3), 0)));
\end_layout
\begin_layout LyX-Code
std::string minute(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
4), 0)));
\end_layout
\begin_layout LyX-Code
std::string second(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
5), 0)));
\end_layout
\begin_layout LyX-Code
std::string weekday(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
6), 0)));
\end_layout
\begin_layout LyX-Code
std::string dayOfYear(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_dat
e, 7), 0)));
\end_layout
\begin_layout LyX-Code
std::string dst(AxStrFromDataPtr(AxArrayElement(AxArrayElement(elf_date,
8), 0)));
\end_layout
\begin_layout LyX-Code
date.year = &year;
\end_layout
\begin_layout LyX-Code
date.month = &month;
\end_layout
\begin_layout LyX-Code
date.day = &day;
\end_layout
\begin_layout LyX-Code
date.hour = &hour;
\end_layout
\begin_layout LyX-Code
date.minute = &minute;
\end_layout
\begin_layout LyX-Code
date.second = &second;
\end_layout
\begin_layout LyX-Code
date.weekday = &weekday;
\end_layout
\begin_layout LyX-Code
date.dayOfYear = &dayOfYear;
\end_layout
\begin_layout LyX-Code
date.dst = &dst;
\end_layout
\begin_layout LyX-Code
std::string result = "";
\end_layout
\begin_layout LyX-Code
int return_integer = TRUE;
\end_layout
\begin_layout LyX-Code
//std::cout << "(1) Calling 'getCurrentDate()'- Web Service method:"
<< std::endl;
\end_layout
\begin_layout LyX-Code
if(ds.ns3__getDate(offset, &date, someday_response) == SOAP_OK)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
someday = someday_response.day;
\end_layout
\begin_layout LyX-Code
//someday = *(someday_response.o_USCOREsomeday);
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
nCurrent date:" << std::endl;
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
tyear: " << *someday->year << std::endl;
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
tmonth: " << *someday->month << std::endl;
\end_layout
\begin_layout LyX-Code
// std::cout << "
\backslash
tday: " << *someday->day << std::endl;
\end_layout
\begin_layout LyX-Code
retArray = AxMakeArray(0);
\end_layout
\begin_layout LyX-Code
//std::string val;
\end_layout
\begin_layout LyX-Code
//val = *someday->year;
\end_layout
\begin_layout LyX-Code
//elfData err;
\end_layout
\begin_layout LyX-Code
//err = AxMakeStrData(val.length(), val.c_str());
\end_layout
\begin_layout LyX-Code
//AxError(1, val.c_str(), err);
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
if (return_integer == TRUE)
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 0, atoi((*someday->year
).c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 1, atoi((*someday->mont
h).c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 2, atoi((*someday->day).
c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 3, atoi((*someday->hour
).c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 4, atoi((*someday->minu
te).c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 5, atoi((*someday->seco
nd).c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 6, atoi((*someday->week
day).c_str()));
\end_layout
\begin_layout LyX-Code
retArray = AxAddIntToArray(retArray, 7, atoi((*someday->dayO
fYear).c_str())); retArray = AxAddIntToArray(retArray,
8, atoi((*someday->dst).c_str()));
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
else
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 0, (*someday->year).c_st
r());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 1, (*someday->month).c_s
tr());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 2, (*someday->day).c_str
());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 3, (*someday->hour).c_st
r());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 4, (*someday->minute).c_
str());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 5, (*someday->second).c_
str());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 6, (*someday->weekday).c
_str());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 7, (*someday->dayOfYear
).c_str());
\end_layout
\begin_layout LyX-Code
retArray = AxAddStrToArray(retArray, 8, (*someday->dst).c_str
());
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
//result = *someday->year + "/" + *someday->month + "/" + *someday->
day;
\end_layout
\begin_layout LyX-Code
//result = *(someday.year) + "/" + *(someday.month) + "/" + *(someday.d
ay);
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
else
\end_layout
\begin_layout LyX-Code
{
\end_layout
\begin_layout LyX-Code
//soap_print_fault(ds.soap, stderr); // gSOAP error
\end_layout
\begin_layout LyX-Code
AxError(1, "SOAP error", "getCurrentDate");
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
//retValue = AxMakeStrData(result.length(), result.c_str());
\end_layout
\begin_layout LyX-Code
//return retValue;
\end_layout
\begin_layout LyX-Code
return retArray;
\end_layout
\begin_layout LyX-Code
}
\end_layout
\begin_layout Standard
The code above implements the following functions:
\end_layout
\begin_layout Itemize
getCurrentDate: Return a string containing the current date.
Takes a string argument.
\end_layout
\begin_layout Itemize
getCurrentDate_2: Return the current date as an array.
Takes a string argument.
\end_layout
\begin_layout Itemize
getDate: Return the input date + offset as a string.
Takes an integer offset and a 9-element date array as arguments.
\end_layout
\begin_layout Itemize
getDate_2: Return input date + offset as an array.
Takes an integer offset and a 9-element date array as arguments.
\end_layout
\begin_layout Standard
To compile the code, you have to add the Applix ELF headers to the include
path:
\end_layout
\begin_layout LyX-Code
g++ -shared -o ax_DateService.so -R/apps/prod/lib
\end_layout
\begin_layout LyX-Code
-I/apps/prod/applix/applix/versions/4.43.1021.544.343/axdata/elf
\end_layout
\begin_layout LyX-Code
-I/apps/pydev/include -L/apps/pydev/lib soapC.cpp soap ax_DateService.cpp
\end_layout
\begin_layout LyX-Code
-lgsoap++ -lsocket
\end_layout
\begin_layout Standard
The resulting shared library
\family typewriter
ax_DateService.so
\family default
must be loaded into Applix before it can be used.
This is done with the
\family typewriter
install_c_library@()
\family default
macro:
\end_layout
\begin_layout LyX-Code
#define path "/data/pydev/WebServicesPresentation/DateService_rpc_literal/Applix
/"
\end_layout
\begin_layout LyX-Code
macro load()
\end_layout
\begin_layout LyX-Code
install_c_library@(path++"ax_DateService.so")
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
macro unload()
\end_layout
\begin_layout LyX-Code
unbind_c_library@(path++"ax_DateService.so")
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
macro reload()
\end_layout
\begin_layout LyX-Code
unbind_c_library@(path++"ax_DateService.so")
\end_layout
\begin_layout LyX-Code
install_c_library@(path++"ax_DateService.so")
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout Standard
After the shared library has been dynamically loaded, the functions can
be used like built-in functions inside the spreadsheet.
To make sensible use of the
\family typewriter
getDate_2
\family default
function which returns the date struct as an array, you have to invoke
it as an array function:
\begin_inset Foot
status open
\begin_layout Standard
Compare to section
\begin_inset LatexCommand \ref{sub:VB-client-implementation-DateService}
\end_inset
.
\end_layout
\end_inset
\end_layout
\begin_layout Enumerate
Select an array with the appropriate number of cells (9 cells, one-dimensional
in our case).
\end_layout
\begin_layout Enumerate
Enter the function call, e.g.:
\end_layout
\begin_deeper
\begin_layout LyX-Code
=getDate_2(offset_5, someday_5)
\end_layout
\end_deeper
\begin_layout Enumerate
Press CTRL-SHIFT-ENTER to insert the formula as array function.
\end_layout
\begin_layout Standard
The actual extension function calls might also be wrapped into additional
macro code.
This makes it possible to invoke the functions from command buttons or
to populate predefined, hardcoded result ranges with the results of a service
call.
Compared to Excel, an additional possibility for Applix is the definition
of an extra argument for the output range
\emph on
name
\emph default
(as a string).
Given the name, this range can then be filled with the result value structure,
removing the need to hardcode range names in the macro code.
\begin_inset Foot
status open
\begin_layout Standard
In Applix, macros can be called from spreadsheet cells but places restrictions
on modifying spreadsheet cells from within a macro.
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The following macro code show some of the possibilities.
Refer to the code comments for explanations:
\end_layout
\begin_layout LyX-Code
#include "spsheet_.am"
\end_layout
\begin_layout LyX-Code
/*
\end_layout
\begin_layout LyX-Code
* Macros for Web Service getCurrentDate()
\end_layout
\begin_layout LyX-Code
*/
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
/* <<<< getCurrentDate_Macro >>>>> */
\end_layout
\begin_layout LyX-Code
' --> Returning ASCII string
\end_layout
\begin_layout LyX-Code
' --> called from within a cell
\end_layout
\begin_layout LyX-Code
' --> providing an input parameter
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Macro getCurrentDate_Macro(text)
\end_layout
\begin_layout LyX-Code
var retStr
\end_layout
\begin_layout LyX-Code
/* Web Service call */
\end_layout
\begin_layout LyX-Code
retStr = getCurrentDate(text)
\end_layout
\begin_layout LyX-Code
return(retStr)
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
/* <<<<<<<<<<<<< END >>>>>>>>>>>>>*/
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
/* <<<< getCurrentDate_2_Macro >>>>> */
\end_layout
\begin_layout LyX-Code
' --> no return value: returning ASCII string with population
\end_layout
\begin_layout LyX-Code
' --> called by Buttons
\end_layout
\begin_layout LyX-Code
' --> no input parameter possible
\end_layout
\begin_layout LyX-Code
' --> hard-coded input-parameter'
\end_layout
\begin_layout LyX-Code
' --> hard coded named range for result population
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Macro getCurrentDate_2_Macro()
\end_layout
\begin_layout LyX-Code
var format ss_cell_ cellInfo
\end_layout
\begin_layout LyX-Code
var celladdr, cell
\end_layout
\begin_layout LyX-Code
var retStr, text
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("input_3")
\end_layout
\begin_layout LyX-Code
cellInfo = ss_get_cell@(cellAddr[0], cellAddr[1], 0)
\end_layout
\begin_layout LyX-Code
text=cellInfo.display_str
\end_layout
\begin_layout LyX-Code
/* Web Service call */
\end_layout
\begin_layout LyX-Code
retStr = getCurrentDate(text)
\end_layout
\begin_layout LyX-Code
/* Result Population */
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("today_1")
\end_layout
\begin_layout LyX-Code
ss_put_cell@(ss_coordinate@(cellAddr[0], cellAddr[1], 0), retStr)
\end_layout
\begin_layout LyX-Code
'Alternativ
\end_layout
\begin_layout LyX-Code
'cell=ss_coordinate@(cellAddr[0], cellAddr[1], 0)
\end_layout
\begin_layout LyX-Code
'new_task@("ss_put_cell@", cell, retStr)
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
/* <<<<<<<<<<<<< END >>>>>>>>>>>>>*/
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
/* <<<< getCurrentDate_3_Macro >>>>> */
\end_layout
\begin_layout LyX-Code
' --> no return value: returning date array with population
\end_layout
\begin_layout LyX-Code
' --> called by cell
\end_layout
\begin_layout LyX-Code
' --> input parameter for result population
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Macro getCurrentDate_3_Macro(text, today)
\end_layout
\begin_layout LyX-Code
'for parameter today the name (string) of a named range has to be passed,
not the named
\end_layout
\begin_layout LyX-Code
' ranged object by itself --> this would pass an array to the macro, where
the
\end_layout
\begin_layout LyX-Code
'content of the named range is provided.
But we need the coordinates of the cells of the
\end_layout
\begin_layout LyX-Code
'named range
\end_layout
\begin_layout LyX-Code
var format ss_cell_ cellInfo
\end_layout
\begin_layout LyX-Code
var celladdr, cell
\end_layout
\begin_layout LyX-Code
var retStr, date, rowStart, rowEnd, col
\end_layout
\begin_layout LyX-Code
var k, i
\end_layout
\begin_layout LyX-Code
/* Web Service call */
\end_layout
\begin_layout LyX-Code
date = getCurrentDate_2(text)
\end_layout
\begin_layout LyX-Code
/* Result Population */
\end_layout
\begin_layout LyX-Code
'cellAddr = ss_extract_range_info@("today")
\end_layout
\begin_layout LyX-Code
' --> hardcoded if no parameter is allowed
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@(today)
\end_layout
\begin_layout LyX-Code
' --> not possible to get named range as parameter for result because
\end_layout
\begin_layout LyX-Code
' the content of the named range is used by APPLIX NOT THE COORDINATES
\end_layout
\begin_layout LyX-Code
rowStart=cellAddr[1]
\end_layout
\begin_layout LyX-Code
rowEnd=cellAddr[3]
\end_layout
\begin_layout LyX-Code
col=cellAddr[2]
\end_layout
\begin_layout LyX-Code
k=0
\end_layout
\begin_layout LyX-Code
for i=rowStart to rowEnd
\end_layout
\begin_layout LyX-Code
cellInfo= ss_get_cell@(col, i, 0)
\end_layout
\begin_layout LyX-Code
'date[k]= { cellInfo.display_str+0 }
\end_layout
\begin_layout LyX-Code
'ss_put_cell@(ss_coordinate@(cellAddr[col], cellAddr[i], 0), date[k])
\end_layout
\begin_layout LyX-Code
'Alternativ
\end_layout
\begin_layout LyX-Code
cell=ss_coordinate@(col, i, 0)
\end_layout
\begin_layout LyX-Code
new_task@("ss_put_cell@", cell, date[k])
\end_layout
\begin_layout LyX-Code
'ss_put_cell@(col,i,date[k])
\end_layout
\begin_layout LyX-Code
k=k+1
\end_layout
\begin_layout LyX-Code
next i
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
/* <<<<<<<<<<<<< END >>>>>>>>>>>>>*/
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
/*
\end_layout
\begin_layout LyX-Code
* Macros for Web Service getDate()
\end_layout
\begin_layout LyX-Code
*/
\end_layout
\begin_layout LyX-Code
/* <<<< getDate_Macro >>>>> */
\end_layout
\begin_layout LyX-Code
' --> Returning ASCII string
\end_layout
\begin_layout LyX-Code
' --> called from within a cell
\end_layout
\begin_layout LyX-Code
' --> providing input parameter
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Macro getDate_macro(offset, someday)
\end_layout
\begin_layout LyX-Code
var retStr, date
\end_layout
\begin_layout LyX-Code
date=someday
\end_layout
\begin_layout LyX-Code
/* Web Service call */
\end_layout
\begin_layout LyX-Code
retStr = getDate(offset, date)
\end_layout
\begin_layout LyX-Code
return(retStr)
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
/* <<<<<<<<<<<<< END >>>>>>>>>>>>>*/
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
/* <<<< getDate_1_Macro >>>>> */
\end_layout
\begin_layout LyX-Code
' --> Not used
\end_layout
\begin_layout LyX-Code
' --> no return value: returning ASCII string with population
\end_layout
\begin_layout LyX-Code
' --> called by Buttons or from within a cell
\end_layout
\begin_layout LyX-Code
' --> no input parameter possible
\end_layout
\begin_layout LyX-Code
' --> hard-coded input-parameter'
\end_layout
\begin_layout LyX-Code
' --> hard coded named range for result population
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Macro getDate_1_macro()
\end_layout
\begin_layout LyX-Code
var format ss_cell_ cellInfo
\end_layout
\begin_layout LyX-Code
var retStr, offset, date, rowStart, rowEnd, col
\end_layout
\begin_layout LyX-Code
var cellAddr, k, i, cell
\end_layout
\begin_layout LyX-Code
/* Preparing Web Service input parameter */
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("offset")
\end_layout
\begin_layout LyX-Code
cellInfo = ss_get_cell@(cellAddr[0], cellAddr[1], 0)
\end_layout
\begin_layout LyX-Code
offset=cellInfo.display_str+0
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("someday")
\end_layout
\begin_layout LyX-Code
rowStart=cellAddr[1]
\end_layout
\begin_layout LyX-Code
rowEnd=cellAddr[3]
\end_layout
\begin_layout LyX-Code
col=cellAddr[2]
\end_layout
\begin_layout LyX-Code
k=0
\end_layout
\begin_layout LyX-Code
for i=rowStart to rowEnd
\end_layout
\begin_layout LyX-Code
cellInfo= ss_get_cell@(col, i, 0)
\end_layout
\begin_layout LyX-Code
date[k]= { cellInfo.display_str+0 }
\end_layout
\begin_layout LyX-Code
k=k+1
\end_layout
\begin_layout LyX-Code
next i
\end_layout
\begin_layout LyX-Code
/* Web Service call */
\end_layout
\begin_layout LyX-Code
retStr = getDate(offset, date)
\end_layout
\begin_layout LyX-Code
/* Result Population */
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("result_macro1")
\end_layout
\begin_layout LyX-Code
/* Gilt fuer Start des Makros ueber Button */
\end_layout
\begin_layout LyX-Code
' ss_put_cell@(ss_coordinate@(cellAddr[0], cellAddr[1], 0), retStr)
\end_layout
\begin_layout LyX-Code
/* Gilt fuer Start des Makros in einer Zelle */
\end_layout
\begin_layout LyX-Code
cell=ss_coordinate@(cellAddr[0], cellAddr[1], 0)
\end_layout
\begin_layout LyX-Code
'cell="A:E12"
\end_layout
\begin_layout LyX-Code
new_task@("ss_put_cell@", cell, retStr)
\end_layout
\begin_layout LyX-Code
return(retStr)
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
/* <<<<<<<<<<<<< END >>>>>>>>>>>>>*/
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
/* <<<< getDate_2_Macro >>>>> */
\end_layout
\begin_layout LyX-Code
' --> no return value: returning date array with population
\end_layout
\begin_layout LyX-Code
' --> called by Buttons
\end_layout
\begin_layout LyX-Code
' --> no input parameter possible
\end_layout
\begin_layout LyX-Code
' --> hard-coded input-parameter'
\end_layout
\begin_layout LyX-Code
' --> hard coded named range for result population
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
Macro getDate_2_macro()
\end_layout
\begin_layout LyX-Code
var format ss_cell_ cellInfo
\end_layout
\begin_layout LyX-Code
var celladdr, cell
\end_layout
\begin_layout LyX-Code
var date, rowStart, rowEnd, col
\end_layout
\begin_layout LyX-Code
var k, i
\end_layout
\begin_layout LyX-Code
var offset, someday
\end_layout
\begin_layout LyX-Code
/* Perparing Web Service input parameter */
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("offset_3")
\end_layout
\begin_layout LyX-Code
cellInfo = ss_get_cell@(cellAddr[0], cellAddr[1], 0)
\end_layout
\begin_layout LyX-Code
'offset=cellInfo.display_str + 0
\end_layout
\begin_layout LyX-Code
offset=cellInfo.value
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("someday_3")
\end_layout
\begin_layout LyX-Code
rowStart=cellAddr[1]
\end_layout
\begin_layout LyX-Code
rowEnd=cellAddr[3]
\end_layout
\begin_layout LyX-Code
col=cellAddr[2]
\end_layout
\begin_layout LyX-Code
k=0
\end_layout
\begin_layout LyX-Code
for i=rowStart to rowEnd
\end_layout
\begin_layout LyX-Code
cellInfo = ss_get_cell@(col, i, 0)
\end_layout
\begin_layout LyX-Code
someday[k] = {cellInfo.value}
\end_layout
\begin_layout LyX-Code
'someday[k]=ss_coordinate@(col, i, 0)
\end_layout
\begin_layout LyX-Code
'new_task@("ss_put_cell@", cell, date[k])
\end_layout
\begin_layout LyX-Code
'ss_put_cell@(col,i,date[k]) --> not working
\end_layout
\begin_layout LyX-Code
k=k+1
\end_layout
\begin_layout LyX-Code
next i
\end_layout
\begin_layout LyX-Code
'DUMP_ARRAY@(someday)
\end_layout
\begin_layout LyX-Code
/* Web Serviuce call */
\end_layout
\begin_layout LyX-Code
date = getDate_2(offset, someday)
\end_layout
\begin_layout LyX-Code
/* Result Population */
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@("day_1")
\end_layout
\begin_layout LyX-Code
' --> not possible to get named range as parameter for result because
\end_layout
\begin_layout LyX-Code
' the content of the named range is used by APPLIX NOT THE COORDINATES
\end_layout
\begin_layout LyX-Code
rowStart=cellAddr[1]
\end_layout
\begin_layout LyX-Code
rowEnd=cellAddr[3]
\end_layout
\begin_layout LyX-Code
col=cellAddr[2]
\end_layout
\begin_layout LyX-Code
k=0
\end_layout
\begin_layout LyX-Code
for i=rowStart to rowEnd
\end_layout
\begin_layout LyX-Code
cell=ss_coordinate@(col, i, 0)
\end_layout
\begin_layout LyX-Code
new_task@("ss_put_cell@", cell, date[k])
\end_layout
\begin_layout LyX-Code
'ss_put_cell@(col,i,date[k]) --> not working
\end_layout
\begin_layout LyX-Code
k=k+1
\end_layout
\begin_layout LyX-Code
next i
\end_layout
\begin_layout LyX-Code
/*
\end_layout
\begin_layout LyX-Code
* DUMP_ARRAY@(retStruct)
\end_layout
\begin_layout LyX-Code
*/
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
/* <<<<<<<<<<<<< END >>>>>>>>>>>>>*/
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
/* <<<< getDate_3_Macro >>>>> */
\end_layout
\begin_layout LyX-Code
' --> no return value: returning date array with population
\end_layout
\begin_layout LyX-Code
' --> called by cells
\end_layout
\begin_layout LyX-Code
' --> input parameter for WebService call
\end_layout
\begin_layout LyX-Code
' --> named range input-parameter for result population
\end_layout
\begin_layout LyX-Code
'
\end_layout
\begin_layout LyX-Code
Macro getDate_3_macro(offset, someday, day)
\end_layout
\begin_layout LyX-Code
var format ss_cell_ cellInfo
\end_layout
\begin_layout LyX-Code
var celladdr, cell
\end_layout
\begin_layout LyX-Code
var date, rowStart, rowEnd, col
\end_layout
\begin_layout LyX-Code
var k, i
\end_layout
\begin_layout LyX-Code
/* Preparation Web Service input parameter not necessary --> provided by
call */
\end_layout
\begin_layout LyX-Code
/* Web Service call */
\end_layout
\begin_layout LyX-Code
date = getDate_2(offset, someday)
\end_layout
\begin_layout LyX-Code
/* Result Population */
\end_layout
\begin_layout LyX-Code
'cellAddr = ss_extract_range_info@("day")
\end_layout
\begin_layout LyX-Code
' --> hardcoded if no parameter is allowed
\end_layout
\begin_layout LyX-Code
cellAddr = ss_extract_range_info@(day)
\end_layout
\begin_layout LyX-Code
' --> not possible to get named range as parameter for result because
\end_layout
\begin_layout LyX-Code
' the content of the named range is used by APPLIX NOT THE COORDINATES
\end_layout
\begin_layout LyX-Code
rowStart=cellAddr[1]
\end_layout
\begin_layout LyX-Code
rowEnd=cellAddr[3]
\end_layout
\begin_layout LyX-Code
col=cellAddr[2]
\end_layout
\begin_layout LyX-Code
k=0
\end_layout
\begin_layout LyX-Code
for i=rowStart to rowEnd
\end_layout
\begin_layout LyX-Code
cell=ss_coordinate@(col, i, 0)
\end_layout
\begin_layout LyX-Code
new_task@("ss_put_cell@", cell, date[k])
\end_layout
\begin_layout LyX-Code
'ss_put_cell@(col,i,date[k]) --> not working
\end_layout
\begin_layout LyX-Code
k=k+1
\end_layout
\begin_layout LyX-Code
next i
\end_layout
\begin_layout LyX-Code
/*
\end_layout
\begin_layout LyX-Code
* DUMP_ARRAY@(retStruct)
\end_layout
\begin_layout LyX-Code
*/
\end_layout
\begin_layout LyX-Code
endmacro
\end_layout
\begin_layout LyX-Code
/* <<<<<<<<<<<<< END >>>>>>>>>>>>>*/
\end_layout
\begin_layout Section
ZSI tracing hacks
\begin_inset LatexCommand \label{sec:ZSI-hack}
\end_inset
\end_layout
\begin_layout Standard
Warning: These are more-or-less nifty recipees to inject some functionality
to ZSI with regard to logging/debugging.
Not tested beyond what you see here.
\end_layout
\begin_layout Subsection
Detailed method call tracing
\begin_inset LatexCommand \label{sub:Detailed-method-call-tracing}
\end_inset
\end_layout
\begin_layout Standard
If something goes wrong with answering a service request in a ZSI server
and you do not know why this is, sometimes ZSIīs fault exception message
is just not enough to get a clue.
As the current ZSI versions do not allow you to output more detailed call
stack information, hereīs a helper module
\family typewriter
inject_tracing.py
\family default
to inject desired functionality into ZSI:
\end_layout
\begin_layout LyX-Code
import types
\end_layout
\begin_layout LyX-Code
# Based on "Method enhancement" Python cookbook recipee by Ken Seehof
\end_layout
\begin_layout LyX-Code
# (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81982)}
\end_layout
\begin_layout LyX-Code
def enhance_method(cls, methodname, decorate):
\end_layout
\begin_layout LyX-Code
'replace a method with an enhancement'
\end_layout
\begin_layout LyX-Code
method = getattr(cls, methodname)
\end_layout
\begin_layout LyX-Code
_f = decorate(method)
\end_layout
\begin_layout LyX-Code
setattr(cls, methodname, types.MethodType(_f, None, cls))
\end_layout
\begin_layout LyX-Code
# loop over class dict and call enhance_method() function
\end_layout
\begin_layout LyX-Code
# for all methods to modify
\end_layout
\begin_layout LyX-Code
def enhance_all_methods(cls, decorate):
\end_layout
\begin_layout LyX-Code
for methodname in cls.__dict__:
\end_layout
\begin_layout LyX-Code
if not methodname.startswith("__")
\backslash
\end_layout
\begin_layout LyX-Code
or methodname in ["__call__", "__call___"]:
\end_layout
\begin_layout LyX-Code
method = getattr(cls, methodname)
\end_layout
\begin_layout LyX-Code
if isinstance(method, types.MethodType):
\end_layout
\begin_layout LyX-Code
enhance_method(cls, methodname, decorate)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def traced(enter_text="-->", leave_text="<--"):
\end_layout
\begin_layout LyX-Code
"""Configurable Function decorator.
\end_layout
\begin_layout LyX-Code
Outputs the text given as enter_text plus the function name and arguments
\end_layout
\begin_layout LyX-Code
before entering the decorated function, and the leave_text string after
\end_layout
\begin_layout LyX-Code
having left the decorated function.
\end_layout
\begin_layout LyX-Code
Example:
\end_layout
\begin_layout LyX-Code
>>> @traced("into", "out of")
\end_layout
\begin_layout LyX-Code
...
def foo(x,y):
\end_layout
\begin_layout LyX-Code
...
print x,y
\end_layout
\begin_layout LyX-Code
...
return x
\end_layout
\begin_layout LyX-Code
...
\end_layout
\begin_layout LyX-Code
>>> foo(1, 2)
\end_layout
\begin_layout LyX-Code
into foo(args=(1, 2), kwargs={})
\end_layout
\begin_layout LyX-Code
1 2
\end_layout
\begin_layout LyX-Code
out of foo()
\end_layout
\begin_layout LyX-Code
1
\end_layout
\begin_layout LyX-Code
>>>
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
def traced(f):
\end_layout
\begin_layout LyX-Code
_f = f
\end_layout
\begin_layout LyX-Code
def f(*args, **kwargs):
\end_layout
\begin_layout LyX-Code
print enter_text, "%s(args=%s, kwargs=%s)" % (_f.__name__, args,
\end_layout
\begin_layout LyX-Code
kwargs)
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
return _f(*args, **kwargs)
\end_layout
\begin_layout LyX-Code
finally:
\end_layout
\begin_layout LyX-Code
print leave_text, "%s()" % (_f.__name__)
\end_layout
\begin_layout LyX-Code
f.__name__ = _f.__name__
\end_layout
\begin_layout LyX-Code
return f
\end_layout
\begin_layout LyX-Code
return traced
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def enhance_module(module, decorator=traced, names=[]):
\end_layout
\begin_layout LyX-Code
"""Wrap module class methods and callables with given decorator.
Applies
\end_layout
\begin_layout LyX-Code
to list of names only, if given, otherwise to all detected
\end_layout
\begin_layout LyX-Code
methods/callables.
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
for objname, obj in module.__dict__.items():
\end_layout
\begin_layout LyX-Code
if not names or objname in names:
\end_layout
\begin_layout LyX-Code
if isinstance(obj, (type, types.ClassType)):
\end_layout
\begin_layout LyX-Code
#print obj
\end_layout
\begin_layout LyX-Code
enhance_all_methods(obj, decorator())
\end_layout
\begin_layout LyX-Code
elif callable(obj):
\end_layout
\begin_layout LyX-Code
#print obj
\end_layout
\begin_layout LyX-Code
module.__dict__[objname] = decorator()(obj)
\end_layout
\begin_layout Standard
The FinancialService server implementation from section
\begin_inset LatexCommand \ref{sub:Python-ZSI-FinancialService-server}
\end_inset
can be modified like this to make use of it:
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the ZSI stuff you'd need no matter what
\end_layout
\begin_layout LyX-Code
from ZSI.wstools import logging
\end_layout
\begin_layout LyX-Code
from ZSI import ServiceContainer
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
# 2.1alpha
\end_layout
\begin_layout LyX-Code
from FinancialService_server import *
\end_layout
\begin_layout LyX-Code
# Dummy implementation
\end_layout
\begin_layout LyX-Code
def adapt(method):
\end_layout
\begin_layout LyX-Code
return method
\end_layout
\begin_layout LyX-Code
except ImportError, e:
\end_layout
\begin_layout LyX-Code
# 2.0final
\end_layout
\begin_layout LyX-Code
from FinancialService_services_server import *
\end_layout
\begin_layout LyX-Code
from service_adaptor import ServiceAdaptor21
\end_layout
\begin_layout LyX-Code
adapt = ServiceAdaptor21.adapt
\end_layout
\begin_layout LyX-Code
# Wrap generated 2.0 class to 2.1 soap_ method behaviour
\end_layout
\begin_layout LyX-Code
FinancialService = ServiceAdaptor21(FinancialService)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Create a Server implementation by inheritance
\end_layout
\begin_layout LyX-Code
# 2.1alpha implementation
\end_layout
\begin_layout LyX-Code
class MyFinancialService(FinancialService):
\end_layout
\begin_layout LyX-Code
# Make WSDL available for HTTP GET
\end_layout
\begin_layout LyX-Code
_wsdl = "".join(open("FinancialService.wsdl").readlines())
\end_layout
\begin_layout LyX-Code
@adapt
\end_layout
\begin_layout LyX-Code
def soap_getPV(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = FinancialService.soap_getPV(self, ps, **kw)
\end_layout
\begin_layout LyX-Code
# Comment that out if need be to see what API these objects offer:
\end_layout
\begin_layout LyX-Code
#print help(request)
\end_layout
\begin_layout LyX-Code
#print help(response)
\end_layout
\begin_layout LyX-Code
# Using getters/setters
\end_layout
\begin_layout LyX-Code
irate = request.get_element_irate()
\end_layout
\begin_layout LyX-Code
CFs = request.get_element_CFSequence().get_element_CF()
\end_layout
\begin_layout LyX-Code
# Alternative way to access the input data
\end_layout
\begin_layout LyX-Code
#irate = request._irate
\end_layout
\begin_layout LyX-Code
#CFs = request._CFSequence._CF
\end_layout
\begin_layout LyX-Code
# Invoke the service worker code
\end_layout
\begin_layout LyX-Code
PV = self.getPV(irate, CFs)
\end_layout
\begin_layout LyX-Code
#print "PV:", PV
\end_layout
\begin_layout LyX-Code
# assign return value to response object
\end_layout
\begin_layout LyX-Code
response = getPVResponse(PV)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Another way to create a serializable response object
\end_layout
\begin_layout LyX-Code
#class SimpleTypeWrapper(float):
\end_layout
\begin_layout LyX-Code
# typecode = response.typecode
\end_layout
\begin_layout LyX-Code
#response = SimpleTypeWrapper(PV)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def getPV(self, irate, cashFlows):
\end_layout
\begin_layout LyX-Code
# worker code method
\end_layout
\begin_layout LyX-Code
t = 0
\end_layout
\begin_layout LyX-Code
PV = 0.0
\end_layout
\begin_layout LyX-Code
for CF in cashFlows:
\end_layout
\begin_layout LyX-Code
PV += (CF or 0.0) * ((irate / 100.0 + 1) ** (-t))
\end_layout
\begin_layout LyX-Code
t += 1
\end_layout
\begin_layout LyX-Code
return PV
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-l", "--loglevel", help="loglevel (DEBUG, WARN)",
\end_layout
\begin_layout LyX-Code
metavar="LOGLEVEL")
\end_layout
\begin_layout LyX-Code
op.add_option("-p", "--port", help="HTTP port",
\end_layout
\begin_layout LyX-Code
metavar="PORT", default=8080, type="int")
\end_layout
\begin_layout LyX-Code
op.add_option("-t", "--trace", help="trace function/method calls",
\end_layout
\begin_layout LyX-Code
action="store_true")
\end_layout
\begin_layout LyX-Code
op.add_option("-n", "--names", help="trace function/method names",
\end_layout
\begin_layout LyX-Code
metavar="NAME", action="append")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
if options.trace:
\end_layout
\begin_layout LyX-Code
from ZSI import parse
\end_layout
\begin_layout LyX-Code
from inject_tracing import enhance_module
\end_layout
\begin_layout LyX-Code
enhance_module(ServiceContainer, names=options.names)
\end_layout
\begin_layout LyX-Code
enhance_module(parse, names=options.names)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# set the loglevel according to cmd line arg
\end_layout
\begin_layout LyX-Code
if options.loglevel:
\end_layout
\begin_layout LyX-Code
loglevel = eval(options.loglevel, logging.__dict__)
\end_layout
\begin_layout LyX-Code
logger = logging.getLogger("")
\end_layout
\begin_layout LyX-Code
logger.setLevel(loglevel)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Run the server with a given list of services
\end_layout
\begin_layout LyX-Code
ServiceContainer.AsServer(port=options.port, services=[MyFinancialService(),])
\end_layout
\begin_layout Standard
This will print way more tracing output for incoming service requests:
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/hjoukl/bin/python2.4 ./myTracedFinancialServer.py -t
\end_layout
\begin_layout LyX-Code
*** ZSI version (2, 1, 0) ***
\end_layout
\begin_layout LyX-Code
--> AsServer(args=(), kwargs={'services': [<__main__.MyFinancialService instance
at 0x4c3558>], 'port': 8080})
\end_layout
\begin_layout LyX-Code
--> server_bind(args=(
,), kwargs={}) <-- server_bind()
\end_layout
\begin_layout LyX-Code
--> setNode(args=(,
<__main__.MyFinancialService instance at 0x4c3558>), kwargs={})
\end_layout
\begin_layout LyX-Code
--> getPost(args=(<__main__.MyFinancialService instance at 0x4c3558>,), kwargs={}
)
\end_layout
\begin_layout LyX-Code
<-- getPost()
\end_layout
\begin_layout LyX-Code
<-- setNode()
\end_layout
\begin_layout LyX-Code
--> handle(args=(,),
kwargs={})
\end_layout
\begin_layout LyX-Code
--> handle_one_request(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
--> parse_request(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- parse_request()
\end_layout
\begin_layout LyX-Code
--> do_POST(args=(,)
, kwargs={})
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> _check_for_legal_children(args=(,
'Envelope', ), kwargs={})
\end_layout
\begin_layout LyX-Code
--> _check_for_legal_children(args=(,
'Envelope', ), kwargs={})
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
<-- _check_for_legal_children()
\end_layout
\begin_layout LyX-Code
<-- _check_for_legal_children()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> _valid_encoding(args=(,),
kwargs={})
\end_layout
\begin_layout LyX-Code
<-- _valid_encoding()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> _check_for_legal_children(args=(,
'Body', , 0), kwargs={})
\end_layout
\begin_layout LyX-Code
--> _check_for_legal_children(args=(,
'Body', , 0), kwargs={})
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
<-- _check_for_legal_children()
\end_layout
\begin_layout LyX-Code
<-- _check_for_legal_children()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> _check_for_pi_nodes(args=(,
[], 0), kwargs={})
\end_layout
\begin_layout LyX-Code
--> _check_for_pi_nodes(args=(,
[], 0), kwargs={})
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
<-- _check_for_pi_nodes()
\end_layout
\begin_layout LyX-Code
<-- _check_for_pi_nodes()
\end_layout
\begin_layout LyX-Code
--> _valid_encoding(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- _valid_encoding()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> _valid_encoding(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- _valid_encoding()
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
--> _check_for_pi_nodes(args=(,
[], 0), kwargs={})
\end_layout
\begin_layout LyX-Code
--> _check_for_pi_nodes(args=(,
[], 0), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- _check_for_pi_nodes()
\end_layout
\begin_layout LyX-Code
<-- _check_for_pi_nodes()
\end_layout
\begin_layout LyX-Code
--> _Dispatch(args=(, , >, >), kwargs={'action': '', 'post': '/FinancialService'})
\end_layout
\begin_layout LyX-Code
--> getNode(args=(,
'/FinancialService'), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- getNode()
\end_layout
\begin_layout LyX-Code
--> authorize(args=(<__main__.MyFinancialService instance at 0x4c3558>, None,
'/FinancialService', ''), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- authorize()
\end_layout
\begin_layout LyX-Code
--> getOperation(args=(<__main__.MyFinancialService instance at 0x4c3558>,
, ''), kwargs={})
\end_layout
\begin_layout LyX-Code
--> getOperationName(args=(<__main__.MyFinancialService instance at 0x4c3558>,
, ''), kwargs={})
\end_layout
\begin_layout LyX-Code
--> (args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- ()
\end_layout
\begin_layout LyX-Code
<-- getOperationName()
\end_layout
\begin_layout LyX-Code
<-- getOperation()
\end_layout
\begin_layout LyX-Code
--> Parse(args=(, ), kwargs={})
\end_layout
\begin_layout LyX-Code
--> Parse(args=(, ), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- Parse()
\end_layout
\begin_layout LyX-Code
<-- Parse()
\end_layout
\begin_layout LyX-Code
--> verify(args=(<__main__.MyFinancialService instance at 0x4c3558>, ), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- verify()
\end_layout
\begin_layout LyX-Code
--> serialize(args=(, 0.934579439252331
67), kwargs={})
\end_layout
\begin_layout LyX-Code
--> writeNSdict(args=(, {}), kwargs={}
)
\end_layout
\begin_layout LyX-Code
<-- writeNSdict()
\end_layout
\begin_layout LyX-Code
<-- serialize()
\end_layout
\begin_layout LyX-Code
--> sign(args=(<__main__.MyFinancialService instance at 0x4c3558>, ), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- sign()
\end_layout
\begin_layout LyX-Code
--> close(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- close()
\end_layout
\begin_layout LyX-Code
--> send_xml(args=(,
\end_layout
\begin_layout LyX-Code
'
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
0.934579
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
'), kwargs={})
\end_layout
\begin_layout LyX-Code
--> send_response(args=(, 200), kwargs={})
\end_layout
\begin_layout LyX-Code
--> log_request(args=(, 200), kwargs={})
\end_layout
\begin_layout LyX-Code
--> log_message(args=(, '"%s" %s %s', 'POST /FinancialService HTTP/1.1', '200', '-'),
kwargs={})
\end_layout
\begin_layout LyX-Code
--> address_string(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- address_string()
\end_layout
\begin_layout LyX-Code
--> log_date_time_string(args=(,),
\end_layout
\begin_layout LyX-Code
kwargs={})
\end_layout
\begin_layout LyX-Code
<-- log_date_time_string()
\end_layout
\begin_layout LyX-Code
adevp02 - - [11/Jan/2008 14:41:24] "POST /FinancialService HTTP/1.1" 200
-
\end_layout
\begin_layout LyX-Code
<-- log_message()
\end_layout
\begin_layout LyX-Code
<-- log_request()
\end_layout
\begin_layout LyX-Code
--> version_string(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- version_string()
\end_layout
\begin_layout LyX-Code
--> send_header(args=(, 'Server', 'ZSI/1.1 BaseHTTP/0.3 Python/2.4.4'), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- send_header()
\end_layout
\begin_layout LyX-Code
--> date_time_string(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- date_time_string()
\end_layout
\begin_layout LyX-Code
--> send_header(args=(, 'Date', 'Fri, 11 Jan 2008 13:41:24 GMT'), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- send_header()
\end_layout
\begin_layout LyX-Code
<-- send_response()
\end_layout
\begin_layout LyX-Code
--> send_header(args=(, 'Content-type', 'text/xml; charset="utf-8"'), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- send_header()
\end_layout
\begin_layout LyX-Code
--> send_header(args=(, 'Content-Length', '456'), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- send_header()
\end_layout
\begin_layout LyX-Code
--> end_headers(args=(,), kwargs={})
\end_layout
\begin_layout LyX-Code
<-- end_headers()
\end_layout
\begin_layout LyX-Code
<-- send_xml()
\end_layout
\begin_layout LyX-Code
<-- _Dispatch()
\end_layout
\begin_layout LyX-Code
<-- do_POST()
\end_layout
\begin_layout LyX-Code
<-- handle_one_request()
\end_layout
\begin_layout LyX-Code
<-- handle()
\end_layout
\begin_layout Subsection
Logging the client request
\begin_inset LatexCommand \label{sub:Logging-the-client-request}
\end_inset
\end_layout
\begin_layout Standard
While section
\begin_inset LatexCommand \ref{sub:Detailed-method-call-tracing}
\end_inset
presents a way to enable a rather detailed tracing of method calls and
arguments, it is often desirable to log the incoming client request on
the server side.
Unfortunately, ZSI currently offers no standard way to do so.
The straightforward way to achieve this is to implement a custom request
handler by copying over the
\family typewriter
ServiceContainer.SOAPRequestHander.do_POST()
\family default
method implementation and insert debugging statements where desired.
We use another approach to get at the incoming XML:
\end_layout
\begin_layout LyX-Code
from optparse import OptionParser
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the ZSI stuff you'd need no matter what
\end_layout
\begin_layout LyX-Code
from ZSI.wstools import logging
\end_layout
\begin_layout LyX-Code
from ZSI import ServiceContainer
\end_layout
\begin_layout LyX-Code
from ZSI import resolvers
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from ZSI.version import Version as zsiversion
\end_layout
\begin_layout LyX-Code
print "*** ZSI version %s ***" % (zsiversion,)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
LOGGER = logging.getLogger("")
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Some more or less nifty stuff for more extensive tracing
\end_layout
\begin_layout LyX-Code
from inject_tracing import enhance_module, TraceLocals
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Import the generated Server Object
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
# 2.1alpha
\end_layout
\begin_layout LyX-Code
from FinancialService_server import *
\end_layout
\begin_layout LyX-Code
# Dummy implementation
\end_layout
\begin_layout LyX-Code
def adapt(method):
\end_layout
\begin_layout LyX-Code
return method
\end_layout
\begin_layout LyX-Code
except ImportError, e:
\end_layout
\begin_layout LyX-Code
# 2.0final
\end_layout
\begin_layout LyX-Code
from FinancialService_services_server import *
\end_layout
\begin_layout LyX-Code
from service_adaptor import ServiceAdaptor21
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
adapt = ServiceAdaptor21.adapt
\end_layout
\begin_layout LyX-Code
# Wrap generated 2.0 class to 2.1 soap_ method behaviour
\end_layout
\begin_layout LyX-Code
FinancialService = ServiceAdaptor21(FinancialService)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Create a Server implementation by inheritance
\end_layout
\begin_layout LyX-Code
# 2.1alpha implementation
\end_layout
\begin_layout LyX-Code
class MyFinancialService(FinancialService):
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Make WSDL available for HTTP GET
\end_layout
\begin_layout LyX-Code
_wsdl = "".join(open("FinancialService.wsdl").readlines())
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@adapt
\end_layout
\begin_layout LyX-Code
def soap_getPV(self, ps, **kw):
\end_layout
\begin_layout LyX-Code
# Call the generated base class method to get appropriate
\end_layout
\begin_layout LyX-Code
# input/output data structures
\end_layout
\begin_layout LyX-Code
request, response = FinancialService.soap_getPV(self, ps, **kw)
\end_layout
\begin_layout LyX-Code
# Comment that out if need be to see what API these objects offer:
\end_layout
\begin_layout LyX-Code
#print help(request)
\end_layout
\begin_layout LyX-Code
#print help(response)
\end_layout
\begin_layout LyX-Code
# Using getters/setters
\end_layout
\begin_layout LyX-Code
irate = request.get_element_irate()
\end_layout
\begin_layout LyX-Code
CFs = request.get_element_CFSequence().get_element_CF()
\end_layout
\begin_layout LyX-Code
# Alternative way to access the input data
\end_layout
\begin_layout LyX-Code
#irate = request._irate
\end_layout
\begin_layout LyX-Code
#CFs = request._CFSequence._CF
\end_layout
\begin_layout LyX-Code
# Invoke the service worker code
\end_layout
\begin_layout LyX-Code
PV = self.getPV(irate, CFs)
\end_layout
\begin_layout LyX-Code
#print "PV:", PV
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# assign return value to response object
\end_layout
\begin_layout LyX-Code
response = getPVResponse(PV)
\end_layout
\begin_layout LyX-Code
# Another way to create a serializable response object
\end_layout
\begin_layout LyX-Code
#class SimpleTypeWrapper(float):
\end_layout
\begin_layout LyX-Code
# typecode = response.typecode
\end_layout
\begin_layout LyX-Code
#response = SimpleTypeWrapper(PV)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
return request, response
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def getPV(self, irate, cashFlows):
\end_layout
\begin_layout LyX-Code
# worker code method
\end_layout
\begin_layout LyX-Code
t = 0
\end_layout
\begin_layout LyX-Code
PV = 0.0
\end_layout
\begin_layout LyX-Code
for CF in cashFlows:
\end_layout
\begin_layout LyX-Code
PV += (CF or 0.0) * ((irate / 100.0 + 1) ** (-t))
\end_layout
\begin_layout LyX-Code
t += 1
\end_layout
\begin_layout LyX-Code
return PV
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# A traced request handler class that debug-logs the payload XML of the
request
\end_layout
\begin_layout LyX-Code
# message, as received from the client
\end_layout
\begin_layout LyX-Code
class DebugSOAPRequestHandler(ServiceContainer.SOAPRequestHandler):
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@TraceLocals.trace(["xml"], logger=LOGGER)
\end_layout
\begin_layout LyX-Code
def do_POST(self):
\end_layout
\begin_layout LyX-Code
ServiceContainer.SOAPRequestHandler.do_POST(self)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
op = OptionParser(usage="%prog [options]")
\end_layout
\begin_layout LyX-Code
op.add_option("-l", "--loglevel", help="loglevel (DEBUG, WARN)",
\end_layout
\begin_layout LyX-Code
metavar="LOGLEVEL")
\end_layout
\begin_layout LyX-Code
op.add_option("-p", "--port", help="HTTP port",
\end_layout
\begin_layout LyX-Code
metavar="PORT", default=8080, type="int")
\end_layout
\begin_layout LyX-Code
op.add_option("-t", "--trace", help="trace function/method calls",
\end_layout
\begin_layout LyX-Code
action="store_true")
\end_layout
\begin_layout LyX-Code
op.add_option("-n", "--names", help="trace function/method names",
\end_layout
\begin_layout LyX-Code
metavar="NAME", action="append")
\end_layout
\begin_layout LyX-Code
options, args = op.parse_args()
\end_layout
\begin_layout LyX-Code
if options.trace:
\end_layout
\begin_layout LyX-Code
from ZSI import parse
\end_layout
\begin_layout LyX-Code
enhance_module(ServiceContainer, names=options.names)
\end_layout
\begin_layout LyX-Code
enhance_module(parse, names=options.names)
\end_layout
\begin_layout LyX-Code
# set the loglevel according to cmd line arg
\end_layout
\begin_layout LyX-Code
if options.loglevel:
\end_layout
\begin_layout LyX-Code
loglevel = eval(options.loglevel, logging.__dict__)
\end_layout
\begin_layout LyX-Code
LOGGER.setLevel(loglevel)
\end_layout
\begin_layout LyX-Code
# Run the server with a given list of services
\end_layout
\begin_layout LyX-Code
address = ('', options.port)
\end_layout
\begin_layout LyX-Code
sc = ServiceContainer.ServiceContainer(
\end_layout
\begin_layout LyX-Code
address, services=[MyFinancialService(),],
\end_layout
\begin_layout LyX-Code
RequestHandlerClass=DebugSOAPRequestHandler)
\end_layout
\begin_layout LyX-Code
sc.serve_forever()
\end_layout
\begin_layout Standard
Comments:
\end_layout
\begin_layout Itemize
Instead of the
\family typewriter
AsServer()
\family default
function, a ServiceContainer instance with a custom request handler class
\family typewriter
DebugSOAPRequestHandler
\family default
gets used
\end_layout
\begin_layout Itemize
\family typewriter
DebugSOAPRequestHandler
\family default
features a decorated
\family typewriter
do_POST()
\family default
method that calls its super-classī
\family typewriter
do_POST()
\family default
.
The decorator provides debugging of local variables, at the point of leaving
the method, and can be parameterized to print only certain variable names
(we want the
\begin_inset Quotes eld
\end_inset
xml
\begin_inset Quotes erd
\end_inset
string only here).
\end_layout
\begin_layout Standard
This is how the extended
\family typewriter
inject_tracing.py
\family default
module now looks like:
\begin_inset Foot
status open
\begin_layout Standard
Based on
\begin_inset ERT
status open
\begin_layout Standard
\backslash
htmladdnormallink{Mailing list posting http://mail.python.org/pipermail/python-lis
t/2005-April/319662.html}{http://mail.python.org/pipermail/python-list/2005-April/3
19662.html}
\end_layout
\end_inset
, by Bengt Richter
\end_layout
\end_inset
\end_layout
\begin_layout LyX-Code
import types
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Based on "Method enhancement" Python cookbook recipee by Ken Seehof
\end_layout
\begin_layout LyX-Code
# (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81982)}
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def enhance_method(cls, methodname, decorate):
\end_layout
\begin_layout LyX-Code
'replace a method with an enhancement'
\end_layout
\begin_layout LyX-Code
method = getattr(cls, methodname)
\end_layout
\begin_layout LyX-Code
_f = decorate(method)
\end_layout
\begin_layout LyX-Code
setattr(cls, methodname, types.MethodType(_f, None, cls))
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# loop over class dict and call enhance_method() function
\end_layout
\begin_layout LyX-Code
# for all methods to modify
\end_layout
\begin_layout LyX-Code
def enhance_all_methods(cls, decorate):
\end_layout
\begin_layout LyX-Code
for methodname in cls.__dict__:
\end_layout
\begin_layout LyX-Code
if not methodname.startswith("__")
\backslash
\end_layout
\begin_layout LyX-Code
or methodname in ["__call__", "__call___"]:
\end_layout
\begin_layout LyX-Code
method = getattr(cls, methodname)
\end_layout
\begin_layout LyX-Code
if isinstance(method, types.MethodType):
\end_layout
\begin_layout LyX-Code
enhance_method(cls, methodname, decorate)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def traced(enter_text="-->", leave_text="<--"):
\end_layout
\begin_layout LyX-Code
"""Configurable Function decorator.
\end_layout
\begin_layout LyX-Code
Outputs the text given as enter_text plus the function name and arguments
\end_layout
\begin_layout LyX-Code
before entering the decorated function, and the leave_text string after
\end_layout
\begin_layout LyX-Code
having left the decorated function.
\end_layout
\begin_layout LyX-Code
Example:
\end_layout
\begin_layout LyX-Code
>>> @traced("into", "out of")
\end_layout
\begin_layout LyX-Code
...
def foo(x,y):
\end_layout
\begin_layout LyX-Code
...
print x,y
\end_layout
\begin_layout LyX-Code
...
return x
\end_layout
\begin_layout LyX-Code
...
\end_layout
\begin_layout LyX-Code
>>> foo(1, 2)
\end_layout
\begin_layout LyX-Code
into foo(args=(1, 2), kwargs={})
\end_layout
\begin_layout LyX-Code
1 2
\end_layout
\begin_layout LyX-Code
out of foo()
\end_layout
\begin_layout LyX-Code
1
\end_layout
\begin_layout LyX-Code
>>>
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
def traced(f):
\end_layout
\begin_layout LyX-Code
_f = f
\end_layout
\begin_layout LyX-Code
def f(*args, **kwargs):
\end_layout
\begin_layout LyX-Code
print enter_text, "%s(args=%s, kwargs=%s)" % (_f.__name__, args,
\end_layout
\begin_layout LyX-Code
kwargs)
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
return _f(*args, **kwargs)
\end_layout
\begin_layout LyX-Code
finally:
\end_layout
\begin_layout LyX-Code
print leave_text, "%s()" % (_f.__name__)
\end_layout
\begin_layout LyX-Code
f.__name__ = _f.__name__
\end_layout
\begin_layout LyX-Code
return f
\end_layout
\begin_layout LyX-Code
return traced
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def enhance_module(module, decorator=traced, names=[]):
\end_layout
\begin_layout LyX-Code
"""Wrap module class methods and callables with given decorator.
Applies
\end_layout
\begin_layout LyX-Code
to list of names only, if given, otherwise to all detected
\end_layout
\begin_layout LyX-Code
methods/callables.
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
for objname, obj in module.__dict__.items():
\end_layout
\begin_layout LyX-Code
if not names or objname in names:
\end_layout
\begin_layout LyX-Code
if isinstance(obj, (type, types.ClassType)):
\end_layout
\begin_layout LyX-Code
#print obj
\end_layout
\begin_layout LyX-Code
enhance_all_methods(obj, decorator())
\end_layout
\begin_layout LyX-Code
elif callable(obj):
\end_layout
\begin_layout LyX-Code
#print obj
\end_layout
\begin_layout LyX-Code
module.__dict__[objname] = decorator()(obj)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
# Based on Python mailing list post
\end_layout
\begin_layout LyX-Code
# http://mail.python.org/pipermail/python-list/2005-April/319662.html
\end_layout
\begin_layout LyX-Code
# as posted by Bengt Richter
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
class TraceLocals(object):
\end_layout
\begin_layout LyX-Code
"""Tracing of local function or method variable names, as of leaving
the
\end_layout
\begin_layout LyX-Code
function.
\end_layout
\begin_layout LyX-Code
Can be used standalone or easiest by applying the method decorator static
\end_layout
\begin_layout LyX-Code
method "trace".
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
from sys import settrace
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def __init__(self, fnames=[], vnames=[], logger=None):
\end_layout
\begin_layout LyX-Code
"""TraceLocals constructor.
\end_layout
\begin_layout LyX-Code
Parameters:
\end_layout
\begin_layout LyX-Code
fnames: List of function or method names to be traced.
\end_layout
\begin_layout LyX-Code
vnames: List of local variable names to output.
If list is
\end_layout
\begin_layout LyX-Code
empty, all local variables will be printed.
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
self.fnames = set(fnames)
\end_layout
\begin_layout LyX-Code
self.vnames = set(vnames)
\end_layout
\begin_layout LyX-Code
if logger:
\end_layout
\begin_layout LyX-Code
self._print = logger.debug
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def _gwatch(self, frame, event, arg):
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
Global scope watcher.
When a new scope is entered, returns the local
\end_layout
\begin_layout LyX-Code
scope watching method _lwatch to do the work for that.
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
if event == 'call':
\end_layout
\begin_layout LyX-Code
name = frame.f_code.co_name # name of executing scope
\end_layout
\begin_layout LyX-Code
if name in self.fnames:
\end_layout
\begin_layout LyX-Code
return self._lwatch
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def _lwatch(self, frame, event, arg):
\end_layout
\begin_layout LyX-Code
if event == 'return':
\end_layout
\begin_layout LyX-Code
vnames = self.vnames or frame.f_locals.keys()
\end_layout
\begin_layout LyX-Code
for vname in vnames:
\end_layout
\begin_layout LyX-Code
if frame.f_locals.has_key(vname):
\end_layout
\begin_layout LyX-Code
self._print("%s: %s = %s",
\end_layout
\begin_layout LyX-Code
frame.f_code.co_name, vname,
\end_layout
\begin_layout LyX-Code
frame.f_locals[vname])
\end_layout
\begin_layout LyX-Code
else:
\end_layout
\begin_layout LyX-Code
return self._lwatch # keep watching for return event
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def on(self):
\end_layout
\begin_layout LyX-Code
"""Set the system trace hook to enable tracing.
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
self.settrace(self._gwatch)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def off(self):
\end_layout
\begin_layout LyX-Code
"""Reset the system trace hook to disable tracing.
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
self.settrace(None)
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
def _print(self, msg, *args):
\end_layout
\begin_layout LyX-Code
print msg % args
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
@staticmethod
\end_layout
\begin_layout LyX-Code
def trace(vnames=[], logger=None):
\end_layout
\begin_layout LyX-Code
"""Method/function decorator that enables tracing of local variables,
as
\end_layout
\begin_layout LyX-Code
of leaving the function.
\end_layout
\begin_layout LyX-Code
Parameters:
\end_layout
\begin_layout LyX-Code
vnames: List of variable names that shall be traced.
If list is
\end_layout
\begin_layout LyX-Code
empty, all local variables will be printed.
\end_layout
\begin_layout LyX-Code
logger: Optional logger instance.
If given, ouput will be routed
\end_layout
\begin_layout LyX-Code
through logger's debug method.
\end_layout
\begin_layout LyX-Code
"""
\end_layout
\begin_layout LyX-Code
def _decorate(func):
\end_layout
\begin_layout LyX-Code
tracer = TraceLocals([func.__name__, ], vnames, logger=logger)
\end_layout
\begin_layout LyX-Code
def _f(*args, **kwargs):
\end_layout
\begin_layout LyX-Code
tracer.on()
\end_layout
\begin_layout LyX-Code
try:
\end_layout
\begin_layout LyX-Code
return func(*args, **kwargs)
\end_layout
\begin_layout LyX-Code
finally:
\end_layout
\begin_layout LyX-Code
tracer.off()
\end_layout
\begin_layout LyX-Code
_f.__name__ = func.__name__
\end_layout
\begin_layout LyX-Code
return _f
\end_layout
\begin_layout LyX-Code
return _decorate
\end_layout
\begin_layout Standard
Using this, the ZSI server now logs the incoming client message:
\end_layout
\begin_layout LyX-Code
$ /apps/pydev/hjoukl/bin/python2.4 myTracedFinancialServer.py -l "DEBUG"
\end_layout
\begin_layout LyX-Code
*** ZSI version (2, 1, 0) ***
\end_layout
\begin_layout LyX-Code
---- ZSI.TCcompound.ComplexType ----
\end_layout
\begin_layout LyX-Code
[DEBUG] parse
\end_layout
\begin_layout LyX-Code
[DEBUG] ofwhat: (, )
\end_layout
\begin_layout LyX-Code
[DEBUG] what: (http://services.zsiserver.net/FinancialService_NS,irate)
\end_layout
\begin_layout LyX-Code
[DEBUG] child node: (http://services.zsiserver.net/FinancialService_NS,ns1:i
rate)
\end_layout
\begin_layout LyX-Code
[DEBUG] what: (http://services.zsiserver.net/FinancialService_NS,CFSequence)
\end_layout
\begin_layout LyX-Code
[DEBUG] child node: (http://services.zsiserver.net/FinancialService_NS,ns1:C
FSequence)
\end_layout
\begin_layout LyX-Code
[DEBUG] parse
\end_layout
\begin_layout LyX-Code
[DEBUG] ofwhat: (,)
\end_layout
\begin_layout LyX-Code
[DEBUG] what: (http://services.zsiserver.net/FinancialService_NS,CF)
\end_layout
\begin_layout LyX-Code
[DEBUG] child node: (http://services.zsiserver.net/FinancialService_NS,ns1:C
F)
\end_layout
\begin_layout LyX-Code
[DEBUG] child node: (http://services.zsiserver.net/FinancialService_NS,ns1:C
F)
\end_layout
\begin_layout LyX-Code
adevp02 - - [18/Jan/2008 13:38:41] "POST /FinancialService# HTTP/1.1" 200
-
\end_layout
\begin_layout LyX-Code
---- ----
\end_layout
\begin_layout LyX-Code
[DEBUG] do_POST: xml =
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
7.000000
\end_layout
\begin_layout LyX-Code
-100.000000
\end_layout
\begin_layout LyX-Code
110.000000
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout Standard
\newpage
\end_layout
\begin_layout Bibliography
\bibitem {ZSIrefdoc2.0}
Salz, Rich; Blunck, Christopher: ZSI: The Zolera Soap Infrastructure.
, Release 2.0.0, February
01, 2007.
\end_layout
\begin_layout Bibliography
\bibitem {ZSIuserguide2.0}
Boverhof, Joshua; Moad, Charles: ZSI: The Zolera Soap Infrastructure Userīs
Guide.
, Release 2.0.0,
February 01, 2007.
\end_layout
\begin_layout Bibliography
\bibitem {ZSIrefdoc2.1}
Salz, Rich; Blunck, Christopher: ZSI: The Zolera Soap Infrastructure.
, Release 2.1.0,
November 01, 2007.
\end_layout
\begin_layout Bibliography
\bibitem {ZSIuserguide2.1}
Boverhof, Joshua; Moad, Charles: ZSI: The Zolera Soap Infrastructure Userīs
Guide.
, Release 2.1.0,
November 01, 2007.
\end_layout
\begin_layout Bibliography
\bibitem {gSOAPdoc}
van Engelen, Robert: gSOAP 2.7.3 User Guide.
, June 27, 2005.
\end_layout
\begin_layout Bibliography
\bibitem {whichWSDL}
Butek, Russell: Which style of WSDL should I use? , May 24, 2005.
\end_layout
\begin_layout Bibliography
\bibitem {InteropHOLGER}
Joukl, Holger: Interoperable WSDL/SOAP web services introduction: Python
ZSI, Excel XP, gSOAP C/C++ & Applix SS).
.
July 22, 2005.
\end_layout
\begin_layout Bibliography
\bibitem {HobbsCookbook}
Hobbs, Chris: Using ZSI.
, August 1, 2007.
\end_layout
\begin_layout Bibliography
\bibitem {LokadTutorial}
Locad.com: Web Services Tutorial with Python.
,
January 2, 2008.
\end_layout
\end_body
\end_document