def callAddNodeOnConduit(self, conduit_id, uid): obj = self.getPortalObject().portal_catalog.getObject(uid) conduit = getConduitByName(conduit_id) if obj.getPortalType() in ('Person', 'Organisation'): xml = obj.Node_asTioSafeXML() elif obj.getPortalType() in ('Product', 'Service'): xml = obj.Resource_asTioSafeXML() conduit.addNode(xml=etree.fromstring(xml), object=self)
def callAddNodeOnConduit(self, conduit_id, uid): obj = self.getPortalObject().portal_catalog.getObject(uid) conduit = getConduitByName(conduit_id) if obj.getPortalType() in ('Person', 'Organisation'): xml = obj.Node_asTioSafeXML() elif obj.getPortalType() in ('Product', 'Service'): xml = obj.Resource_asTioSafeXML() conduit.addNode(xml=etree.fromstring(xml), object=self)
def getGidFromObject(self, object, encoded=True): """ Returns the object gid """ o_base = aq_base(object) gid = None # first try with new method gid_generator = self.getGidGeneratorMethodId("") if gid_generator not in ("", None) and getattr(self, gid_generator, None): raw_gid = getattr(self, gid_generator)(object) else: # old way using the conduit conduit_name = self.getConduitModuleId() conduit = getConduitByName(conduit_name) raw_gid = conduit.getGidFromObject(object) if isinstance(raw_gid, unicode): raw_gid = raw_gid.encode('ascii', 'ignore') if encoded: gid = b16encode(raw_gid) else: gid = raw_gid return gid
def getConduit(self): """ Return the conduit object defined """ conduit_name = self.getConduitModuleId() return getConduitByName(conduit_name)
def _getSyncMLData(self, syncml_response, id_list=None): """ XXX Comment to be fixed """ if not id_list: syncml_logger.warning("Non optimal call to _getSyncMLData, no id list provided : %r" % (id_list)) else: syncml_logger.info("getSyncMLData, id list provided %s" % (id_list,)) conduit = self.getConduit() finished = True if isinstance(conduit, basestring): conduit = getConduitByName(conduit) try: object_list = self.getDocumentList(id_list=id_list) except TypeError: # Old style script warn("Script %s does not accept id_list paramater" % (self.getListMethodId(),), DeprecationWarning) object_list = self.getDocumentList() loop = 0 traverse = self.getPortalObject().restrictedTraverse alert_code = self.getSyncmlAlertCode() sync_all = alert_code in ("refresh_from_client_only", "slow_sync") # XXX Quick & dirty hack to prevent signature creation, this must be defined # on pub/sub instead create_signature = alert_code != "refresh_from_client_only" if not len(object_list) and id_list: syncml_logger.warning("No object retrieved althoud id_list (%s) is provided" % (id_list)) for result in object_list: object_path = result.getPath() # if loop >= max_range: # # For now, maximum object list is always none, so we will never come here ! # syncml_logger.warning("...Send too many objects, will split message...") # finished = False # break # Get the GID document = traverse(object_path) gid = self.getGidFromObject(document) if not gid: raise ValueError("Impossible to compute gid for %s" % (object_path)) if True: # not loop: # or len(syncml_response) < MAX_LEN: # XXX must find a better way to prevent sending # no object due to a too small limit signature = self.getSignatureFromGid(gid) more_data = False # For the case it was never synchronized, we have to send everything if not signature or sync_all: # First time we send this object or the synchronization more required # to send every data as it was never synchronized before document_data = conduit.getXMLFromObjectWithId( # XXX To be renamed (getDocumentData) independant from format document, xml_mapping=self.getXmlBindingGeneratorMethodId(), context_document=self.getPath(), ) if not document_data: continue if create_signature: if not signature: signature = self.newContent( portal_type="SyncML Signature", id=gid, reference=document.getPath(), temporary_data=document_data, ) syncml_logger.debug( "Created a signature %s for gid = %s, path %s" % (signature.getPath(), gid, document.getPath()) ) if len(document_data) > MAX_LEN: syncml_logger.debug("data too big, sending multiple message") more_data = True finished = False document_data, rest_string = cutXML(document_data, MAX_LEN) # Store the remaining data to send it later signature.setPartialData(rest_string) signature.setPartialAction(ADD_ACTION) signature.changeToPartial() else: # The data will be copied in 'data' property once we get # confirmation that the document was well synchronized signature.setTemporaryData(document_data) signature.doSync() syncml_logger.debug("signature %s is syncing" % (signature.getRelativeUrl(),)) # Generate the message syncml_response.addSyncCommand( sync_command=ADD_ACTION, gid=gid, data=document_data, more_data=more_data, media_type=conduit.getContentType(), ) elif signature.getValidationState() in ("not_synchronized", "conflict_resolved_with_merge"): # We don't have synchronized this object yet but it has a signature xml_object = conduit.getXMLFromObjectWithId( document, xml_mapping=self.getXmlBindingGeneratorMethodId(), context_document=self.getPath() ) if signature.getValidationState() == "conflict_resolved_with_merge": # XXX Why putting confirmation message here # Server can get confirmation of sync although it has not yet # send its data modification to the client # This must be checked against specifications syncml_response.addConfirmationMessage( source_ref=signature.getId(), sync_code="conflict_resolved_with_merge", command="Replace" ) if not signature.checkMD5(xml_object): # MD5 checksum tell there is a modification of the object if conduit.getContentType() != "text/xml": # If there is no xml, we re-send the whole object # XXX this must be managed by conduit ? data_diff = xml_object else: # Compute the diff new_document = conduit.replaceIdFromXML(xml_object, "gid", gid) previous_document = conduit.replaceIdFromXML(signature.getData(), "gid", gid) data_diff = conduit.generateDiff(new_data=new_document, former_data=previous_document) if not data_diff: # MD5 Checksum can detect changes like <lang/> != <lang></lang> # but Diff generator will return no diff for it # in this case, no need to send diff signature.synchronize() syncml_logger.debug("signature %s is synchronized" % (signature.getRelativeUrl(),)) continue # Split data if necessary if len(data_diff) > MAX_LEN: syncml_logger.debug("data too big, sending multiple messages") more_data = True finished = False data_diff, rest_string = cutXML(data_diff, MAX_LEN) signature.setPartialData(rest_string) signature.setPartialAction(REPLACE_ACTION) if signature.getValidationState() != "partial": signature.changeToPartial() syncml_logger.debug("signature %s is partial" % (signature.getRelativeUrl(),)) else: # Store the new representation of the document # It will be copy to "data" property once synchronization # is confirmed signature.setTemporaryData(xml_object) signature.doSync() syncml_logger.debug("signature %s is syncing" % (signature.getRelativeUrl(),)) # Generate the command syncml_logger.debug("will send Replace command with %s" % (data_diff,)) syncml_response.addSyncCommand( sync_command=REPLACE_ACTION, gid=gid, data=data_diff, more_data=more_data, media_type=conduit.getContentType(), ) elif signature.getValidationState() != "synchronized": # We should not have this case when we are in CONFLICT_MERGE syncml_logger.debug("signature %s is synchronized" % (signature.getRelativeUrl(),)) signature.synchronize() elif signature.getValidationState() == "conflict_resolved_with_client_command_winning": # We have decided to apply the update # XXX previous_xml will be geXML instead of getTempXML because # some modification was already made and the update # may not apply correctly xml_update = signature.getPartialData() previous_xml_with_gid = conduit.replaceIdFromXML(signature.getData(), "gid", gid, as_string=False) conduit.updateNode( xml=xml_update, object=document, previous_xml=previous_xml_with_gid, force=True, gid=gid, signature=signature, domain=self, ) syncml_response.addConfirmationMessage( target_ref=gid, sync_code="conflict_resolved_with_client_command_winning", command="Replace" ) signature.synchronize() syncml_logger.debug("signature %s is synchronized" % (signature.getRelativeUrl(),)) elif signature.getValidationState() == "partial": # Case of partially sent data xml_string = signature.getPartialData() # XXX Cutting must be managed by conduit # Here it is too specific to XML data if len(xml_string) > MAX_LEN: syncml_logger.info("Remaining data too big, splitting it...") more_data = True finished = False xml_string = signature.getFirstPdataChunk(MAX_LEN) xml_string = etree.CDATA(xml_string.decode("utf-8")) syncml_response.addSyncCommand( sync_command=signature.getPartialAction(), gid=gid, data=xml_string, more_data=more_data, media_type=self.getContentType(), ) if not more_data: signature.doSync() syncml_logger.debug("signature %s is syncing" % (signature.getRelativeUrl(),)) elif signature.getValidationState() in ("syncing", "synchronized"): raise ValueError( "Must not get signature in %s state here, signature is %s" % (signature.getValidationState(), signature.getPath()) ) if not more_data: pass else: syncml_logger.info("Splitting document") break else: syncml_logger.warning("Package is going to be splitted") break loop += 1 syncml_logger.debug("_getSyncMLData end with finished %s" % (finished,)) return finished