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
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
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 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)