Пример #1
0
    def resolveDomainValue(self, maybeEntityProxy, detectDeadEntities):
        """Convert a client-side value into a domain value.

        @param maybeEntityProxy the client object to resolve
        @param detectDeadEntities if <code>true</code> this method will throw a
                 ReportableException containing a {@link DeadEntityException}
                 if an EntityProxy cannot be resolved
        """
        if isinstance(maybeEntityProxy, BaseProxy):
            bean = AutoBeanUtils.getAutoBean(maybeEntityProxy)
            domain = bean.getTag(Constants.DOMAIN_OBJECT)
            if domain is None and detectDeadEntities:
                raise ReportableException(DeadEntityException(
                        'The requested entity is not available on the server'))
            return domain
        elif isinstance(maybeEntityProxy, (list, set)):
            if isinstance(maybeEntityProxy, list):
                accumulator = list()
            elif isinstance(maybeEntityProxy, set):
                accumulator = set()
            else:
                raise ReportableException('Unsupported collection type '
                        + maybeEntityProxy.getClass().getName())
            for o in maybeEntityProxy:
                accumulator.add(self.resolveDomainValue(o, detectDeadEntities))
            return accumulator
        return maybeEntityProxy
Пример #2
0
    def resolveDomainValue(self, maybeEntityProxy, detectDeadEntities):
        """Convert a client-side value into a domain value.

        @param maybeEntityProxy the client object to resolve
        @param detectDeadEntities if <code>true</code> this method will throw a
                 ReportableException containing a {@link DeadEntityException}
                 if an EntityProxy cannot be resolved
        """
        if isinstance(maybeEntityProxy, BaseProxy):
            bean = AutoBeanUtils.getAutoBean(maybeEntityProxy)
            domain = bean.getTag(Constants.DOMAIN_OBJECT)
            if domain is None and detectDeadEntities:
                raise ReportableException(
                    DeadEntityException(
                        'The requested entity is not available on the server'))
            return domain
        elif isinstance(maybeEntityProxy, (list, set)):
            if isinstance(maybeEntityProxy, list):
                accumulator = list()
            elif isinstance(maybeEntityProxy, set):
                accumulator = set()
            else:
                raise ReportableException(
                    'Unsupported collection type ' +
                    maybeEntityProxy.getClass().getName())
            for o in maybeEntityProxy:
                accumulator.add(self.resolveDomainValue(o, detectDeadEntities))
            return accumulator
        return maybeEntityProxy
Пример #3
0
    def resolveClientValue(self, domainValue, clientTypeOrAssignableTo, propertyRefs=None):
        """Given a domain object, return a value that can be encoded by the client.

        Creates a Resolution object that holds a client value that represents the
        given domain value. The resolved client value will be assignable to
        {@code clientType}.

        @param domainValue the domain object to be converted into a client-side
                 value
        @param assignableTo the type in the client to which the resolved value
                 should be assignable. A value of {@code null} indicates that any
                 resolution will suffice.
        @param propertyRefs the property references requested by the client
        """
        if propertyRefs is None:
            clientType = clientTypeOrAssignableTo
            if domainValue is None:
                return Resolution(None)
            anyType = clientType is None
            if anyType:
                clientType = object()
            assignableTo = TypeUtils.ensureBaseType(clientType)
            key = ResolutionKey(domainValue, clientType)
            previous = self._resolved[key]

            if (previous is not None
                    and assignableTo.isInstance(previous.getClientObject())):
                return previous

            returnClass = self._service.resolveClientType(domainValue.getClass(),
                    assignableTo, True)
            if anyType:
                assignableTo = returnClass

            # Pass simple values through
            if ValueCodex.canDecode(returnClass):
                return self.makeResolution(domainValue)

            # Convert entities to EntityProxies or EntityProxyIds
            isProxy = BaseProxy.isAssignableFrom(returnClass)
            isId = issubclass(returnClass, EntityProxyId)
            if isProxy or isId:
                proxyClass = returnClass.asSubclass(BaseProxy)
                return self.resolveClientProxy(domainValue, proxyClass, key)
            # Convert collections
            if issubclass(returnClass, Collection):
                if issubclass(returnClass, list):
                    accumulator = list()
                elif issubclass(returnClass, set):
                    accumulator = set()
                else:
                    raise ReportableException('Unsupported collection type'
                            + returnClass.getName())
                elementType = TypeUtils.getSingleParameterization(Collection, clientType)
                for o in domainValue:
                    accumulator.add(self.resolveClientValue(o, elementType).getClientObject())
                return self.makeResolution(accumulator)
            raise ReportableException('Unsupported domain type ' + returnClass.getCanonicalName())
        else:
            assignableTo = clientTypeOrAssignableTo
            toReturn = self.resolveClientValue(domainValue, assignableTo)
            if toReturn is None:
                return None
            self.addPathsToResolution(toReturn, '',
                    self.expandPropertyRefs(propertyRefs))
            while len(self._toProcess) > 0:
                working = list(self._toProcess)
                self._toProcess.clear()
                for resolution in working:
                    if resolution.hasWork():
                        bean = AutoBeanUtils.getAutoBean(resolution.getClientObject())
                        bean.accept(self.PropertyResolver(resolution))
            return toReturn.getClientObject()
Пример #4
0
    def resolveClientValue(self,
                           domainValue,
                           clientTypeOrAssignableTo,
                           propertyRefs=None):
        """Given a domain object, return a value that can be encoded by the client.

        Creates a Resolution object that holds a client value that represents the
        given domain value. The resolved client value will be assignable to
        {@code clientType}.

        @param domainValue the domain object to be converted into a client-side
                 value
        @param assignableTo the type in the client to which the resolved value
                 should be assignable. A value of {@code null} indicates that any
                 resolution will suffice.
        @param propertyRefs the property references requested by the client
        """
        if propertyRefs is None:
            clientType = clientTypeOrAssignableTo
            if domainValue is None:
                return Resolution(None)
            anyType = clientType is None
            if anyType:
                clientType = object()
            assignableTo = TypeUtils.ensureBaseType(clientType)
            key = ResolutionKey(domainValue, clientType)
            previous = self._resolved[key]

            if (previous is not None
                    and assignableTo.isInstance(previous.getClientObject())):
                return previous

            returnClass = self._service.resolveClientType(
                domainValue.getClass(), assignableTo, True)
            if anyType:
                assignableTo = returnClass

            # Pass simple values through
            if ValueCodex.canDecode(returnClass):
                return self.makeResolution(domainValue)

            # Convert entities to EntityProxies or EntityProxyIds
            isProxy = BaseProxy.isAssignableFrom(returnClass)
            isId = issubclass(returnClass, EntityProxyId)
            if isProxy or isId:
                proxyClass = returnClass.asSubclass(BaseProxy)
                return self.resolveClientProxy(domainValue, proxyClass, key)
            # Convert collections
            if issubclass(returnClass, Collection):
                if issubclass(returnClass, list):
                    accumulator = list()
                elif issubclass(returnClass, set):
                    accumulator = set()
                else:
                    raise ReportableException('Unsupported collection type' +
                                              returnClass.getName())
                elementType = TypeUtils.getSingleParameterization(
                    Collection, clientType)
                for o in domainValue:
                    accumulator.add(
                        self.resolveClientValue(o,
                                                elementType).getClientObject())
                return self.makeResolution(accumulator)
            raise ReportableException('Unsupported domain type ' +
                                      returnClass.getCanonicalName())
        else:
            assignableTo = clientTypeOrAssignableTo
            toReturn = self.resolveClientValue(domainValue, assignableTo)
            if toReturn is None:
                return None
            self.addPathsToResolution(toReturn, '',
                                      self.expandPropertyRefs(propertyRefs))
            while len(self._toProcess) > 0:
                working = list(self._toProcess)
                self._toProcess.clear()
                for resolution in working:
                    if resolution.hasWork():
                        bean = AutoBeanUtils.getAutoBean(
                            resolution.getClientObject())
                        bean.accept(self.PropertyResolver(resolution))
            return toReturn.getClientObject()
    def createReturnOperations(self, operations, returnState, toProcess):
        for id_, bean in toProcess.iteritems():
            domainObject = bean.getTag(Constants.DOMAIN_OBJECT)
            if id_.isEphemeral() and returnState.isEntityType(id_.getProxyClass()):
                # See if the entity has been persisted in the meantime
                returnState.getResolver().resolveClientValue(domainObject,
                        id_.getProxyClass(), set())

            if (id_.isEphemeral() or id_.isSynthetic()) or (domainObject is None):
                # If the object isn't persistent, there's no reason to send an update
                writeOperation = None
            elif not self._service.isLive(domainObject):
                writeOperation = WriteOperation.DELETE
            elif id_.wasEphemeral():
                writeOperation = WriteOperation.PERSIST
            else:
                writeOperation = WriteOperation.UPDATE

            version = None
            if ((writeOperation == WriteOperation.PERSIST)
                    or (writeOperation == WriteOperation.UPDATE)):
                # If we're sending an operation, the domain object must be persistent.
                # This means that it must also have a non-null version.
                domainVersion = self._service.getVersion(domainObject)
                if domainVersion is None:
                    raise UnexpectedException('The persisted entity with id '
                            + self._service.getId(domainObject)
                            + ' has a null version', None)
                version = returnState.flatten(domainVersion)

            inResponse = bean.getTag(Constants.IN_RESPONSE) is not None

            # Don't send any data back to the client for an update on an object that
            # isn't part of the response payload when the client's version matches
            # the domain version.
            if WriteOperation.UPDATE == writeOperation and not inResponse:
                previousVersion = bean.getTag(Constants.VERSION_PROPERTY_B64)
                if (version is not None and previousVersion is not None
                        and version == fromBase64(previousVersion)):
                    continue

            op = FACTORY.operation().as_()

            # Send a client id if the id is ephemeral or was previously associated
            # with a client id.
            if id_.wasEphemeral():
                op.setClientId(id_.getClientId())

            op.setOperation(writeOperation)

            # Only send properties for entities that are part of the return graph
            if inResponse:
                propertyMap = OrderedDict()
                # Add all non-null properties to the serialized form
                diff = AutoBeanUtils.getAllProperties(bean)
                for d in diff.iteritems():
                    value = d[1]
                    if value is not None:
                        propertyMap[d[0]] = EntityCodex.encode(returnState, value)
                op.setPropertyMap(propertyMap)

            if not id_.isEphemeral() and not id_.isSynthetic():
                # Send the server address only for persistent objects
                op.setServerId(toBase64(id_.getServerId()))

            if id_.isSynthetic():
                op.setStrength(Strength.SYNTHETIC)
                op.setSyntheticId(id_.getSyntheticId())
            elif id_.isEphemeral():
                op.setStrength(Strength.EPHEMERAL)

            op.setTypeToken(self._service.resolveTypeToken(id_.getProxyClass()))

            if version is not None:
                op.setVersion(toBase64(version.getPayload()))

            operations.add(op)