コード例 #1
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def checkToken(self, typebyte, size):
     if self.classname is None:
         if typebyte not in (tokens.STRING, tokens.VOCAB):
             raise BananaError("InstanceUnslicer classname must be string")
     elif self.attrname is None:
         if typebyte not in (tokens.STRING, tokens.VOCAB):
             raise BananaError("InstanceUnslicer keys must be STRINGs")
コード例 #2
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def checkToken(self, typebyte, size):
     if self.key is None:
         if typebyte != tokens.INT:
             raise BananaError("VocabUnslicer only accepts INT keys")
     else:
         if typebyte != tokens.STRING:
             raise BananaError("VocabUnslicer only accepts STRING values")
コード例 #3
0
ファイル: call.py プロジェクト: UstadMobile/eXePUB
 def checkToken(self, typebyte, size):
     if self.request == None:
         if typebyte != tokens.INT:
             raise BananaError("request ID must be an INT")
     elif not self.gotFailure:
         self.fConstraint.checkToken(typebyte, size)
     else:
         raise BananaError("stop sending me stuff!")
コード例 #4
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def checkToken(self, typebyte, size):
     if self.state == 0:
         if typebyte not in (tokens.STRING, tokens.VOCAB):
             raise BananaError("MethodUnslicer methodname must be a string")
     elif self.state == 1:
         if typebyte != tokens.OPEN:
             raise BananaError("MethodUnslicer instance must be OPEN")
     elif self.state == 2:
         if typebyte != tokens.OPEN:
             raise BananaError("MethodUnslicer class must be an OPEN")
コード例 #5
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def doOpen(self, opentype):
     # check the opentype
     if self.state == 1:
         if opentype[0] not in ("instance", "none"):
             raise BananaError("MethodUnslicer instance must be " +
                               "instance or None")
     elif self.state == 2:
         if opentype[0] != "class":
             raise BananaError("MethodUnslicer class must be a class")
     unslicer = self.open(opentype)
     # TODO: apply constraint
     return unslicer
コード例 #6
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def receiveKey(self, key):
     # I don't think it is legal (in python) to use an incomplete object
     # as a dictionary key, because you must have all the contents to
     # hash it. Someone could fake up a token stream to hit this case,
     # however: OPEN(dict), OPEN(tuple), OPEN(reference), 0, CLOSE, CLOSE,
     # "value", CLOSE
     if isinstance(key, Deferred):
         raise BananaError("incomplete object as dictionary key")
     try:
         if self.d.has_key(key):
             raise BananaError("duplicate key '%s'" % key)
     except TypeError:
         raise BananaError("unhashable key '%s'" % key)
     self.key = key
コード例 #7
0
    def handleViolation(self, f, methname, inOpen=False, inClose=False):
        """An Unslicer has decided to give up, or we have given up on it
        (because we received an ABORT token).
        """

        where = self.describeReceive()
        f.value.setLocation(where)

        if self.debugReceive:
            print " handleViolation-%s (inOpen=%s, inClose=%s): %s" \
                  % (methname, inOpen, inClose, f)

        assert isinstance(f, BananaFailure)

        if self.logViolations:
            log.msg("Violation in %s at %s" % (methname, where))
            log.err(f)

        if inOpen:
            self.discardCount += 1
            if self.debugReceive:
                print "  ++discardCount (inOpen), now %d" % self.discardCount

        while True:
            # tell the parent that their child is dead. This is useful for
            # things like PB, which may want to errback the current request.
            if self.debugReceive:
                print " reportViolation to %s" % self.receiveStack[-1]
            f = self.receiveStack[-1].reportViolation(f)
            if not f:
                # they absorbed the failure
                if self.debugReceive:
                    print "  buck stopped, error absorbed"
                break

            # the old top wants to propagate it upwards
            if self.debugReceive:
                print "  popping %s" % self.receiveStack[-1]
            if not inClose:
                self.discardCount += 1
                if self.debugReceive:
                    print "  ++discardCount (pop, not inClose), now %d" \
                          % self.discardCount
            inClose = False

            old = self.receiveStack.pop()

            try:
                # TODO: if handleClose encountered a Violation in .finish,
                # we will end up calling it a second time
                old.finish()  # ??
            except Violation:
                pass  # they've already failed once

            if not self.receiveStack:
                # now there's nobody left to create new Unslicers, so we
                # must drop the connection
                why = "Oh my god, you killed the RootUnslicer! " + \
                      "You bastard!!"
                raise BananaError(why)
コード例 #8
0
    def receiveClose(self):
        # three things must happen before our request is complete:
        #   receiveClose has occurred
        #   the receiveChild object deferred (if any) has fired
        #   ready_deferred has finished
        # If ready_deferred errbacks, provide its failure object to the
        # request. If not, provide the request with whatever receiveChild
        # got.

        if not self._child_deferred:
            raise BananaError("Answer didn't include an answer")

        if self._ready_deferreds:
            d = AsyncAND(self._ready_deferreds)
        else:
            d = defer.succeed(None)

        def _ready(res):
            return self._child_deferred

        d.addCallback(_ready)

        def _done(res):
            self.request.complete(res)

        def _fail(f):
            # we hit here if any of the _ready_deferreds fail (i.e a Gift
            # failed to resolve), or if the _child_deferred fails (not sure
            # how this could happen). I think it's ok to return a local
            # exception (instead of a RemoteException) for both.
            self.request.fail(f)

        d.addCallbacks(_done, _fail)

        return None, None
コード例 #9
0
 def checkToken(self, typebyte, size):
     if self.attrname == None:
         if typebyte not in (tokens.STRING, tokens.VOCAB):
             raise BananaError("RemoteCopyUnslicer keys must be STRINGs")
     else:
         if self.attrConstraint:
             self.attrConstraint.checkToken(typebyte, size)
コード例 #10
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def receiveChild(self, obj, ready_deferred=None):
     assert not isinstance(obj, Deferred)
     assert ready_deferred is None
     if self.finished:
         raise BananaError("FunctionUnslicer only accepts one string")
     self.finished = True
     # TODO: taste here!
     self.func = reflect.namedObject(obj)
コード例 #11
0
 def checkToken(self, typebyte, size):
     # TODO: limit strings by returning a number instead of None
     if self.stage == 0:
         if typebyte != tokens.INT:
             raise BananaError("request ID must be an INT")
     elif self.stage == 1:
         if typebyte not in (tokens.INT, tokens.NEG):
             raise BananaError("object ID must be an INT/NEG")
     elif self.stage == 2:
         if typebyte not in (tokens.STRING, tokens.VOCAB):
             raise BananaError("method name must be a STRING")
         # TODO: limit to longest method name of self.obj in the interface
     elif self.stage == 3:
         if typebyte != tokens.OPEN:
             raise BananaError("arguments must be an 'arguments' sequence")
     else:
         raise BananaError("too many objects given to CallUnslicer")
コード例 #12
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def receiveChild(self, obj, ready_deferred=None):
     assert ready_deferred is None
     if self.classname is None:
         self.classname = obj
         self.attrname = None
     elif self.attrname is None:
         self.attrname = obj
     else:
         if isinstance(obj, Deferred):
             # TODO: this is an artificial restriction, and it might
             # be possible to remove it, but I need to think through
             # it carefully first
             raise BananaError("unreferenceable object in attribute")
         if self.d.has_key(self.attrname):
             raise BananaError("duplicate attribute name '%s'" % name)
         self.setAttribute(self.attrname, obj)
         self.attrname = None
コード例 #13
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def receiveChild(self, obj, ready_deferred=None):
     assert not isinstance(obj, Deferred)
     assert ready_deferred is None
     if self.finished:
         raise BananaError("ModuleUnslicer only accepts one string")
     self.finished = True
     # TODO: taste here!
     mod = __import__(obj, {}, {}, "x")
     self.mod = mod
コード例 #14
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def receiveChild(self, token, ready_deferred=None):
     assert not isinstance(token, Deferred)
     assert ready_deferred is None
     if self.key is None:
         if self.d.has_key(token):
             raise BananaError("duplicate key '%s'" % token)
         self.key = token
     else:
         self.d[self.key] = token
         self.key = None
コード例 #15
0
 def receiveChild(self, obj, ready_deferred=None):
     assert not isinstance(obj, Deferred)
     assert ready_deferred is None
     if self.finished:
         raise BananaError("ReferenceUnslicer only accepts one int")
     self.obj = self.protocol.getObject(obj)
     self.finished = True
     # assert that this conforms to the constraint
     if self.constraint:
         self.constraint.checkObject(self.obj, True)
コード例 #16
0
ファイル: call.py プロジェクト: UstadMobile/eXePUB
 def checkToken(self, typebyte, size):
     # TODO: limit strings by returning a number instead of None
     if self.stage == 0:
         if typebyte != tokens.INT:
             raise BananaError("request ID must be an INT")
     elif self.stage == 1:
         if typebyte not in (tokens.INT, tokens.NEG):
             raise BananaError("object ID must be an INT/NEG")
     elif self.stage == 2:
         if typebyte not in (tokens.STRING, tokens.VOCAB):
             raise BananaError("method name must be a STRING")
         # TODO: limit to longest method name of self.obj in the interface
     elif self.stage == 3:
         if self.argname == None:
             if typebyte not in (tokens.STRING, tokens.VOCAB):
                 raise BananaError("argument name must be a STRING")
             # TODO: limit to the longest argname in the method
         else:
             if self.argConstraint:
                 self.argConstraint.checkToken(typebyte, size)
コード例 #17
0
 def receiveClose(self):
     if self.stage != 4:
         raise BananaError("'call' sequence ended too early")
     # time to create the InboundDelivery object so we can queue it
     delivery = InboundDelivery(self.broker, self.reqID, self.obj,
                                self.interface, self.methodname,
                                self.methodSchema, self.allargs)
     ready_deferred = None
     if self._ready_deferreds:
         ready_deferred = AsyncAND(self._ready_deferreds)
     return delivery, ready_deferred
コード例 #18
0
 def checkToken(self, typebyte, size):
     if self.numargs is None:
         # waiting for positional-arg count
         if typebyte != tokens.INT:
             raise BananaError("posarg count must be an INT")
         return
     if len(self.args) < self.numargs:
         # waiting for a positional arg
         if self.argConstraint:
             self.argConstraint.checkToken(typebyte, size)
         return
     if self.argname is None:
         # waiting for the name of a keyword arg
         if typebyte not in (tokens.STRING, tokens.VOCAB):
             raise BananaError("kwarg name must be a STRING")
         # TODO: limit to longest argument name of the method?
         return
     # waiting for the value of a kwarg
     if self.argConstraint:
         self.argConstraint.checkToken(typebyte, size)
コード例 #19
0
 def receiveChild(self, obj, ready_deferred=None):
     assert not isinstance(obj, defer.Deferred)
     assert ready_deferred is None
     if self.attrname == None:
         attrname = obj
         if self.d.has_key(attrname):
             raise BananaError("duplicate attribute name '%s'" % attrname)
         s = self.schema
         if s:
             accept, self.attrConstraint = s.getAttrConstraint(attrname)
             assert accept
         self.attrname = attrname
     else:
         if isinstance(obj, defer.Deferred):
             # TODO: this is an artificial restriction, and it might
             # be possible to remove it, but I need to think through
             # it carefully first
             raise BananaError("unreferenceable object in attribute")
         self.setAttribute(self.attrname, obj)
         self.attrname = None
         self.attrConstraint = None
コード例 #20
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def openerCheckToken(self, typebyte, size, opentype):
     if typebyte == tokens.STRING:
         if size > self.maxIndexLength:
             why = "STRING token is too long, %d>%d" % \
                   (size, self.maxIndexLength)
             raise Violation(why)
     elif typebyte == tokens.VOCAB:
         return
     else:
         # TODO: hack for testing
         raise Violation("index token 0x%02x not STRING or VOCAB" % \
                           ord(typebyte))
         raise BananaError("index token 0x%02x not STRING or VOCAB" % \
                           ord(typebyte))
コード例 #21
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def receiveClose(self):
     if self.state != 3:
         raise BananaError("MethodUnslicer requires three objects")
     if self.im_self is None:
         meth = getattr(self.im_class, self.im_func)
         # getattr gives us an unbound method
         return meth, None
     # TODO: late-available instances
     #if isinstance(self.im_self, NotKnown):
     #    im = _InstanceMethod(self.im_name, self.im_self, self.im_class)
     #    return im
     meth = self.im_class.__dict__[self.im_func]
     # whereas __dict__ gives us a function
     im = instancemethod(meth, self.im_self, self.im_class)
     return im, None
コード例 #22
0
ファイル: slicer.py プロジェクト: UstadMobile/eXePUB
 def receiveChild(self, obj, ready_deferred=None):
     assert not isinstance(obj, Deferred)
     assert ready_deferred is None
     if self.state == 0:
         self.im_func = obj
         self.state = 1
     elif self.state == 1:
         assert type(obj) in (types.InstanceType, types.NoneType)
         self.im_self = obj
         self.state = 2
     elif self.state == 2:
         assert type(obj) == types.ClassType  # TODO: new-style classes?
         self.im_class = obj
         self.state = 3
     else:
         raise BananaError("MethodUnslicer only accepts three objects")
コード例 #23
0
    def handleClose(self, closeCount):
        if self.debugReceive:
            print "handleClose(%d)" % closeCount
        if self.receiveStack[-1].openCount != closeCount:
            raise BananaError("lost sync, got CLOSE(%d) but expecting %s" \
                              % (closeCount, self.receiveStack[-1].openCount))

        child = self.receiveStack[-1]  # don't pop yet: describe() needs it

        try:
            obj, ready_deferred = child.receiveClose()
        except Violation:
            # the child is contaminated. However, they're finished, so we
            # don't have to discard anything. Just give an Failure to the
            # parent instead of the object they would have returned.
            f = BananaFailure()
            self.handleViolation(f, "receiveClose", inClose=True)
            return
        if self.debugReceive: print "receiveClose returned", obj

        try:
            child.finish()
        except Violation:
            # .finish could raise a Violation if an object that references
            # the child is just now deciding that they don't like it
            # (perhaps their TupleConstraint couldn't be asserted until the
            # tuple was complete and referenceable). In this case, the child
            # has produced a valid object, but an earlier (incomplete)
            # object is not valid. So we treat this as if this child itself
            # raised the Violation. The .where attribute will point to this
            # child, which is the node that caused somebody problems, but
            # will be marked <FINISH>, which indicates that it wasn't the
            # child itself which raised the Violation. TODO: not true
            #
            # TODO: it would be more useful if the UF could also point to
            # the completing object (the one which raised Violation).

            f = BananaFailure()
            self.handleViolation(f, "finish", inClose=True)
            return

        self.receiveStack.pop()

        # now deliver the object to the parent
        self.handleToken(obj, ready_deferred)
コード例 #24
0
ファイル: banana.py プロジェクト: UstadMobile/eXePUB
    def handleClose(self, closeCount):
        if self.debugReceive:
            print "handleClose(%d)" % closeCount
        if self.receiveStack[-1].openCount != closeCount:
            raise BananaError("lost sync, got CLOSE(%d) but expecting %s" \
                              % (closeCount, self.receiveStack[-1].openCount))

        child = self.receiveStack[-1]  # don't pop yet: describe() needs it

        try:
            obj, ready_deferred = child.receiveClose()
        except Violation, v:
            # the child is contaminated. However, they're finished, so we
            # don't have to discard anything. Just give an Failure to the
            # parent instead of the object they would have returned.
            f = BananaFailure()
            self.handleViolation(f, "receiveClose", inClose=True)
            return
コード例 #25
0
 def receiveClose(self):
     if self.debug:
         log.msg("%s.receiveClose: %s %s %s" %
                 (self, self.closed, self.num_unreferenceable_children,
                  len(self._ready_deferreds)))
     if (self.numargs is None or len(self.args) < self.numargs
             or self.argname is not None):
         raise BananaError("'arguments' sequence ended too early")
     self.closed = True
     dl = []
     if self.num_unreferenceable_children:
         d = self._all_children_are_referenceable_d = defer.Deferred()
         dl.append(d)
     dl.extend(self._ready_deferreds)
     ready_deferred = None
     if dl:
         ready_deferred = AsyncAND(dl)
     return self, ready_deferred
コード例 #26
0
ファイル: call.py プロジェクト: UstadMobile/eXePUB
 def checkToken(self, typebyte, size):
     if self.request is None:
         if typebyte != tokens.INT:
             raise BananaError("request ID must be an INT")
     elif not self.haveResults:
         if self.resultConstraint:
             try:
                 self.resultConstraint.checkToken(typebyte, size)
             except Violation, v:
                 # improve the error message
                 if v.args:
                     # this += gives me a TypeError "object doesn't
                     # support item assignment", which confuses me
                     #v.args[0] += " in inbound method results"
                     why = v.args[0] + " in inbound method results"
                     v.args = why,
                 else:
                     v.args = ("in inbound method results", )
                 raise v  # this will errback the request
コード例 #27
0
    def handleSendViolation(self, f, doPop, sendAbort):
        f.value.setLocation(self.describeSend())

        while True:
            top = self.slicerStack[-1][0]

            if self.debugSend:
                print " handleSendViolation.loop, top=%s" % top

            # should we send an ABORT? Only if an OPEN has been sent, which
            # happens in pushSlicer (if at all).
            if sendAbort:
                lastOpenID = self.slicerStack[-1][2]
                if lastOpenID is not None:
                    if self.debugSend:
                        print "  sending ABORT(%s)" % lastOpenID
                    self.sendAbort(lastOpenID)

            # should we pop the Slicer? yes
            if doPop:
                if self.debugSend: print "  popping %s" % top
                self.popSlicer()
                if not self.slicerStack:
                    if self.debugSend: print "RootSlicer died!"
                    raise BananaError("Hey! You killed the RootSlicer!")
                top = self.slicerStack[-1][0]

            # now inform the parent. If they also give up, we will
            # loop, popping more Slicers off the stack until the
            # RootSlicer ignores the error

            if self.debugSend:
                print "  notifying parent", top
            f = top.childAborted(f)

            if f:
                doPop = True
                sendAbort = True
                continue
            else:
                break
コード例 #28
0
ファイル: call.py プロジェクト: UstadMobile/eXePUB
 def receiveClose(self):
     if self.stage != 3 or self.argname != None:
         raise BananaError("'call' sequence ended too early")
     self.stage = 4
     return self.checkComplete()
コード例 #29
0
ファイル: call.py プロジェクト: UstadMobile/eXePUB
    def receiveChild(self, token, ready_deferred=None):
        if self.stage < 3:
            assert not isinstance(token, defer.Deferred)
            assert ready_deferred is None
        #print "CallUnslicer.receiveChild [s%d]" % self.stage, repr(token)
        # TODO: if possible, return an error to the other side

        if self.stage == 0:  # reqID
            # we don't yet know which reqID to send any failure to
            self.reqID = token
            self.stage += 1
            assert not self.broker.activeLocalCalls.get(self.reqID)
            self.broker.activeLocalCalls[self.reqID] = self
            return

        if self.stage == 1:  # objID
            # this might raise an exception if objID is invalid
            self.objID = token
            self.obj = self.broker.getMyReferenceByCLID(token)
            #iface = self.broker.getRemoteInterfaceByName(token)
            if self.objID < 0:
                self.interface = None
            else:
                self.interface = self.obj.getInterface()
            self.stage = 2
            return

        if self.stage == 2:  # methodname
            # validate the methodname, get the schema. This may raise an
            # exception for unknown methods
            if self.objID < 0:
                # the target is a bound method
                self.methodSchema = getattr(self.obj, "methodSchema", None)
                self.methodname = None  # TODO: give it something useful
                if self.broker.requireSchema and not self.methodSchema:
                    why = "This broker does not accept unconstrained " + \
                          "method calls"
                    raise Violation(why)
                self.stage = 3
                return

            methodname = token
            # must find the schema, using the interfaces

            # TODO: getSchema should probably be in an adapter instead of in
            # a pb.Referenceable base class. Old-style (unconstrained)
            # flavors.Referenceable should be adapted to something which
            # always returns None

            # TODO: make this faster. A likely optimization is to take a
            # tuple of components.getInterfaces(obj) and use it as a cache
            # key. It would be even faster to use obj.__class__, but that
            # would probably violate the expectation that instances can
            # define their own __implements__ (independently from their
            # class). If this expectation were to go away, a quick
            # obj.__class__ -> RemoteReferenceSchema cache could be built.

            ms = None

            if self.interface:
                # they are calling an interface+method pair
                ms = self.interface.get(methodname)
                if not ms:
                    why = "method '%s' not defined in %s" % \
                          (methodname, self.interface.__remote_name__)
                    raise Violation(why)

            self.methodSchema = ms
            self.methodname = methodname

            if self.broker.requireSchema and not self.methodSchema:
                why = "This broker does not accept unconstrained method calls"
                raise Violation(why)

            self.stage = 3
            return

        if self.stage == 3:  # argname/value pairs
            if self.argname == None:
                assert not isinstance(token, defer.Deferred)
                assert ready_deferred is None
                argname = token
                if self.args.has_key(argname):
                    raise BananaError("duplicate argument '%s'" % argname)
                ms = self.methodSchema
                if ms:
                    # if the argname is invalid, this may raise Violation
                    accept, self.argConstraint = ms.getArgConstraint(argname)
                    assert accept  # TODO: discard if not
                self.argname = argname
            else:
                argvalue = token
                if isinstance(argvalue, defer.Deferred):
                    self.num_unreferenceable_children += 1
                    argvalue.addCallback(self.update, self.argname)
                    argvalue.addErrback(self.explode)
                self.args[self.argname] = argvalue
                self.argname = None
                if ready_deferred:
                    self.num_unready_children += 1
                    ready_deferred.addCallback(self.ready)
コード例 #30
0
ファイル: call.py プロジェクト: UstadMobile/eXePUB
            if self.resultConstraint:
                try:
                    self.resultConstraint.checkToken(typebyte, size)
                except Violation, v:
                    # improve the error message
                    if v.args:
                        # this += gives me a TypeError "object doesn't
                        # support item assignment", which confuses me
                        #v.args[0] += " in inbound method results"
                        why = v.args[0] + " in inbound method results"
                        v.args = why,
                    else:
                        v.args = ("in inbound method results", )
                    raise v  # this will errback the request
        else:
            raise BananaError("stop sending me stuff!")

    def doOpen(self, opentype):
        if self.resultConstraint:
            self.resultConstraint.checkOpentype(opentype)
            # TODO: improve the error message
        unslicer = self.open(opentype)
        if unslicer:
            if self.resultConstraint:
                unslicer.setConstraint(self.resultConstraint)
        return unslicer

    def receiveChild(self, token, ready_deferred=None):
        assert not isinstance(token, defer.Deferred)
        assert ready_deferred is None
        if self.request == None: