Диаграммы последовательностей работы коннектора Fortress#

Данный документ содержит диаграммы последовательностей (PlantUML), описывающие алгоритмы работы коннектора Fortress.

Тестирование подключения (test)#

@startuml
title Диаграмма последовательности: Тестирование подключения

participant "IDM Framework" as Framework
participant "FortressConnector" as Connector
participant "FortressApiClient" as ApiClient
participant "HttpClient" as Http
participant "Fortress API" as API

Framework -> Connector: test()
activate Connector
Connector -> ApiClient: getHealth()
activate ApiClient

ApiClient -> Http: GET /health
Http -> API: GET /health\nheaders: Accept=application/json
API --> Http: 200 OK\n"healthy"
Http --> ApiClient: HttpResponse

alt statusCode != 200
    ApiClient --> ApiClient: ConnectionFailedException
else statusCode == 200
    ApiClient --> Connector: JsonNode("healthy")
end

deactivate ApiClient
Connector --> Framework: test завершён
deactivate Connector
@enduml

Создание объекта (create)#

@startuml
title Диаграмма последовательности: Создание объекта

participant "IDM Framework" as Framework
participant "FortressConnector" as Connector
participant "AccountHandler" as Handler
participant "FortressApiClient" as ApiClient
participant "HttpClient" as Http
participant "Fortress API" as API

Framework -> Connector: create(ObjectClass, attributes)
activate Connector

note right: Извлечение UID и NAME\nиз атрибутов
Connector -> Connector: найти uidAttribute
Connector -> Connector: найти nameAttribute

alt uid не найден
    Connector --> Framework: ConnectorIOException("UID not found")
    deactivate Connector
else name не найден
    Connector --> Framework: ConnectorIOException("NAME not found")
    deactivate Connector
else uid и name найдены
    note right: Проверка существования УЗ
    Connector -> Handler: find(nameValue, allowNotFound=true)
    activate Handler
    Handler -> ApiClient: findFortressUser({name: nameValue})
    activate ApiClient
    ApiClient -> Http: POST /msad/fortress/user/search
    Http -> API: POST с JSON body
    API --> Http: 200 OK\n{payload: {...}} или 404
    Http --> ApiClient: HttpResponse
    ApiClient --> Handler: JsonNode или null
    
    alt пользователь найден
        Handler --> Connector: JsonNode
        Connector --> Framework: AlreadyExistsException
        deactivate Handler
        deactivate Connector
    else пользователь не найден
        Handler --> Connector: null
        deactivate Handler
        
        note right: Создание УЗ
        Connector -> Handler: create(attributes)
        activate Handler
        Handler -> ApiClient: fortressUser(attributes)
        activate ApiClient
        ApiClient -> Http: POST /msad/fortress/user
        Http -> API: POST с JSON body
        API --> Http: 201 Created\n{payload: {documentId: "xxx"}}
        Http --> ApiClient: HttpResponse
        ApiClient --> Handler: JsonNode
        Handler --> Connector: documentId
        
        alt documentId не получен
            Connector --> Framework: UnknownUidException
            deactivate Connector
        else documentId получен
            Connector -> Connector: new NameWrapper(name)
            Connector -> Connector: nameWrapper.setDocumentId(documentId)
            Connector -> Connector: nameWrapper.setOperation(CREATE)
            Connector -> Connector: new Uid(uidValue, nameWrapper.getNameAttributeWithOperation())
            Connector --> Framework: Uid
            deactivate Connector
        end
    end
end
@enduml

Поиск по UID (searchByUid)#

@startuml
title Диаграмма последовательности: Поиск по UID

participant "IDM Framework" as Framework
participant "FortressConnector" as Connector
participant "AccountHandler" as Handler
participant "FortressApiClient" as ApiClient
participant "HttpClient" as Http
participant "Fortress API" as API
participant "ResultsHandler" as Results

Framework -> Connector: executeQuery(ObjectClass, EqualsFilter(uid), resultsHandler)
activate Connector

Connector -> Connector: uid.getNameHint()
alt nameHint == null
    Connector --> Framework: ConnectorIOException("Uid nameHint is null")
    deactivate Connector
end

Connector -> Connector: new NameWrapper(nameHint)
Connector -> Connector: documentId = nameWrapper.getDocumentId()

Connector -> Connector: new AccountAttributesContext()

alt documentId != null
    note right: Проверка статуса документа
    Connector -> Handler: findDocument(documentId)
    activate Handler
    Handler -> ApiClient: getDocument(documentId)
    activate ApiClient
    ApiClient -> Http: GET /documents/status/{id}
    Http -> API: GET document status
    API --> Http: 200 OK\n{payload: {status: "in_progress"|"success"|"error"}}
    Http --> ApiClient: HttpResponse
    ApiClient --> Handler: status
    Handler --> Connector: status
    deactivate Handler
    deactivate ApiClient
    
    Connector -> Connector: attributesContext.addDocumentAttribute("id", documentId)
    Connector -> Connector: attributesContext.addDocumentAttribute("status", status)
    
    Connector -> Connector: checkOperationStatus(status)
    
    alt status == "in_progress"
        alt operation == CREATE
            Connector -> Connector: findUser = false
        else operation == UPDATE
            Connector -> Connector: forceNameWithOp = true
            Connector -> Connector: findUser = true
        end
    else status == "success"
        alt operation == CREATE
            Connector -> Connector: addAction(FORCE_CHANGE_PASSWORD_AFTER_CREATE)
        end
    else status == "error"
        alt operation == CREATE
            Connector -> Connector: findUser = false
        end
    end
end

alt findUser == true
    note right: Поиск пользователя
    Connector -> Handler: find(nameValue, allowNotFound=false)
    activate Handler
    Handler -> ApiClient: findFortressUser({name: nameValue})
    ApiClient -> Http: POST /msad/fortress/user/search
    Http -> API: POST search
    API --> Http: 200 OK\n{payload: {...}}
    Http --> ApiClient: HttpResponse
    ApiClient --> Handler: JsonNode
    Handler --> Connector: userData
    deactivate Handler
    
    Connector -> Connector: attributesContext.process(userData)
end

Connector -> Connector: getConnectorObject()
Connector -> Results: handle(connectorObject)
Connector --> Framework: завершено
deactivate Connector
@enduml

Поиск по NAME (searchByName)#

@startuml
title Диаграмма последовательности: Поиск по NAME

participant "IDM Framework" as Framework
participant "FortressConnector" as Connector
participant "AccountHandler" as Handler
participant "FortressApiClient" as ApiClient
participant "HttpClient" as Http
participant "Fortress API" as API
participant "ResultsHandler" as Results

Framework -> Connector: executeQuery(ObjectClass, EqualsFilter(name), resultsHandler)
activate Connector

Connector -> Connector: new NameWrapper(name)
Connector -> Connector: new AccountAttributesContext()

note right: Поиск пользователя
Connector -> Handler: find(nameValue, allowNotFound=false)
activate Handler
Handler -> ApiClient: findFortressUser({name: nameValue})
activate ApiClient
ApiClient -> Http: POST /msad/fortress/user/search
Http -> API: POST search
API --> Http: 200 OK\n{payload: {...}}
Http --> ApiClient: HttpResponse
ApiClient --> Handler: JsonNode
Handler --> Connector: userData
deactivate Handler
deactivate ApiClient

Connector -> Connector: attributesContext.process(userData)
Connector -> Connector: getConnectorObject()
Connector -> Results: handle(connectorObject)
Connector --> Framework: завершено
deactivate Connector
@enduml

Обновление объекта (updateDelta)#

@startuml
title Диаграмма последовательности: Обновление объекта (Delta)

participant "IDM Framework" as Framework
participant "FortressConnector" as Connector
participant "AccountHandler" as Handler
participant "FortressApiClient" as ApiClient

Framework -> Connector: updateDelta(ObjectClass, uid, deltas)
activate Connector

Connector -> Connector: uid.getNameHint()
alt name == null
    Connector --> Framework: ConnectorIOException("NAME not found")
    deactivate Connector
end

Connector -> Connector: name.getNameValue()
alt name содержит OP_DOCUMENT_DELIMITER
    note right: Пропуск update, если выполняется\nCREATE/UPDATE операция
    Connector --> Framework: emptySet
    deactivate Connector
end

note right: Обработка ENABLE/DISABLE
Connector -> Connector: найти statusAttribute delta
Connector -> Handler: disable(name, disableDate, statusValue)
activate Handler
Handler -> ApiClient: disableFortressUser({name, ...})
ApiClient -> ApiClient: POST /msad/fortress/user/disable
Handler --> Connector: готово
deactivate Handler

note right: Обработка UNLOCK/RESET PASSWORD
Connector -> Connector: найти password delta
Connector -> Connector: найти lockout delta
Connector -> Handler: unlock(name, password)
activate Handler
Handler -> ApiClient: unlockUser({name, password})
ApiClient -> ApiClient: POST /msad/fortress/user/unlock
Handler --> Connector: готово
deactivate Handler

note right: Обновление остальных атрибутов
Connector -> Connector: отфильтровать basic attributes\n(исключая create attrs и status)

alt attributes не пустые
    Connector -> Connector: new AccountAttributesContext()
    Connector -> Handler: find(nameValue, allowNotFound=true)
    activate Handler
    Handler -> ApiClient: findFortressUser(...)
    Handler --> Connector: userData
    deactivate Handler
    
    Connector -> Connector: attributesContext.process(userData)
    Connector -> Connector: сформировать новые атрибуты
    
    Connector -> Handler: create(newAttributes)
    activate Handler
    Handler -> ApiClient: fortressUser(attributes)
    Handler --> Connector: documentId
    deactivate Handler
    
    alt documentId != null
        Connector -> Connector: nameWrapper.setDocumentId(documentId)
        Connector -> Connector: nameWrapper.setOperation(UPDATE)
        Connector -> Connector: создать nameAttributeDelta
        Connector -> Connector: добавить в result
    end
end

Connector --> Framework: Set<AttributeDelta>
deactivate Connector
@enduml

Disable пользователя#

@startuml
title Диаграмма последовательности: Disable пользователя

participant "FortressConnector" as Connector
participant "AccountHandler" as Handler
participant "FortressApiClient" as ApiClient
participant "HttpClient" as Http
participant "Fortress API" as API

Connector -> Connector: найти statusAttribute в deltas
alt statusAttribute найден
    Connector -> Connector: найти disableDate (ENABLE_DISABLE_DATE)
    Connector -> Connector: получить boolean значение status
    
    Connector -> Handler: disable(name, disableDate, statusValue)
    activate Handler
    
    Handler -> ApiClient: disableFortressUser(attributes)
    activate ApiClient
    
    ApiClient -> Http: POST /msad/fortress/user/disable
    Http -> API: POST {name, status, disableDate}
    API --> Http: 201 Created
    Http --> ApiClient: HttpResponse
    
    alt statusCode != 201
        ApiClient --> ApiClient: ConnectorIOException
    else
        ApiClient --> Handler: null
    end
    
    deactivate ApiClient
    Handler --> Connector: готово
    deactivate Handler
end
@enduml

Unlock пользователя#

@startuml
title Диаграмма последовательности: Unlock пользователя

participant "FortressConnector" as Connector
participant "AccountHandler" as Handler
participant "FortressApiClient" as ApiClient
participant "HttpClient" as Http
participant "Fortress API" as API

Connector -> Connector: найти password в deltas
Connector -> Connector: найти lockoutAttribute в deltas

alt password != null ИЛИ (lockout != null И valuesToReplace содержит FALSE)
    Connector -> Handler: unlock(name, password)
    activate Handler
    
    Handler -> ApiClient: unlockUser(attributes)
    activate ApiClient
    
    ApiClient -> Http: POST /msad/fortress/user/unlock
    Http -> API: POST {name, password?}
    API --> Http: 201 Created
    Http --> ApiClient: HttpResponse
    
    alt statusCode != 201
        ApiClient --> ApiClient: ConnectorIOException
    else
        ApiClient --> Handler: null
    end
    
    deactivate ApiClient
    Handler --> Connector: готово
    deactivate Handler
end
@enduml