diff idavoll/pubsub.py @ 31:fa866793075d

Split up implementation in several Services that match the division in the backend interfaces. Add appropriate adapter calls.
author Ralph Meijer <ralphm@ik.nu>
date Tue, 26 Oct 2004 16:29:44 +0000
parents 256dcda26752
children c9ddca3cce20
line wrap: on
line diff
--- a/idavoll/pubsub.py	Tue Oct 26 16:28:07 2004 +0000
+++ b/idavoll/pubsub.py	Tue Oct 26 16:29:44 2004 +0000
@@ -25,194 +25,228 @@
 PUBSUB_CONFIGURE_SET = PUBSUB_SET + '/configure'
 
 class PubSubError(Exception):
-	pubsub_error = None
-	msg = ''
+    pubsub_error = None
+    msg = ''
 
 class NotImplemented(PubSubError):
-	pass
+    pass
 
 class OptionsUnavailable(PubSubError):
-	pubsub_error = 'subscription-options-unavailable'
+    pubsub_error = 'subscription-options-unavailable'
 
 class SubscriptionOptionsUnavailable(PubSubError):
-	pubsub_error = 'subscription-options-unavailable'
+    pubsub_error = 'subscription-options-unavailable'
 
 class NodeNotConfigurable(PubSubError):
-	pubsub_error = 'node-not-configurable'
+    pubsub_error = 'node-not-configurable'
 
 class CreateNodeNotConfigurable(PubSubError):
-	pubsub_error = 'node-not-configurable'
+    pubsub_error = 'node-not-configurable'
 
 error_map = {
-	backend.NotAuthorized:			'not-authorized',
-	backend.NodeNotFound:			'item-not-found',
-	backend.NoPayloadAllowed:		'bad-request',
-	backend.PayloadExpected:		'bad-request',
-	backend.NoInstantNodes:			'not-acceptable',
-	backend.NodeExists:				'conflict',
-	NotImplemented:					'feature-not-implemented',
-	OptionsUnavailable:				'feature-not-implemented',
-	SubscriptionOptionsUnavailable:	'not-acceptable',
-	NodeNotConfigurable:			'feature-not-implemented',
-	CreateNodeNotConfigurable:		'not-acceptable',
+    backend.NotAuthorized:          'not-authorized',
+    backend.NodeNotFound:           'item-not-found',
+    backend.NoPayloadAllowed:       'bad-request',
+    backend.PayloadExpected:        'bad-request',
+    backend.NoInstantNodes:         'not-acceptable',
+    backend.NodeExists:             'conflict',
+    backend.NotImplemented:         'feature-not-implemented',
+    NotImplemented:                 'feature-not-implemented',
+    OptionsUnavailable:             'feature-not-implemented',
+    SubscriptionOptionsUnavailable: 'not-acceptable',
+    NodeNotConfigurable:            'feature-not-implemented',
+    CreateNodeNotConfigurable:      'not-acceptable',
 }
 
-class ComponentServiceFromBackend(component.Service):
+class Service(component.Service):
+
+    __implements__ = component.IService
 
-	def __init__(self, backend):
-		self.backend = backend
-		self.backend.pubsub_service = self
-		
-	def componentConnected(self, xmlstream):
-		xmlstream.addObserver(PUBSUB_SET, self.onPubSub)
-		xmlstream.addObserver(PUBSUB_GET, self.onPubSub)
+    def __init__(self, backend):
+        self.backend = backend
+
+    def componentConnected(self, xmlstream):
+        pass
 
-	def getIdentities(self, node):
-		results = []
-		if not node:
-			results.append({
-				'category': 'pubsub',
-				'type': 'generic',
-				'name': 'Generic Pubsub Service'
-			})
-		return results
+    def error(self, failure, iq):
+        try: 
+            r = failure.trap(*error_map.keys())
+            xmpp_error.error_from_iq(iq, error_map[r], failure.value.msg)
+            if isinstance(failure.value, PubSubError) and \
+               failure.value.pubsub_error is not None:
+                iq.error.addElement((NS_PUBSUB_ERRORS,
+                                     failure.value.pubsub_error),
+                                    NS_PUBSUB_ERRORS)
+            return iq
+        except:
+            xmpp_error.error_from_iq(iq, 'internal-server-error')
+            self.send(iq)
+            raise
+    
+    def success(self, result, iq):
+        iq.swapAttributeValues("to", "from")
+        iq["type"] = 'result'
+        iq.children = result or []
+        return iq
 
-	def getFeatures(self, node):
-		return [
-			"http://jabber.org/protocol/pubsub#outcast-affil",
-			"http://jabber.org/protocol/pubsub#publisher-affil",
-			"http://jabber.org/protocol/pubsub#persistent-items",
-			]
+    def handler_wrapper(self, handler, iq):
+        try:
+            d = handler(iq)
+        except:
+            d = defer.fail()
+
+        d.addCallback(self.success, iq)
+        d.addErrback(self.error, iq)
+        d.addCallback(self.send)
+        iq.handled = True
+
+class ComponentServiceFromService(Service):
 
-	def error(self, failure, iq):
-		try: 
-			r = failure.trap(*error_map.keys())
-			xmpp_error.error_from_iq(iq, error_map[r], failure.value.msg)
-			if isinstance(failure.value, PubSubError) and \
-			   failure.value.pubsub_error is not None:
-				iq.error.addElement((NS_PUBSUB_ERRORS,
-					                 failure.value.pubsub_error),
-									NS_PUBSUB_ERRORS)
-			return iq
-		except:
-			xmpp_error.error_from_iq(iq, 'internal-server-error')
-			self.send(iq)
-			raise
-	
-	def success(self, result, iq):
-		iq.swapAttributeValues("to", "from")
-		iq["type"] = 'result'
-		iq.children = result or []
-		return iq
+    def getIdentities(self, node):
+        results = []
+        if not node:
+            results.append({
+                'category': 'pubsub',
+                'type': 'generic',
+                'name': 'Generic Pubsub Service'
+            })
+        return results
+
+    def getFeatures(self, node):
+        features = []
+
+        affiliations = self.backend.get_supported_affiliations()
+        if 'outcast' in affiliations:
+            features.append("http://jabber.org/protocol/pubsub#outcast-affil")
+
+        if 'publisher' in affiliations:
+            features.append("http://jabber.org/protocol/pubsub#publisher-affil")
+
+        # "http://jabber.org/protocol/pubsub#persistent-items"
+
+        return features
+
+components.registerAdapter(ComponentServiceFromService, backend.IBackendService, component.IService)
 
-	def onPubSub(self, iq):
-		for elem in iq.pubsub.elements():
-			if not elem.hasAttribute('xmlns'):
-				action = elem.name
-				break
+class ComponentServiceFromNotificationService(Service):
 
-		if not action:
-			return
+    def __init__(self, backend):
+        Service.__init__(self, backend)
+        self.backend.register_notifier(self.notify)
+        
+    def notify(self, object):
+        node_id = object["node_id"]
+        items = object["items"]
+        d = self.backend.get_notification_list(node_id, items)
+        d.addCallback(self._notify, node_id)
 
-		try:
-			try:
-				handler = getattr(self, 'on%s%s' % (action.capitalize(),
-													iq["type"].capitalize()))
-			except KeyError:
-				raise NotImplemented
-			else:
-				d = handler(iq)
-		except:
-			d = defer.fail()
-				
-		d.addCallback(self.success, iq)
-		d.addErrback(self.error, iq)
-		d.addCallback(self.send)
-		iq.handled = True
+    def _notify(self, list, node_id):
+        for recipient, items in list.items():
+            self._notify_recipient(recipient, node_id, items)
 
-	# action handlers
-
-	def onPublishSet(self, iq):
-		node = iq.pubsub.publish["node"]
+    def _notify_recipient(self, recipient, node_id, itemlist):
+        message = domish.Element((NS_COMPONENT, "message"))
+        message["from"] = self.parent.jabberId
+        message["to"] = recipient
+        event = message.addElement((NS_PUBSUB_EVENT, "event"), NS_PUBSUB_EVENT)
+        items = event.addElement("items")
+        items["node"] = node_id
+        items.children.extend(itemlist)
+        self.send(message)
 
-		items = []
-		for child in iq.pubsub.publish.children:
-			if child.__class__ == domish.Element and child.name == 'item':
-				items.append(child)
+components.registerAdapter(ComponentServiceFromNotificationService, backend.INotificationService, component.IService)
+
+class ComponentServiceFromPublishService(Service):
 
-		print items
+    def componentConnected(self, xmlstream):
+        xmlstream.addObserver(PUBSUB_PUBLISH, self.onPublish)
+
+    def onPublish(self, iq):
+        self.handler_wrapper(self._onPublish, iq)
 
-		return self.backend.do_publish(node,
-				                       jid.JID(iq["from"]).userhost(),
-									   items)
+    def _onPublish(self, iq):
+        node = iq.pubsub.publish["node"]
 
-	def onOptionsGet(self, iq):
-		raise OptionsUnavailable
+        items = []
+        for child in iq.pubsub.publish.children:
+            if child.__class__ == domish.Element and child.name == 'item':
+                items.append(child)
 
-	def onOptionsSet(self, iq):
-		raise OptionsUnavailable
+        print items
+
+        return self.backend.publish(node, items,
+                                    jid.JID(iq["from"]).userhostJID())
 
-	def onConfigureGet(self, iq):
-		raise NodeNotConfigurable
+components.registerAdapter(ComponentServiceFromPublishService, backend.IPublishService, component.IService)
+
+class ComponentServiceFromSubscriptionService(Service):
 
-	def onConfigureSet(self, iq):
-		raise NodeNotConfigurable
+    def componentConnected(self, xmlstream):
+        xmlstream.addObserver(PUBSUB_SUBSCRIBE, self.onSubscribe)
+
+    def onSubscribe(self, iq):
+        self.handler_wrapper(self._onSubscribe, iq)
 
-	def onSubscribeSet(self, iq):
-		if iq.pubsub.options:
-			raise SubscribeOptionsUnavailable
+    def _onSubscribe(self, iq):
+        if iq.pubsub.options:
+            raise SubscribeOptionsUnavailable
 
-		node_id = iq.pubsub.subscribe["node"]
-		subscriber = jid.JID(iq.pubsub.subscribe["jid"])
-		requestor = jid.JID(iq["from"]).userhostJID()
-		d = self.backend.do_subscribe(node_id, subscriber, requestor)
-		d.addCallback(self.return_subscription)
-		d.addCallback(self.succeed, iq)
-		d.addErrback(self.error, iq)
-		d.addCallback(self.send)
+        node_id = iq.pubsub.subscribe["node"]
+        subscriber = jid.JID(iq.pubsub.subscribe["jid"])
+        requestor = jid.JID(iq["from"]).userhostJID()
+        d = self.backend.do_subscribe(node_id, subscriber, requestor)
+        d.addCallback(self.return_subscription)
+        d.addCallback(self.succeed, iq)
+        d.addErrback(self.error, iq)
+        d.addCallback(self.send)
 
-	def return_subscription(self, result):
-		reply = domish.Element("pubsub", NS_PUBSUB)
-		entity = reply.addElement("entity")
-		entity["node"] = result["node"]
-		entity["jid"] = result["jid"].full()
-		entity["affiliation"] = result["affiliation"]
-		entity["subscription"] = result["subscription"]
-		return reply
+    def _onConfigureGet(self, iq):
+        raise NodeNotConfigurable
+
+    def _onConfigureSet(self, iq):
+        raise NodeNotConfigurable
 
-	def onCreateSet(self, iq):
-		if iq.pubsub.options:
-			raise CreateNodeNotConfigurable
+    def return_subscription(self, result):
+        reply = domish.Element("pubsub", NS_PUBSUB)
+        entity = reply.addElement("entity")
+        entity["node"] = result["node"]
+        entity["jid"] = result["jid"].full()
+        entity["affiliation"] = result["affiliation"]
+        entity["subscription"] = result["subscription"]
+        return reply
 
-		node = iq.pubsub.create["node"]
-		owner = jid.JID(iq["from"]).userhostJID()
+components.registerAdapter(ComponentServiceFromSubscriptionService, backend.ISubscriptionService, component.IService)
+
+class ComponentServiceFromNodeCreationService(Service):
 
-		d = self.backend.create_node(node, owner)
-		d.addCallback(self.return_create_response, iq)
-		return d
+    def componentConnected(self, xmlstream):
+        xmlstream.addObserver(PUBSUB_CREATE, self.onCreate)
+
+    def onCreate(self, iq):
+        self.handler_wrapper(self._onCreate, iq)
 
-	def return_create_response(self, result, iq):
-		if iq.pubsub.create["node"] is None:
-			reply = domish.Element('pubsub', NS_PUBSUB)
-			entity = reply.addElement('create')
-			entity['node'] = result['node_id']
-			return reply
+    def _onCreate(self, iq):
+        if iq.pubsub.options:
+            raise CreateNodeNotConfigurable
 
-	# other methods
+        node = iq.pubsub.create["node"]
+        owner = jid.JID(iq["from"]).userhostJID()
 
-	def do_notification(self, list, node):
-		for recipient, items in list.items():
-			self.notify(node, items, recipient)
+        d = self.backend.create_node(node, owner)
+        d.addCallback(self.return_create_response, iq)
+        return d
 
-	def notify(self, node, itemlist, recipient):
-		message = domish.Element((NS_COMPONENT, "message"))
-		message["from"] = self.parent.jabberId
-		message["to"] = recipient
-		event = message.addElement((NS_PUBSUB_EVENT, "event"), NS_PUBSUB_EVENT)
-		items = event.addElement("items")
-		items["node"] = node
-		items.children.extend(itemlist)
-		self.send(message)
-		
-components.registerAdapter(ComponentServiceFromBackend, backend.IService, component.IService)
+    def _onOptionsGet(self, iq):
+        raise OptionsUnavailable
+
+    def _onOptionsSet(self, iq):
+        raise OptionsUnavailable
 
+    def return_create_response(self, result, iq):
+        if iq.pubsub.create["node"] is None:
+            reply = domish.Element('pubsub', NS_PUBSUB)
+            entity = reply.addElement('create')
+            entity['node'] = result['node_id']
+            return reply
+
+components.registerAdapter(ComponentServiceFromNodeCreationService, backend.INodeCreationService, component.IService)