Parsing the ProjectRename Method

The Project Renamer PDS extender for Microsoft® Office Project Server 2003 uses the RenameProject function to parse the <ProjectRename> node in the XML request and to call the helper functions that do the work of renaming a project.

Following is the RenameProject signature:

Public Function RenameProject( _
    ByVal oNode As MSXML2.IXMLDOMNode) _
    As Long

XMLRequest passes the following XML node to RenameProject in the oNode parameter. The <ProjectRename> node can have one or more <Project> nodes.

<ProjectRename>
  <Project>
    <ProjectID></ProjectID>
    <NewName></NewName>
  </Project>
  <Project>
    <ProjectID></ProjectID>
    <NewName></NewName>
  </Project>
    . . .
</ProjectRename>

RenameProject parses all of the <Project> child nodes, and then creates a comma-separated list of the ProjectID values in the sIDs variable and makes the following basic checks for errors for each Project in the request. If any value is incorrect, the entire ProjectRename request fails with the appropriate STATUS code.

  • Check the ProjectID value for an empty string
  • If the ProjectID string is numeric, use CLng to convert it to a variable of type Long.
  • Don't continue if ProjectID is less than 1 (the minimum value of PROJ_ID in the database).
  • Call the Validate function for each NewName value, to make sure there are no invalid characters in the name.

RenameProject creates another comma-separated list of the valid NewName values in the sNames variable, where NewName string values are delineated by single quotation marks.

Note  Validate uses the INVALID_CHAR constant, which is defined in Constants.bas as the following set of characters for the U.S. keyboard:
Public Const INVALID_CHAR = ".\""/:;|?'<>*"
If one NewName value is invalid, then the whole call fails and RenameProject returns STATUS_PROJECT_NAME_INVALID. You can add other characters to the set; it might be a different set of characters for other language keyboard layouts.

If each NewName value is valid, RenameProject also calls ProduceSQLQuery and adds the resulting SQL query string with the project name and ID to the sQuery variable.

    Dim oProjNodes As IXMLDOMNodeList
    Dim oProjNode As IXMLDOMNode
    Dim nProjID As Long
    Dim sNewName As String
    Dim result As Boolean
    Dim sQuery As String
    Dim lStatus As Long
    Dim numIDs As Long
    lStatus = STATUS_OK
    
    Dim sNames As String, sIDs As String
    
    result = oNode.hasChildNodes()
    If (result = True) Then
        
        sQuery = ""
        numIDs = 0
        Set oProjNodes = oNode.selectNodes("Project")                
       
        For Each oProjNode In oProjNodes
            Dim sProjID As String
            sProjID = GetNodeValue(oProjNode, "ProjectID")
                
            If sProjID = "" Then
                lStatus = rsNoValuesSpecified
                GoTo PrepareReply
            End If
            
            If IsNumeric(sProjID) Then
                nProjID = CLng(sProjID)
            Else
                lStatus = rsProjectIDInvalid
                GoTo PrepareReply
            End If
                        
            If nProjID < MIN_PROJECT_ID Then
                lStatus = rsProjectIDInvalid
                GoTo PrepareReply
            Else
                sNewName = GetNodeValue(oProjNode, "NewName")
            End If
            
            If Validate(sNewName) Then
                ' Update SQL Query
                sQuery = sQuery & ProduceSQLQuery(sNewName, nProjID) & vbNewLine
            Else
                lStatus = STATUS_PROJECT_NAME_INVALID
                GoTo PrepareReply
            End If
            
            sIDs = sIDs & "," & nProjID
            numIDs = numIDs + 1             
            sNames = sNames & ",'" & sNewName & "'"
        Next oProjNode
        
        sIDs = Right(sIDs, Len(sIDs) - 1)
        sNames = Right(sNames, Len(sNames) - 1)
          
        ' Connect and run query, and set lStatus
        . . . 
          
    Else
        lStatus = STATUS_INVALID_REQUEST
        GoTo PrepareReply
    End If
PrepareReply:
    RenameProject = lStatus
End Function

After the sQuery, sIDs, and sNames strings are set for all <Project> nodes in the XML request, RenameProject then connects to the Project Server database. Before running the SQL query to change the project names, you should check that every project ID actually matches an existing project, and you must make sure no duplicate names will be created. The user must also have the necessary permission to change each project name, and none of the projects to be renamed can be checked out. The whole request fails if any of the tests fail. The CheckProjIDs, CheckForDuplicates, CheckForPermission, and CheckForCheckedOut functions use the sIDs and sNames strings to check all of the projects that would be affected.

        . . . 
        ' Connect and run queries; set lStatus if any tests fail
        CreateConnection
        
        If Not CheckProjIDs(sIDs, numIDs) Then
            lStatus = rsProjectNotFound
        ElseIf Not CheckForDuplicates(sNames) Then
            lStatus = rsProjectNameMultiplesInvalid
        ElseIf Not CheckForPermission(sIDs) Then
            lStatus = STATUS_ACCESS_DENIED
        ElseIf Not CheckForCheckedOut(sIDs) Then
            lStatus = STATUS_PROJECT_CHECKEDOUT
        Else
            ExecuteSQLQuery sQuery
        End If
        
        DestroyConnection
        . . .

For an explanation of how ProduceSQLQuery works, and of the queries in the CheckProjIDs, CheckForDuplicates, CheckForPermission, and CheckForCheckedOut functions, see Creating the Database Queries.

Note  The CMain.cls file in the Project 2003: Project Renamer PDS Extender (pj11pdsxRenamer.exe) download contains the implementation of the SQL query functions, and of the CreateConnection, DestroyConnection, and ExecuteSQLQuery functions.