Package: wasp
This package is an abstraction of interactions with WASPs allowing
application developers to send and recieve messages without having to
worry about the mechanics of sending and recieving messages with a
particular wasp.It also allows the WASP being used to be changed by configuration
only, without any changes to application code.InstallationTo install the package, unpack the source distribution and then do:python setup.py installYou can also install with easy_install:easy_install waspAlternatively, if you’re using zc.buildout, you can just specify the
package as an egg requirement:[buildout]
parts = myeggs ...
...

[myeggs]
recipe = zc.recipe.egg
eggs = wasp
...Finally, if you’re using with Zope 2, just unpack the source
distribution into $INSTANCE_HOME/lib/python.
Be careful if you use easy_install or a buildout recipewitha Zope
2 base distribution, such as that used by Plone, as  versions of the
packages requires bywaspmay be installed that are incompatible
with Zope 2.ConfigurationThe configuration of sending and receiving messages centres around the
configuration of utilities providing ISendMessage, INotifyMessage and
IRecieveMessage. Reading the documentation for these in interfaces.py
will cover a lot of the explanation required to use thewasppackage.To use the package, the first thing you’ll need to do is choose a WASP
implementation and load any ZCML directives it provides. For the
examples here, we’ll use the demo implementations which basically echo
all their actions to the console rather than actually doing anything:>>> load_zcml('''
... <include package="wasp.demo" file="meta.zcml" />
... ''')In order to send messages, you need to wire in the ISendMessage
utility of your chosen WASP. WASP implementations usually provide a
custom ZCML directive for doing this which allows you to specify the
parameters.The demo implementation is no exception:>>> load_zcml('''
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:wasp="http://namespaces.simplistix.co.uk/wasp">
...     <wasp:sender />
... </configure>
... ''')Next, if you’re planning on receiving messages or notifications about
messages you’ve sent, you need to wire in the Receiver view. For
demonstration purposes, we wire it to all objects, but you probably
only want to wire it in such that it appears at one particular url.>>> load_zcml('''
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:browser="http://namespaces.zope.org/browser">
...   <browser:page
...       name="wasp"
...       for="*"
...       class="wasp.Receiver"
...       permission="zope.Public"
...
...     />
... </configure>
... ''')Again, if you’re planning on receiving messages or notifications about
messages you’ve sent, you need to wire in an IProcessReponse
utility. This is WASP-specific but can be changed independently of
where the Receiver view is or how it’s wired in. This means that
application developers only have to worry about wiring in the Receiver
view where they want it and system administrators can choose and
change the WASP implementation used whenever they want.For the examples, we’ll use awasp.demo.ProcessResponseimplementation:>>> load_zcml('''
... <configure
...     xmlns="http://namespaces.zope.org/zope">
...     <utility factory="wasp.demo.ProcessResponse"/>
... </configure>
... ''')Sending MessagesOnce configured, sending messages is as simple as:>>> from wasp import send
>>> send('271234','some message')
Send to: '271234'
Message: 'some message'
     Id: None
TrueAs this shows, the send method takes anmsisdn, amessageand
optionally amessage_id.Ifsendreturns True, it indicates that the message has been
successfully delivered. If something goes wrong, an exception will be
raised.However, the most common case is when send returns False:>>> load_zcml('''
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:wasp="http://namespaces.simplistix.co.uk/wasp">
...     <wasp:sender response="False"/>
... </configure>
... ''')
>>> send('271234','some message','id4321')
Send to: '271234'
Message: 'some message'
     Id: 'id4321'
FalseA return value of False means that the message has successfully been
passed to the WASP, but the WASP didn’t have a definite response at
this stage. To find out what happened, the application progammer must
pass amessage_id. This will be passed to the WASP and when the WASP
calls back, thismessage_idwill be returned. This is the subject of
the next section.Receiving Notifications About Sent MessagesTo receive notifications about sent messages, the application
programmer must provide an INotifyMessage utility.Here’s a really simple example of this:>>> class HandleNotification:
...     def __call__(self,message_id,status,details):
...         print "message_id:",repr(message_id)
...         print "    status:",repr(status)
...         print "   details:",repr(details)Normally, we’d register this utility with ZCML, but here we do so
directly with the component architecture:>>> from wasp.interfaces import INotifyMessage
>>> from zope.component import provideUtility
>>> provideUtility(HandleNotification(),provides=INotifyMessage)We can show this in action by using the demo WASP implementations
method of calling back:>>> browser.open('http://localhost/@@wasp?type=notification&message_id=123&status=delivered&details=ok')
message_id: u'123'
    status: <wasp.status.Delivered instance at ...>
   details: u'ok'Now, in some cases, particularly if data is stored in the zodb, it’s
convenient to have access to the context of the Receiver view. Thewasppackage supports this by letting you register an adapter
instead of a utility.Here’s a simple example of a suitable adapter:>>> class HandleNotification:
...     def __init__(self,context):
...         self.context = context
...     def __call__(self,message_id,status,details):
...         print "   context:",self.context
...         print "message_id:",repr(message_id)
...         print "    status:",repr(status)
...         print "   details:",repr(details)This should generally be registered for all objects as the Receiver
view will make sure that only its context is adapted:>>> from wasp.interfaces import INotifyMessage
>>> from zope.component import provideAdapter
>>> provideAdapter(HandleNotification,adapts=(None,),provides=INotifyMessage)Now when a notification is received, the code called has access to the
context:>>> browser.open('http://localhost/@@wasp?type=notification&message_id=123&status=delivered&details=ok')
   context: <security proxied zope.app.folder.folder.Folder instance at ...>
message_id: u'123'
    status: <wasp.status.Delivered instance at ...>
   details: u'ok'Receiving MessagesTo receive messages, the application programmer must provide an
IReceiveMessage utility.Here’s a really simple example of this:>>> class HandleMessage:
...     def __call__(self,msisdn,message_text):
...         print "      msisdn:",repr(msisdn)
...         print "message_text:",repr(message_text)Normally, we’d register this utility with ZCML, but here we do so
directly with the component architecture:>>> from wasp.interfaces import IReceiveMessage
>>> from zope.component import provideUtility
>>> provideUtility(HandleMessage(),provides=IReceiveMessage)We can show this in action by using the demo WASP implementations
method of calling back:>>> browser.open('http://localhost/@@wasp?type=message&msisdn=123&message_text=my+message')
      msisdn: u'123'
message_text: u'my message'Now, in some cases, particularly if data is stored in the zodb, it’s
convenient to have access to the context of the Receiver view. Thewasppackage supports this by letting you register an adapter
instead of a utility.Here’s a simple example of a suitable adapter:>>> class HandleMessage:
...     def __init__(self,context):
...         self.context = context
...     def __call__(self,msisdn,message_text):
...         print "     context:",self.context
...         print "      msisdn:",repr(msisdn)
...         print "message_text:",repr(message_text)This should generally be registered for all objects as the Receiver
view will make sure that only its context is adapted:>>> from wasp.interfaces import IReceiveMessage
>>> from zope.component import provideAdapter
>>> provideAdapter(HandleMessage,adapts=(None,),provides=IReceiveMessage)Now when a message is received, the code called has access to the
context:>>> browser.open('http://localhost/@@wasp?type=message&msisdn=123&message_text=my+message')
     context: <security proxied zope.app.folder.folder.Folder instance at ...>
      msisdn: u'123'
message_text: u'my message'Currently Available WASPsDocumentation for the configuration of the currently avalable WASPs is
found in the ‘readme.txt’ of each of thewaspsubpackages. Each
subpackage represents a different WASP implementation.The currently available WASP implementations are listed below:demoa WASP for testing that just echos requests and responses.bulksmsan implementation for the service provided byhttp://bulksms.2way.co.za/LicensingCopyright (c) 2008 Simplistix LtdThis Software is released under the MIT License:http://www.opensource.org/licenses/mit-license.htmlSee license.txt for more details.CreditsRoche Compaan and Rijk Stofberg at UpfrontIdeas and fundingChris WithersDevelopmentChanges1.0.1first open source release1.0.0implementation for BulkSMS WASP.clarified the meaning ofmsisdnin IReceiveMessageadded a generic SendException for use by WASP implementations.change IProcessResponse to cater for returning notifications,
messagesanda response for the browser0.9.0initial release featuring only the demo implementation.