sisterserv.py :  » Network » Twisted » Twisted-1.0.3 » Twisted-1.0.3 » twisted » sister » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Twisted 
Twisted » Twisted 1.0.3 » Twisted 1.0.3 » twisted » sister » sisterserv.py
# -*- test-case-name: twisted.test.test_sister -*-

from twisted.spread.pb import Service,Perspective,Error
from twisted.spread.sturdy import PerspectiveConnector
from twisted.spread.flavors import Referenceable
from twisted.spread.refpath import PathReferenceDirectory

from twisted.internet import defer
from twisted.python import log
from twisted.python.failure import Failure
from twisted.cred.util import challenge

from twisted.cred.authorizer import DefaultAuthorizer
from twisted.cred.identity import Identity

    
class TicketAuthorizer(DefaultAuthorizer):
    
    def loadIdentity(self, identityName, keys):
        log.msg( "loading identity: %s:%s " %(identityName, keys))
        ticket = challenge()
        ident = Identity(identityName, self.application)
        ident.setPassword(ticket)
        for serviceName, perspectiveName in keys:
            ident.addKeyByString( serviceName, perspectiveName)
        ident.save()
        return ticket

True = 1
False = 0


class SisterMotherClient(Referenceable):
    def __init__(self, sistersrv):
        self.sistersrv = sistersrv

    def remote_loadResource(self, resourceType, resourceName, *args):
        return self.sistersrv.loadResource(resourceType, resourceName, args)

    def remote_callDistributed(self, srcResourceType, srcResourceName, destResourceType, destResourceName, methodName, args, kw):
        """invoked to call a method on a distributed object.
        """
        resource = self.sistersrv.ownedResources.get( (destResourceType, destResourceName), None)
        if not resource:
            return defer.fail("Sister does not own this resource")
        method = getattr(resource, "sister_%s" % methodName)
        fullArgs = (srcResourceType, srcResourceName) + args
        return apply(method, fullArgs, kw)
        
class SisterService(Service, Perspective):
    """A 'sister' object, managed by a mother server

    I am one of a set of sisters managed by a mother server. I use the mother server as
    a central manager of distributed objects, and as a mechanism for communicating to other
    sister servers.

    Distributed login into me is handled by passing identity resources - which I have a special
    loader and authorizer for.
    """

    def __init__(self, motherHost, motherPort, motherService, publishHost, localPort,
                 serviceName="twisted.sister", sharedSecret="shhh!", application=None):
        """Initialize me.

        (Application's authorizer must be a TicketAuthorizer, otherwise
        login won't work.)
        """
        Service.__init__(self, serviceName, application)
        Perspective.__init__(self, "sister")
        self.addPerspective(self)
        self.ownedResources = {}
        self.remoteResources = {}
        self.resourceLoaders = {}
        self.localPort = localPort
        self.sisterMother = SisterMotherClient(self)
        self.motherRef = PerspectiveConnector(
            motherHost, motherPort, "mother", sharedSecret,
            motherService, client = self.sisterMother)
        self.makeIdentity(sharedSecret)
        self.application.authorizer.sisterService = self
        ## identities are a special kind of resource
        self.registerResourceLoader("identity", self.application.authorizer.loadIdentity)
        
        # this will be the first method called on the mother connection once it is setup
        self.motherRef.callRemote('publishIP', publishHost, self.localPort, self.sisterMother)
        
    def startService(self):
        log.msg( 'starting sister, woo')

    def __getstate__(self):
        d = self.__dict__.copy()
        d['ownedResources'] = {}
        d['remoteResources'] = {}
        return d

    # XXX I know what these mean, don't delete them -glyph
    def _cbLocked(self, result, path):
        if result is None:
            obj = apply(func, args, kw)
            self.ownedResources[path] = obj
            return (True, obj)
        else:
            self.remoteResources[path] = result
            return (False, result)

    def _ebLocked(self, error, path):
        log.msg('not locked, panicking')
        raise error

    # OK now on to the real code

    def ownResource(self, resourceObject, resourceType, resourceName):
        log.msg('sister: owning resource %s/%s' % (resourceType, resourceName))
        self.ownedResources[resourceType, resourceName] = resourceObject
        return resourceObject

    def loadResource(self, resourceType, resourceName, args):
        """Returns a Deferred when the resource is loaded. This deferred may
        yield some data that is returned to the caller.

        """
        log.msg( 'sister: loading resource %s/%s' %(resourceType, resourceName))
        value = apply(self.resourceLoaders[resourceType], (resourceName,) + args)
        if isinstance(value, defer.Deferred):
            dvalue = value
        else:
            dvalue = defer.succeed(value)
        dvalue.addCallback(self.ownResource, resourceType, resourceName)
        return dvalue

    def registerResourceLoader(self, resourceType, resourceLoader):
        """Register a callable object to generate resources.

        The callable object may return Deferreds or synchronous values.
        """
        log.msg( 'sister: registering resource loader %s:%s' % (resourceType, repr(resourceLoader)))
        self.resourceLoaders[resourceType] = resourceLoader
        
    def unloadResource(self, resourceType, resourceName):
        print "sister: unloading (%s:%s)" %(resourceType, resourceName)
        del self.ownedResources[ (resourceType, resourceName) ]
        return self.motherRef.callRemote("unloadResource", resourceType, resourceName).addCallback(self._cbUnload)

    def _cbUnload(self, data):
        log.msg( "Unloaded resource: %s" % data)

    def callDistributed(self, caller, destResourceType, destResourceName, methodName, *args, **kw):
        """Call a distributed method on a resource managed by the
        sister network. This will call the method 'getResourceInfo' on
        the calling object which must return its resourceType and
        resourceName to be identified by.  The final method being called will have
        'sister_' prepended to its name and have the calling objects resourceType and
        resourceName as the first arguments.

        #NOTE: this method of identifying the calling object is temporary.. need to
               establish a better way which includes allowing the calling object to
               expose some data and/or functionality to the caller.
        """
        (srcResourceType, srcResourceName) = caller.getResourceInfo()
        if not self.ownedResources.has_key((srcResourceType,srcResourceName)):
            raise "sister does not own this resource!"
        fullArgs = ('callDistributed', srcResourceType, srcResourceName,
                    destResourceType, destResourceName, methodName) + args
        return apply( self.motherRef.callRemote, fullArgs, kw)


    def removeIdentity(self, identityName):
        self.application.authorizer.removeIdentity(identityName)
        self.unloadResource("identity", identityName)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.