<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns="http://purl.org/rss/1.0/">




    



<channel rdf:about="http://glicksoftware.com/search_rss">
  <title>davisagli</title>
  <link>http://glicksoftware.com</link>

  <description>
    
            These are the search results for the query, showing results 1 to 1.
        
  </description>

  

  

  <image rdf:resource="http://glicksoftware.com/logo.png"/>

  <items>
    <rdf:Seq>
      
        <rdf:li rdf:resource="http://glicksoftware.com/presentations/the-art-of-integrating-plone-with-webservices"/>
      
    </rdf:Seq>
  </items>

</channel>


  <item rdf:about="http://glicksoftware.com/presentations/the-art-of-integrating-plone-with-webservices">
    <title>The Art of Integrating Plone with Webservices</title>
    <link>http://glicksoftware.com/presentations/the-art-of-integrating-plone-with-webservices</link>
    <description>Part of Zope's power lies in integrating it with other web-based services. Python provides some powerful "batteries included" to help with this, but there are still some common pitfalls to watch out for.</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<!--?xml version="1.0" encoding="utf-8" ?-->
<p>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<meta content="Docutils 0.6: http://docutils.sourceforge.net/" name="generator" />
<title></title>
</p>
<!-- /* :Author: David Goodger (goodger@python.org) :Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $ :Copyright: This stylesheet has been placed in the public domain.  Default cascading style sheet for the HTML output of Docutils.  See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to customize this style sheet. */  /* used to remove borders from tables and images */ .borderless, table.borderless td, table.borderless th {   border: 0 }  table.borderless td, table.borderless th {   /* Override padding for "table.docutils td" with "! important".      The right padding separates the table cells. */   padding: 0 0.5em 0 0 ! important }  .first {   /* Override more specific margin styles with "! important". */   margin-top: 0 ! important }  .last, .with-subtitle {   margin-bottom: 0 ! important }  .hidden {   display: none }  a.toc-backref {   text-decoration: none ;   color: black }  blockquote.epigraph {   margin: 2em 5em ; }  dl.docutils dd {   margin-bottom: 0.5em }  /* Uncomment (and remove this text!) to get bold-faced definition list terms dl.docutils dt {   font-weight: bold } */  div.abstract {   margin: 2em 5em }  div.abstract p.topic-title {   font-weight: bold ;   text-align: center }  div.admonition, div.attention, div.caution, div.danger, div.error, div.hint, div.important, div.note, div.tip, div.warning {   margin: 2em ;   border: medium outset ;   padding: 1em }  div.admonition p.admonition-title, div.hint p.admonition-title, div.important p.admonition-title, div.note p.admonition-title, div.tip p.admonition-title {   font-weight: bold ;   font-family: sans-serif }  div.attention p.admonition-title, div.caution p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title, div.warning p.admonition-title {   color: red ;   font-weight: bold ;   font-family: sans-serif }  /* Uncomment (and remove this text!) to get reduced vertical space in    compound paragraphs. div.compound .compound-first, div.compound .compound-middle {   margin-bottom: 0.5em }  div.compound .compound-last, div.compound .compound-middle {   margin-top: 0.5em } */  div.dedication {   margin: 2em 5em ;   text-align: center ;   font-style: italic }  div.dedication p.topic-title {   font-weight: bold ;   font-style: normal }  div.figure {   margin-left: 2em ;   margin-right: 2em }  div.footer, div.header {   clear: both;   font-size: smaller }  div.line-block {   display: block ;   margin-top: 1em ;   margin-bottom: 1em }  div.line-block div.line-block {   margin-top: 0 ;   margin-bottom: 0 ;   margin-left: 1.5em }  div.sidebar {   margin: 0 0 0.5em 1em ;   border: medium outset ;   padding: 1em ;   background-color: #ffffee ;   width: 40% ;   float: right ;   clear: right }  div.sidebar p.rubric {   font-family: sans-serif ;   font-size: medium }  div.system-messages {   margin: 5em }  div.system-messages h1 {   color: red }  div.system-message {   border: medium outset ;   padding: 1em }  div.system-message p.system-message-title {   color: red ;   font-weight: bold }  div.topic {   margin: 2em }  h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {   margin-top: 0.4em }  h1.title {   text-align: center }  h2.subtitle {   text-align: center }  hr.docutils {   width: 75% }  img.align-left, .figure.align-left{   clear: left ;   float: left ;   margin-right: 1em }  img.align-right, .figure.align-right {   clear: right ;   float: right ;   margin-left: 1em }  .align-left {   text-align: left }  .align-center {   clear: both ;   text-align: center }  .align-right {   text-align: right }  /* reset inner alignment in figures */ div.align-right {   text-align: left }  /* div.align-center * { */ /*   text-align: left } */  ol.simple, ul.simple {   margin-bottom: 1em }  ol.arabic {   list-style: decimal }  ol.loweralpha {   list-style: lower-alpha }  ol.upperalpha {   list-style: upper-alpha }  ol.lowerroman {   list-style: lower-roman }  ol.upperroman {   list-style: upper-roman }  p.attribution {   text-align: right ;   margin-left: 50% }  p.caption {   font-style: italic }  p.credits {   font-style: italic ;   font-size: smaller }  p.label {   white-space: nowrap }  p.rubric {   font-weight: bold ;   font-size: larger ;   color: maroon ;   text-align: center }  p.sidebar-title {   font-family: sans-serif ;   font-weight: bold ;   font-size: larger }  p.sidebar-subtitle {   font-family: sans-serif ;   font-weight: bold }  p.topic-title {   font-weight: bold }  pre.address {   margin-bottom: 0 ;   margin-top: 0 ;   font: inherit }  pre.literal-block, pre.doctest-block {   margin-left: 2em ;   margin-right: 2em }  span.classifier {   font-family: sans-serif ;   font-style: oblique }  span.classifier-delimiter {   font-family: sans-serif ;   font-weight: bold }  span.interpreted {   font-family: sans-serif }  span.option {   white-space: nowrap }  span.pre {   white-space: pre }  span.problematic {   color: red }  span.section-subtitle {   /* font-size relative to parent (h1..h6 element) */   font-size: 80% }  table.citation {   border-left: solid 1px gray;   margin-left: 1px }  table.docinfo {   margin: 2em 4em }  table.docutils {   margin-top: 0.5em ;   margin-bottom: 0.5em }  table.footnote {   border-left: solid 1px black;   margin-left: 1px }  table.docutils td, table.docutils th, table.docinfo td, table.docinfo th {   padding-left: 0.5em ;   padding-right: 0.5em ;   vertical-align: top }  table.docutils th.field-name, table.docinfo th.docinfo-name {   font-weight: bold ;   text-align: left ;   white-space: nowrap ;   padding-left: 0 }  h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {   font-size: 100% }  ul.auto-toc {   list-style-type: none } -->
<div class="document">
<div class="section" id="what-is-a-web-service">
<h2>What is a web service?</h2>
<ul class="simple">
<li>Lets code running on one machine (the client) interact with code on another (the server)</li>
<li>Transports messages over HTTP</li>
</ul>
</div>
<div class="section" id="why-web-services">
<h2>Why web services?</h2>
<ul class="simple">
<li>Often easier to integrate than to build your own</li>
<li>Combine best-of-breed tools</li>
</ul>
</div>
<div class="section" id="major-categories">
<h2>Major categories</h2>
<dl class="docutils"> <dt>RPC-style / Service-oriented architecture</dt> <dd>Focus is on the action being performed.</dd> <dt>REST-style / Resource-oriented architecture</dt> <dd>Focus is on the object being acted upon.</dd> </dl>
<div class="section" id="xml-rpc">
<h3>XML-RPC</h3>
<ul>
<li>
<p class="first">Passes messages in a simple XML-based format.</p>
<p>Sample request:</p>
<pre>&lt;?xml version="1.0"?&gt;<br />&lt;methodCall&gt;<br />  &lt;methodName&gt;examples.getStateName&lt;/methodName&gt;<br />  &lt;params&gt;<br />    &lt;param&gt;<br />        &lt;value&gt;&lt;i4&gt;40&lt;/i4&gt;&lt;/value&gt;<br />    &lt;/param&gt;<br />  &lt;/params&gt;<br />&lt;/methodCall&gt;<br /></pre>
<p>Sample response:</p>
<pre>&lt;?xml version="1.0"?&gt;<br />&lt;methodResponse&gt;<br />  &lt;params&gt;<br />    &lt;param&gt;<br />        &lt;value&gt;&lt;string&gt;South Dakota&lt;/string&gt;&lt;/value&gt;<br />    &lt;/param&gt;<br />  &lt;/params&gt;<br />&lt;/methodResponse&gt;<br /></pre>
</li>
<li>
<p class="first">Support in the Python stdlib: xmlrpclib</p>
</li>
</ul>
<div class="section" id="example-querying-pypi">
<h4>Example: Querying PyPI</h4>
<blockquote>
<pre class="doctest-block">&gt;&gt;&gt; import xmlrpclib<br />&gt;&gt;&gt; from pprint import pprint<br />&gt;&gt;&gt; client = xmlrpclib.ServerProxy('http://pypi.python.org/pypi')<br />&gt;&gt;&gt; client.release_urls('Plone', '4.0.1')<br />&gt;&gt;&gt; pprint(client.release_urls('Plone', '4.0.1'))<br />[{'comment_text': '',<br />  'downloads': 177,<br />  'filename': 'Plone-4.0.1.zip',<br />  'has_sig': False,<br />  'md5_digest': 'be72596d49295b7207f0a861ee3530ed',<br />  'packagetype': 'sdist',<br />  'python_version': 'source',<br />  'size': 1507065,<br />  'upload_time': &lt;DateTime '20101004T02:30:01' at 10071a248&gt;,<br />  'url': 'http://pypi.python.org/packages/source/P/Plone/Plone-4.0.1.zip'}]<br /></pre>
</blockquote>
<p>More info: <a class="reference external" href="http://wiki.python.org/moin/PyPiXmlRpc">http://wiki.python.org/moin/PyPiXmlRpc</a></p>
</div>
<div class="section" id="example-wsapi4plone">
<h4>Example: wsapi4plone</h4>
<p>Provides an XML-RPC interface for interacting with a Plone site.</p>
<ul class="simple">
<li>post_object</li>
<li>put_object</li>
<li>get_object</li>
<li>delete_object</li>
<li>query</li>
<li>get_schema</li>
<li>get_types</li>
<li>get_workflow</li>
<li>set_workflow</li>
<li>get_discussion</li>
</ul>
<p>More info: <a class="reference external" href="http://pypi.python.org/pypi/wsapi4plone.core">http://pypi.python.org/pypi/wsapi4plone.core</a></p>
</div>
</div>
<div class="section" id="soap">
<h3>SOAP</h3>
<ul class="simple">
<li>"big Web Services" — described by various WS-* W3C standards</li>
<li>passes XML-based messages like XML-RPC, but more complicated (can represent complex types)</li>
<li>WSDL (web service description language) — machine-readable XML description of the interface</li>
<li>In Python:  
<ul>
<li>soaplib</li>
<li>suds</li>
</ul>
</li>
</ul>
<div class="section" id="sample-request-and-response">
<h4>Sample Request and Response</h4>
<p>Sample request:</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;SOAP-ENV:Envelope xmlns:ns0="http://cicero.azavea.com/"<br />                   xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/"<br />                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />                   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"&gt;<br />   &lt;SOAP-ENV:Header/&gt;<br />   &lt;ns1:Body&gt;<br />      &lt;ns0:GetOfficialsByAddress&gt;<br />         &lt;ns0:authToken&gt;FOO&lt;/ns0:authToken&gt;<br />         &lt;ns0:address&gt;1402 3rd Ave&lt;/ns0:address&gt;<br />         &lt;ns0:city&gt;Seattle&lt;/ns0:city&gt;<br />         &lt;ns0:state&gt;WA&lt;/ns0:state&gt;<br />         &lt;ns0:postalCode&gt;98101&lt;/ns0:postalCode&gt;<br />         &lt;ns0:country&gt;US&lt;/ns0:country&gt;<br />         &lt;ns0:districtType&gt;NATIONAL_UPPER&lt;/ns0:districtType&gt;<br />         &lt;ns0:includeAtLarge&gt;false&lt;/ns0:includeAtLarge&gt;<br />      &lt;/ns0:GetOfficialsByAddress&gt;<br />   &lt;/ns1:Body&gt;<br />&lt;/SOAP-ENV:Envelope&gt;<br /></pre>
<p>Sample response:</p>
<pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;<br />&lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"<br />               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />               xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;<br />  &lt;soap:Body&gt;<br />    &lt;GetOfficialsByAddressResponse xmlns="http://cicero.azavea.com/"&gt;<br />      &lt;GetOfficialsByAddressResult&gt;<br />        &lt;ElectedOfficialInfo&gt;<br />          &lt;ElectedOfficialID&gt;326f9123-4196-49ff-a9ab-cca8194a12a8&lt;/ElectedOfficialID&gt;<br />          &lt;AssemblyName /&gt;<br />          (snip)<br />          &lt;FirstName&gt;Maria&lt;/FirstName&gt;<br />          &lt;MiddleInitial&gt;E.&lt;/MiddleInitial&gt;<br />          &lt;LastName&gt;Cantwell&lt;/LastName&gt;<br />          (snip)<br />          &lt;LastUpdateDate&gt;2009-03-26T00:00:00&lt;/LastUpdateDate&gt;<br />        &lt;/ElectedOfficialInfo&gt;<br />      &lt;/GetOfficialsByAddressResult&gt;<br />    &lt;/GetOfficialsByAddressResponse&gt;<br />  &lt;/soap:Body&gt;<br />&lt;/soap:Envelope&gt;<br /></pre>
</div>
<div class="section" id="suds-example-azavea-s-cicero-api">
<h4>suds example: Azavea's Cicero API</h4>
<p>Azavea provides a web service to look up information about elected officials for a given address:</p>
<pre>&gt;&gt;&gt; from suds.client import Client<br />&gt;&gt;&gt; auth_client = Client('http://cicero.azavea.com/Azavea.Cicero.WebService.v2/AuthenticationService.asmx?WSDL')<br />&gt;&gt;&gt; token = auth_client.service.GetToken(username, password)<br /><br /># printing a client lists its service's available methods<br />&gt;&gt;&gt; client = Client('http://cicero.azavea.com/Azavea.Cicero.WebService.v2/ElectedOfficialQueryService.asmx?WSDL')<br />&gt;&gt;&gt; print client<br />Suds ( https://fedorahosted.org/suds/ )  version: 0.4 GA  build: R699-20100913<br />Service ( ElectedOfficialQueryService ) tns="http://cicero.azavea.com/"<br />   Prefixes (2)<br />      ns0 = "http://cicero.azavea.com/"<br />      ns1 = "http://microsoft.com/wsdl/types/"<br />   Ports (2):<br />      (ElectedOfficialQueryServiceSoap)<br />         Methods (11):<br />            GetOfficialsByAddress(xs:string authToken, xs:string address, xs:string city, xs:string state, xs:string postalCode, xs:string country, xs:string districtType, xs:boolean includeAtLarge, )<br />(snip)<br /><br />&gt;&gt;&gt; officials = client.service.GetOfficialsForAddress(token, '1402 3rd Ave', 'Seattle', 'WA', '98101', 'US', 'NATIONAL_UPPER', True)<br />&gt;&gt;&gt; officials.ElectedOfficialInfo[0].FirstName<br />'Maria'<br />&gt;&gt;&gt; officials.ElectedOfficialInfo[0].LastName<br />'Cantwell'<br /></pre>
</div>
</div>
<div class="section" id="restful-apis">
<h3>RESTful APIs</h3>
<ul class="simple">
<li>reaction to "big web services"</li>
<li>resource-oriented</li>
<li>encourages direct use of features of HTTP (request methods, passing parameters in query string, caching, etc.)</li>
<li>response representations may vary. XML and JSON are common.</li>
<li>in Python:  
<ul>
<li>urllib/urllib2 for transfer (stdlib)</li>
<li>ElementTree (stdlib), lxml, or some other XML library to parse XML</li>
<li>json (stdlib) to parse JSON</li>
</ul>
</li>
</ul>
<div class="section" id="example-brown-paper-tickets-api">
<h4>Example: Brown Paper Tickets API</h4>
<p>Brown Paper Tickets provides an API for listing and registering for events.</p>
<p>Sample Response:</p>
<pre>&lt;?xml version="1.0"?&gt;<br />&lt;document&gt;<br />&lt;result&gt;success&lt;/result&gt;<br />&lt;resultcode&gt;000000&lt;/resultcode&gt;<br />&lt;note&gt;&lt;/note&gt;<br />&lt;event&gt;<br />      &lt;title&gt;My Event&lt;/title&gt;<br />      &lt;link&gt;http://www.brownpapertickets.com/event/120141&lt;/link&gt;<br />      &lt;description&gt;blah blah blah&lt;/description&gt;<br />      &lt;event_id&gt;120141&lt;/event_id&gt;<br />      &lt;live&gt;y&lt;/live&gt;<br />      (snip)<br />&lt;/event&gt;<br />&lt;/document&gt;<br /></pre>
<p>We can make a request to this service using urllib and parse the response using ElementTree:</p>
<blockquote>
<pre class="doctest-block">&gt;&gt;&gt; from urllib import urlencode, urlopen<br />&gt;&gt;&gt; from xml.etree import ElementTree<br />&gt;&gt;&gt; url = 'https://www.brownpapertickets.com/api2/eventlist?id=foo&amp;client=bar'<br />&gt;&gt;&gt; res = urlopen(url).read()<br />&gt;&gt;&gt; tree = ElementTree.fromstring(res)<br />&gt;&gt;&gt; for node in tree.findall('event'):<br />...     title = node.find('title').text<br /></pre>
</blockquote>
</div>
</div>
</div>
<div class="section" id="authentication">
<h2>Authentication</h2>
<blockquote>
<ul class="simple">
<li>Token or API key in request</li>
<li>HTTP basic authentication</li>
<li>AuthSub &amp; OAuth (requires callback to receive token)</li>
</ul>
</blockquote>
</div>
<div class="section" id="what-could-go-wrong">
<h2>What could go wrong</h2>
<ul class="simple">
<li>call times out</li>
<li>call fails</li>
<li>call succeeds but other code fails</li>
<li>ZODB conflict errors</li>
<li>long external calls tie up publisher threads</li>
</ul>
<div class="section" id="timeouts-deadlocks">
<h3>Timeouts &amp; Deadlocks</h3>
<ul class="simple">
<li>Python's default socket timeout is None (forever), which is pathological</li>
<li>Can override with socket.setdefaulttimeout(), then catch socket.timeout</li>
<li>But note that it is a global setting, not per-thread</li>
</ul>
</div>
<div class="section" id="transactions">
<h3>Transactions</h3>
<ul class="simple">
<li>In Zope, we're used to transactions being handled automatically:  
<ul>
<li>new transaction for each request</li>
<li>resource manager exists for common resources</li>
<li>two-phase commit ensures atomicity</li>
</ul>
</li>
<li>But web services are not generally transactional</li>
<li>Can do the non-transactional (e.g. web service) calls last:  
<ul>
<li>If something local fails, exception will cause transaction to abort</li>
<li>Web service call never happens</li>
<li>Can use transaction.addAfterCommitHook for this</li>
</ul>
</li>
<li>What if we need to write something locally based on a response from a web service? (e.g. payment authorization)  
<ul>
<li>If something fails _after_ the web service call, the transaction will abort but the web service call can't be undone</li>
<li>Workaround: Catch exceptions and make a new webservice call to undo the effect of the first (but what if _that_ fails?)</li>
<li>Workaround: Catch exceptions and log them (make sure your logging is foolproof!)</li>
<li>Workaround: Use an asynchronous task system like zc.async to queue the second part as a separate job that can be retried if it fails</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="conflicterrors">
<h3>ConflictErrors</h3>
<p>Occurs when connection A tries to commit changes to an object that was modified by another transaction (from connection B) since the object was loaded by connection A.</p>
<p>Even worse variant of the last case:</p>
<blockquote><ol class="arabic simple">
<li>Web service call succeeds</li>
<li>Write to ZODB fails with a ConflictError</li>
<li>ZPublisher RETRIES THE REQUEST -- and the web service gets called again</li>
<li>Much weeping and gnashing of teeth</li>
</ol></blockquote>
<p>This is exacerbated by the fact that remote web service calls tend to be slow, which makes transactions last longer and increases the risk of conflicts.</p>
<p>Possible ways to mitigate:</p>
<blockquote>
<ul class="simple">
<li>Set the request's retry_max_count attribute to 0 (conflicting requests will fail hard instead of getting retried silently, but sometimes that's better)</li>
<li>Handle remote calls as zc.async jobs, so they take place in a separate transaction</li>
</ul>
</blockquote>
</div>
</div>
<div class="section" id="tools-and-techniques">
<h2>Tools and techniques</h2>
<div class="section" id="maintaining-a-pool-of-clients">
<h3>Maintaining a pool of clients</h3>
<ul class="simple">
<li>Generally want one client object per thread to store session token, avoid reinitializing</li>
<li>Store in foreign_connections dictionary, an attribute of the ZODB connection</li>
<li>Use _v_ attributes only as a fallback</li>
<li>See "How This Package Maintains Persistent Connections" at <a class="reference external" href="http://pypi.python.org/pypi/alm.solrindex">http://pypi.python.org/pypi/alm.solrindex</a></li>
</ul>
</div>
<div class="section" id="server-side-caching">
<h3>Server-side caching</h3>
<ul class="simple">
<li>Goal: improve performance or API usage by cutting out unnecessary web service requests</li>
<li>plone.memoize provides various decorators to cache method results in different ways  
<ul>
<li>on the request object</li>
<li>in an object attribute</li>
<li>in an object volatile attribute</li>
<li>in a global RAM cache</li>
</ul>
</li>
<li>Can use something like time.time() // 3600 in the cache key to expire after no more than some given interval.</li>
<li>But remember there are only two hard problems in computer science: Naming things, cache invalidation, and off-by-one errors.</li>
</ul>
</div>
<div class="section" id="asynchronous-loading">
<h3>Asynchronous Loading</h3>
<p>If you're fetching something from a remote server for display as part of a web page, load it in a separate request after the main page loads.</p>
<p>Advantages:</p>
<blockquote>
<ul class="simple">
<li>Keeps the site from being perceived as slow</li>
<li>Separates long-running remote calls from write transactions, so the risk of ConflictErrors is reduced.</li>
<li>Sometimes can load directly from the external service to Javascript instead of hitting your server.</li>
</ul>
</blockquote>
<p>Example: collective.googleanalytics</p>
<p>JQuery makes it easy:</p>
<pre>jq(function () {<br />    jq('#analytics--1027659344').load('http://davisagli.com/blog/plone-4-in-the-news/@@analytics_async', {<br />       'report_ids': 'page-pageviews-sparkline,page-top-keywords-table',<br />       'profile_ids': 'ga:31264872',<br />       'request_url': 'http://davisagli.com/blog/plone-4-in-the-news',<br />       'date_range': 'month'<br />    }, function () {<br />        jq('#analytics--1027659344').css({<br />                'background-image': 'none',<br />                'height': 'auto'<br />            });<br />    });<br />});<br /></pre>
</div>
<div class="section" id="asynchronous-processing">
<h3>Asynchronous Processing</h3>
<p><a class="reference external" href="http://dist.enfoldsystems.com/catalog/plone.async.core">plone.async.core</a> makes it easy to queue asynchronous jobs to run via the zc.async infrastructure.</p>
<p>As discussed above, this can be used to avoid blocking the ZPublisher threads and keeping transactions open when long-running external calls are needed.</p>
<p>Simple usage example:</p>
<pre>from Products.Five import BrowserView<br />import zc.async.job<br />from plone.async.core import getQueues<br />from time import sleep<br /><br />def do_work(MAX):<br />    for x in xrange(1,MAX):<br />        sleep(0.1)<br />    print 'done!'<br /><br />class Work(BrowserView):<br /><br />    def __call__(self):<br />        queue = getQueues()['']<br />        job = zc.async.job.Job(do_work, 100)<br />        queue.put(job)<br />        # returns immediately; job runs in another thread<br /></pre>
</div>
<div class="section" id="testing-web-services">
<h3>Testing Web Services</h3>
<p>Some approaches:</p>
<ul class="simple">
<li>use a real connection (full system test)</li>
<li>connect to a stub server (for an example, see zc.authorizedotnet)</li>
<li>inject responses to particular calls (unit test)</li>
</ul>
</div>
</div>
<div class="section" id="serving-webservices-from-zope">
<h2>Serving webservices from Zope</h2>
<ul class="simple">
<li>XML-RPC  
<ul>
<li>native support in Zope 2</li>
<li>overview at <a class="reference external" href="http://plone.org/documentation/manual/plone-community-developer-documentation/serving/xmlrpc">http://plone.org/documentation/manual/plone-community-developer-documentation/serving/xmlrpc</a></li>
</ul>
</li>
<li>SOAP  
<ul>
<li>good overview at <a class="reference external" href="http://plone.org/documentation/kb/soap-support-for-plone">http://plone.org/documentation/kb/soap-support-for-plone</a></li>
<li>soaplib</li>
<li>z3c.soap</li>
<li>ZSI (Zolera SOAP Infrastructure)</li>
</ul>
</li>
<li>etc.  
<ul>
<li>write browser views which serialize to JSON or other representations</li>
</ul>
</li>
</ul>
</div>
</div>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>David Glick</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>Zope</dc:subject>
    
    
      <dc:subject>presentation</dc:subject>
    
    
      <dc:subject>webservices</dc:subject>
    
    <dc:date>2011-07-13T03:37:31Z</dc:date>
    <dc:type>Page</dc:type>
  </item>




</rdf:RDF>
