parameters: (self, action, request_message_id, syncml_response,
                         simulate=False)
docstring: Apply a sync command received
      Here is the main algorithm :
      - try to get the signature for the GID ( some mode does not required it)
      - apply the action
      - update signature
      - generate the status command
docstring_summary: Apply a sync command received
      Here is the main algorithm :
      - try to get the signature for the GID ( some mode does not required it)
      - apply the action
      - update signature
      - generate the status command
docstring_tokens: Apply a sync command received Here is the main algorithm : - try to get the signature for the GID ( some mode does not required it ) - apply the action - update signature - generate the status command
function: def _applySyncCommand(self, action, request_message_id, syncml_response,
                         simulate=False):
      """
      Apply a sync command received
      Here is the main algorithm :
      - try to get the signature for the GID ( some mode does not required it)
      - apply the action
      - update signature
      - generate the status command
      """
      conduit = self.getConduit()
      destination = self.getSourceValue()
      conflict_list = []
      status_code = 'success'
      # First retrieve the GID of the object we want to modify
      gid = action["source"] or action["target"]
      # Retrieve the signature for the current GID
      path_list = []
      signature = self.getSignatureFromGid(gid)
      if syncml_response is not None:  # No response to send when no signature to create
        document = self.getDocumentFromGid(gid)
        if signature is None:
          # Create a new signature when needed
          # XXX what if it does not happen on a Add command ?
          signature = self.newContent(
            portal_type='SyncML Signature',
            id=gid,
            )
          syncml_logger.info("Created a signature for %s - document : %s",
                             signature.getPath(), document)
          if document is not None:
            signature.setReference(document.getPath())
  
        path_list.append(signature.getPath())
        force = signature.isForce()  # XXX-must check the use of this later
      else:
        force = True  # Always erease data in this mod
        document = self.getDocumentFromGid(gid)
        #document = None  # For now, do no try to retrieve previous version of document
        # XXX this has to be managed with a property
        # XXX Some improvement can also be done to retrieve a list of document at once
      # Get the data
      if 'xml_data' in action:
        # Rebuild an Element
        incoming_data = etree.fromstring(action["xml_data"])
      else:  # Raw data
        incoming_data = action['raw_data']
      # XXX must find a way to check for No data received here
      if not action['more_data']:
        # This is the last chunk of a partial xml
        # or this is just an entire data chunk
        if signature and signature.hasPartialData():
          # Build data with already stored data
          signature.appendPartialData(incoming_data)
          incoming_data = signature.getPartialData()
          signature.setPartialData(None)
        __traceback_info__ = (gid, document, incoming_data, action['command']) # pylint: disable=unused-variable
        # Browse possible actions
        if action["command"] == 'Add':
          status_code = "item_added"  # Default status code for addition
          if document is None:
            # This is the default behaviour when getting an "Add" command
            # we create new document from the received data
            syncml_logger.info("Calling addNode with no previous document found")
            add_data = conduit.addNode(xml=incoming_data,
                                       object=destination,
                                       signature=signature,
                                       domain=self)
            conflict_list.extend(add_data['conflict_list'])
            # Retrieve directly the document from addNode
            document = add_data['object']
            if document is None:
              raise ValueError("Adding a document failed, data = %s"
                               % (etree.tostring(incoming_data,
                                                 pretty_print=True),))
          else:
            # Document was retrieved from the database
            actual_xml = conduit.getXMLFromObjectWithGid(document, gid,
                           xml_mapping=\
                           self.getXmlBindingGeneratorMethodId(force=True),
                           context_document=self.getPath())
            # use gid to compare because their ids can be different
            incoming_data = conduit.replaceIdFromXML(incoming_data, 'gid', gid)
            # produce xupdate
            data_diff = conduit.generateDiff(new_data=incoming_data,
                                             former_data=actual_xml)
  
            if data_diff and len(data_diff):
              # XXX Here maybe a conflict must be raised as document was never
              # synchronized and we try to add one which is different
              syncml_logger.critical("trying to add data, but already existing object exists, diff is\n%s", data_diff)
  
            conflict_list.extend(conduit.updateNode(
                                        xml=data_diff,
                                        object=document,
                                        previous_xml=actual_xml,
                                        force=force,
                                        simulate=simulate,
                                        reset=True,
                                        signature=signature,
                                        domain=self))
  
          xml_document = incoming_data
          if not isinstance(xml_document, basestring):
            # XXX using deepcopy to remove parent link - must be done elsewhere
            xml_document = deepcopy(xml_document)
            # Remove useless namespace
            etree.cleanup_namespaces(xml_document)
            xml_document = etree.tostring(xml_document, encoding='utf-8',
                                          pretty_print=True)
  
          if isinstance(xml_document, unicode):
            xml_document = xml_document.encode('utf-8')
          # Link the signature to the document
          if signature:
            signature.setReference(document.getPath())
        elif action["command"] == 'Replace':
          status_code = "success"  # Default status code for addition
          if document is not None:
            signature = self.getSignatureFromGid(gid)
            previous_xml = signature.getData()
            if previous_xml:
              # Make xml consistent XXX should be part of the conduit work
              # XXX this should not happen if we call replaceIdFromXML when
              # editing signature
              previous_xml = conduit.replaceIdFromXML(previous_xml, 'gid', gid)
            conflict_list += conduit.updateNode(xml=incoming_data,
                                                object=document,
                                                previous_xml=previous_xml,
                                                force=force,
                                                signature=signature,
                                                simulate=False, #simulate,
                                                domain=self)
            if previous_xml:
              # here compute patched data with given diff
              xml_document = conduit.applyDiff(previous_xml, incoming_data)
              xml_document = conduit.replaceIdFromXML(xml_document, 'id',
                                                      document.getId(),
                                                      as_string=True)
            else:
              raise ValueError("Got a signature with no data for %s" % (gid,))
          else:
            # Try to apply an update on a delete document
            # What to do ?
            raise ValueError("No document found to apply update")
  
        elif action['command'] == 'Delete':
          status_code="success"
          document = self.getDocumentFromGid(signature.getId())
          syncml_logger.info("Deleting signature %s & doc %s", signature.getPath(),
                                                               document.getPath())
          path_list.remove(signature.getPath())
          if document is not None:
            # XXX Can't we get conflict ?
            # XXX Review the code to prevent retrieving document
            conduit.deleteNode(xml=incoming_data,
                               object=destination,
                               object_id=document.getId())
            # Delete signature
            self._delObject(gid)
          else:
            syncml_logger.error("Document with gid %s is already deleted",
                                gid)
  
          self.z_delete_data_from_path(path="%s" %(signature.getPath(),))
        else:
          raise ValueError("Unknown command %s" %(action['command'],))
  
        # Now update signature status regarding conflict list
        if action['command'] != "Delete" and signature:
          if len(conflict_list):
            status_code = "conflict"
            signature.changeToConflict()
            # Register the data received which generated the diff
            # XXX Why ?
            if not isinstance(incoming_data, basestring):
              incoming_data = etree.tostring(incoming_data,
                                             encoding='utf-8')
            signature.setPartialData(incoming_data)
          else:
            signature.setData(str(xml_document))
            signature.synchronize()
          syncml_logger.info("change state of signature to %s with %s",
                             signature.getValidationState(), signature.getData())
  
        if signature:
          # Generate status about the object synchronized
          # No need to generate confirmation when no signature are stored
          syncml_response.addConfirmationMessage(
            command=action['command'],
            sync_code=status_code,
            target_ref=action["target"],
            source_ref=action["source"],
            command_ref=action["command_id"],
            message_ref=request_message_id)
  
      else:  # We want to retrieve more data
        syncml_logger.info("we need to retrieve more data for %s",
                           signature.getRelativeUrl())
        signature.appendPartialData(incoming_data)
        # XXX Must check if size is present into the xml
        # if not, client might ask it to server with a 411 alert
        # in this case, do not process received data
        syncml_response.addConfirmationMessage(
          command=action['command'],
          sync_code='chunk_accepted',
          target_ref=action["target"],
          source_ref=action["source"],
          command_ref=action["command_id"],
          message_ref=request_message_id)
        # Must add an alert message to ask remaining data to be processed
        # Alert 222 must be generated
        # XXX Will be into the Sync tag -> bad
        syncml_response.addAlertCommand(
              alert_code='next_message',
              target=self.getDestinationReference(),
              source=self.getSourceReference(),
              last_anchor=self.getLastAnchor(),
              next_anchor=self.getNextAnchor())
      # Index signature with their new value
      if len(path_list):
        self.SQLCatalog_indexSyncMLDocumentList(path_list)
function_tokens: def _applySyncCommand ( self , action , request_message_id , syncml_response , simulate = False ) : conduit = self . getConduit ( ) destination = self . getSourceValue ( ) conflict_list = [ ] status_code = 'success' # First retrieve the GID of the object we want to modify gid = action [ "source" ] or action [ "target" ] # Retrieve the signature for the current GID path_list = [ ] signature = self . getSignatureFromGid ( gid ) if syncml_response is not None : # No response to send when no signature to create document = self . getDocumentFromGid ( gid ) if signature is None : # Create a new signature when needed # XXX what if it does not happen on a Add command ? signature = self . newContent ( portal_type = 'SyncML Signature' , id = gid , ) syncml_logger . info ( "Created a signature for %s - document : %s" , signature . getPath ( ) , document ) if document is not None : signature . setReference ( document . getPath ( ) ) path_list . append ( signature . getPath ( ) ) force = signature . isForce ( ) # XXX-must check the use of this later else : force = True # Always erease data in this mod document = self . getDocumentFromGid ( gid ) #document = None  # For now, do no try to retrieve previous version of document # XXX this has to be managed with a property # XXX Some improvement can also be done to retrieve a list of document at once # Get the data if 'xml_data' in action : # Rebuild an Element incoming_data = etree . fromstring ( action [ "xml_data" ] ) else : # Raw data incoming_data = action [ 'raw_data' ] # XXX must find a way to check for No data received here if not action [ 'more_data' ] : # This is the last chunk of a partial xml # or this is just an entire data chunk if signature and signature . hasPartialData ( ) : # Build data with already stored data signature . appendPartialData ( incoming_data ) incoming_data = signature . getPartialData ( ) signature . setPartialData ( None ) __traceback_info__ = ( gid , document , incoming_data , action [ 'command' ] ) # pylint: disable=unused-variable # Browse possible actions if action [ "command" ] == 'Add' : status_code = "item_added" # Default status code for addition if document is None : # This is the default behaviour when getting an "Add" command # we create new document from the received data syncml_logger . info ( "Calling addNode with no previous document found" ) add_data = conduit . addNode ( xml = incoming_data , object = destination , signature = signature , domain = self ) conflict_list . extend ( add_data [ 'conflict_list' ] ) # Retrieve directly the document from addNode document = add_data [ 'object' ] if document is None : raise ValueError ( "Adding a document failed, data = %s" % ( etree . tostring ( incoming_data , pretty_print = True ) , ) ) else : # Document was retrieved from the database actual_xml = conduit . getXMLFromObjectWithGid ( document , gid , xml_mapping = self . getXmlBindingGeneratorMethodId ( force = True ) , context_document = self . getPath ( ) ) # use gid to compare because their ids can be different incoming_data = conduit . replaceIdFromXML ( incoming_data , 'gid' , gid ) # produce xupdate data_diff = conduit . generateDiff ( new_data = incoming_data , former_data = actual_xml ) if data_diff and len ( data_diff ) : # XXX Here maybe a conflict must be raised as document was never # synchronized and we try to add one which is different syncml_logger . critical ( "trying to add data, but already existing object exists, diff is\n%s" , data_diff ) conflict_list . extend ( conduit . updateNode ( xml = data_diff , object = document , previous_xml = actual_xml , force = force , simulate = simulate , reset = True , signature = signature , domain = self ) ) xml_document = incoming_data if not isinstance ( xml_document , basestring ) : # XXX using deepcopy to remove parent link - must be done elsewhere xml_document = deepcopy ( xml_document ) # Remove useless namespace etree . cleanup_namespaces ( xml_document ) xml_document = etree . tostring ( xml_document , encoding = 'utf-8' , pretty_print = True ) if isinstance ( xml_document , unicode ) : xml_document = xml_document . encode ( 'utf-8' ) # Link the signature to the document if signature : signature . setReference ( document . getPath ( ) ) elif action [ "command" ] == 'Replace' : status_code = "success" # Default status code for addition if document is not None : signature = self . getSignatureFromGid ( gid ) previous_xml = signature . getData ( ) if previous_xml : # Make xml consistent XXX should be part of the conduit work # XXX this should not happen if we call replaceIdFromXML when # editing signature previous_xml = conduit . replaceIdFromXML ( previous_xml , 'gid' , gid ) conflict_list += conduit . updateNode ( xml = incoming_data , object = document , previous_xml = previous_xml , force = force , signature = signature , simulate = False , #simulate, domain = self ) if previous_xml : # here compute patched data with given diff xml_document = conduit . applyDiff ( previous_xml , incoming_data ) xml_document = conduit . replaceIdFromXML ( xml_document , 'id' , document . getId ( ) , as_string = True ) else : raise ValueError ( "Got a signature with no data for %s" % ( gid , ) ) else : # Try to apply an update on a delete document # What to do ? raise ValueError ( "No document found to apply update" ) elif action [ 'command' ] == 'Delete' : status_code = "success" document = self . getDocumentFromGid ( signature . getId ( ) ) syncml_logger . info ( "Deleting signature %s & doc %s" , signature . getPath ( ) , document . getPath ( ) ) path_list . remove ( signature . getPath ( ) ) if document is not None : # XXX Can't we get conflict ? # XXX Review the code to prevent retrieving document conduit . deleteNode ( xml = incoming_data , object = destination , object_id = document . getId ( ) ) # Delete signature self . _delObject ( gid ) else : syncml_logger . error ( "Document with gid %s is already deleted" , gid ) self . z_delete_data_from_path ( path = "%s" % ( signature . getPath ( ) , ) ) else : raise ValueError ( "Unknown command %s" % ( action [ 'command' ] , ) ) # Now update signature status regarding conflict list if action [ 'command' ] != "Delete" and signature : if len ( conflict_list ) : status_code = "conflict" signature . changeToConflict ( ) # Register the data received which generated the diff # XXX Why ? if not isinstance ( incoming_data , basestring ) : incoming_data = etree . tostring ( incoming_data , encoding = 'utf-8' ) signature . setPartialData ( incoming_data ) else : signature . setData ( str ( xml_document ) ) signature . synchronize ( ) syncml_logger . info ( "change state of signature to %s with %s" , signature . getValidationState ( ) , signature . getData ( ) ) if signature : # Generate status about the object synchronized # No need to generate confirmation when no signature are stored syncml_response . addConfirmationMessage ( command = action [ 'command' ] , sync_code = status_code , target_ref = action [ "target" ] , source_ref = action [ "source" ] , command_ref = action [ "command_id" ] , message_ref = request_message_id ) else : # We want to retrieve more data syncml_logger . info ( "we need to retrieve more data for %s" , signature . getRelativeUrl ( ) ) signature . appendPartialData ( incoming_data ) # XXX Must check if size is present into the xml # if not, client might ask it to server with a 411 alert # in this case, do not process received data syncml_response . addConfirmationMessage ( command = action [ 'command' ] , sync_code = 'chunk_accepted' , target_ref = action [ "target" ] , source_ref = action [ "source" ] , command_ref = action [ "command_id" ] , message_ref = request_message_id ) # Must add an alert message to ask remaining data to be processed # Alert 222 must be generated # XXX Will be into the Sync tag -> bad syncml_response . addAlertCommand ( alert_code = 'next_message' , target = self . getDestinationReference ( ) , source = self . getSourceReference ( ) , last_anchor = self . getLastAnchor ( ) , next_anchor = self . getNextAnchor ( ) ) # Index signature with their new value if len ( path_list ) : self . SQLCatalog_indexSyncMLDocumentList ( path_list )