Openidm - Доступ к исходным или целевым значениям в коннекторе groovy.
В настоящее время я создаю свой собственный соединитель Openidm для подготовки внешней системы с использованием соединителя инфраструктуры Groovy на основе примера ScriptedRest2DJ.
Я реализую файл searchScript.groovy для поиска ресурсов (пользователей) в целевой системе и хочу передать текущий пользовательский UID исходной системы в моем запросе.
Вот исходный код SearchScript.groovy:
import groovyx.net.http.RESTClient
import org.apache.http.client.HttpClient
import org.forgerock.openicf.connectors.scriptedrest.ScriptedRESTConfiguration
import org.forgerock.openicf.misc.scriptedcommon.OperationType
import org.identityconnectors.common.logging.Log
import org.identityconnectors.framework.common.objects.Attribute
import org.identityconnectors.framework.common.objects.AttributeUtil
import org.identityconnectors.framework.common.objects.Name
import org.identityconnectors.framework.common.objects.ObjectClass
import org.identityconnectors.framework.common.objects.OperationOptions
import org.identityconnectors.framework.common.objects.SearchResult
import org.identityconnectors.framework.common.objects.Uid
import org.identityconnectors.framework.common.objects.filter.Filter
import org.identityconnectors.framework.common.objects.AttributesAccessor
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON;
// imports used for CREST based REST APIs
import org.forgerock.openicf.misc.crest.CRESTFilterVisitor
import org.forgerock.openicf.misc.crest.VisitorParameter
def operation = operation as OperationType
def configuration = configuration as ScriptedRESTConfiguration
def httpClient = connection as HttpClient
def connection = customizedConnection as RESTClient
def filter = filter as Filter
def log = log as Log
def objectClass = objectClass as ObjectClass
def options = options as OperationOptions
def resultHandler = handler
log.info("Entering " + operation + " Script")
switch (objectClass) {
case ObjectClass.ACCOUNT:
// Search for a specific user in Alfresco
// http://docs.alfresco.com/community/references/RESTful-PersonPersonGet.html
def searchResult = connection.request(GET, JSON) { req ->
uri.path = 'people'
headers.Accept = 'application/json'
response.success = { resp, json ->
json.people.each() { value ->
resultHandler {
uid value.userName
id value.userName
attribute 'email', value?.email
attribute 'lastName', value?.lastName
attribute 'userName', value?.userName
attribute 'firstName', value?.firstName
attribute 'enabled', value?.enabled
//attribute ('groups', *(value?.groups))
}
}
json
}
}
return new SearchResult(null, -1) // no remaining results
}
Как вы могли бы получить доступ к исходному значению в сценарии? У меня есть тест Uid, Id, Name, ... безуспешно.
Спасибо за помощь
1 ответ
Чтобы ваш SearchScript делал больше, чем просто возвращает всех пользователей, вам нужно использовать объект "фильтр". Вы объявили это в своем скрипте, но вы его не используете - это объект, который имеет все детали, которые соединитель должен знать, какой "поиск" должен выполнять этот скрипт на бэкэнде (через REST в этом дело). Объекты фильтра - это, по сути, древовидные структуры, и их ожидаемое использование основано на " Шаблоне посетителя".
Образец scriptedrest2dj, на котором вы основываете свой код, демонстрирует использование CRESTFilterVisitor, который является особым и особенно полезен для работы с OpenDJ (целью этого примера). Для реализации посетителя более общего назначения я предлагаю взглянуть на образец скрипта Search3.groovy. Sample3 - это пример работы с бэкэндом SQL, но показанный там посетитель может быть использован для генерации строки запроса любого типа (например, той, которую вы можете передать службе REST).
Из кода фильтра sample3 это возвращает регулярную карту значений, представляющую дерево фильтра:
def query = filter.accept(MapFilterVisitor.INSTANCE, null)
Вот структура этой карты для простых значений (например, поле eq "значение"):
[
"operation": "EQUALS|CONTAINS|STARTSWITH|ENDSWITH",
"not": "true|false",
"left": "fieldName",
"right": "value"
]
"левый" и "правый" здесь можно рассматривать как части уравнения. В случае: "Id eq "bob"" слева будет "Id", а справа будет "bob". "операция" будет "РАВНЫМИ".
А вот структура для более сложных выражений (например, simpleExpr AND simpleExpr):
[
"operation": "AND|OR",
"left": "simpleExpression|complexExpression",
"right": "simpleExpression|complexExpression"
]
Как вы можете видеть здесь, вы можете иметь произвольно сложные логические выражения, представленные в этой структуре карты. В зависимости от того, какую сложность вы хотите поддерживать в вашем конкретном случае, вы можете выбрать поддержку полностью рекурсивного построителя выражений (например, как показано в sample3) или просто поддержать основные случаи.
Вот несколько примеров операций, которые ваш скрипт должен обрабатывать:
GET /openidm/system/scriptedrest/account?_queryId=query-all-ids
- это в основном то, что у вас есть сейчас. При выполнении этой операции объект "фильтр" будет нулевым, поэтому вам вообще не нужно ничего фильтровать
GET /openidm/system/scriptedrest/account/bob
это операция чтения, но она также реализована с помощью SearchScript. "Чтение" - это то же самое, что и простой фильтр для конкретного
__UID__
значение. Быстрый и грязный способ сделать это состоит в том, чтобы преобразовать ваш объект фильтра в карту (как я описал), а затем предположить, что карта будет содержать только фильтр, ищущий определенную__UID__
, вот так:def uid = query.get('right')
Затем вы можете передать это в свой вызов REST (возможно, добавив его в переменную uri.path).
В идеале ваш поисковый скрипт должен иметь возможность обрабатывать более сложные фильтры, например:
GET /openidm/system/scriptedrest/account?_queryFilter=/email eq "bob@bob.com"
- это более общий поиск записей с конкретными значениями. Ваш REST-сервер должен будет поддерживать такие вещи, а ваш построитель запросов фильтра должен иметь возможность проходить по дереву, чтобы создать соответствующую строку запроса. В зависимости от того, что вам нужно сделать с этим разъемом, это может быть необязательно.