IDM 7.2.2

Search operation

Connectors continue to be released outside the IDM release. For the latest documentation, refer to the ICF documentation.

The search operation enables the connector to search for objects on the target system.

The ICF framework handles searches as follows:

  1. The application sends a query, with a search filter, to the OpenICF framework.

  2. The framework submits the query, with the filter, to the connector.

  3. The connector implements the createFilterTranslator() method to obtain a FilterTranslator object.

  4. The framework then uses this FilterTranslator object to transform the filter to a format that the executeQuery() method expects.

You can implement the FilterTranslator object in two ways:

  • The FilterTranslator translates the original filter into one or more native queries.

    The framework then calls the executeQuery() method for each native query.

  • The FilterTranslator does not modify the original filter.

    The framework then calls the executeQuery() method with the original ICF filter.

    Using this second approach enables your connector to distinguish between a search and a get operation and to benefit from the visitor design pattern.

Based on the resultsHandlerConfiguration, the OpenICF framework can perform additional filtering on the returning results. For more information on the resultsHandlerConfiguration, refer to Configure How Results Are Handled.

The connector facade calls the executeQuery method once for each native query that the filter translator produces. If the filter translator produces more than one native query, the connector facade merges the results from each query and eliminates any duplicates.

Note that this implies an in-memory data structure that holds a set of UID values. Memory usage, in the event of multiple queries, will be O(N) where N is the number of results. It is therefore important that the filter translator for the connector implement OR operators, if possible.

Whether the application calls a get API operation, or a search API operation, the ICF framework translates that request to a search request on the connector.

Use the ICF get operation

The GetApiOp returns null when the UID does not exist on the resource.

Consumption of the Get operation, at the API Level
@Test
public void getObjectTest() {
    logger.info("Running GetObject Test");
    final ConnectorFacade facade = createConnectorFacade(BasicConnector.class, null);
    final OperationOptionsBuilder builder = new OperationOptionsBuilder();
    builder.setAttributesToGet(Name.NAME);
    ConnectorObject co =
            facade.getObject(ObjectClass.ACCOUNT, new Uid(
                    "3f50eca0-f5e9-11e3-a3ac-0800200c9a66"), builder.build());
    Assert.assertEquals(co.getName().getNameValue(), "Foo");
}

Use the ICF search operation

Consumption of the Search operation, at the API Level
@Test
public void searchTest() {
    logger.info("Running Search Test");
    final ConnectorFacade facade = createConnectorFacade(BasicConnector.class, null);
    final OperationOptionsBuilder builder = new OperationOptionsBuilder();
    builder.setPageSize(10);
    final ResultsHandler handler = new ToListResultsHandler();

    SearchResult result =
            facade.search(ObjectClass.ACCOUNT, FilterBuilder.equalTo(new Name("Foo")), handler,
                    builder.build());
    Assert.assertEquals(result.getPagedResultsCookie(), "0");
    Assert.assertEquals(((ToListResultsHandler) handler).getObjects().size(), 1);
}

Implement the search operation

Implementation of the Search operation, at the SPI Level
public FilterTranslator<String> createFilterTranslator(ObjectClass objectClass,
        OperationOptions options) {
    return new BasicFilterTranslator();
}

public void executeQuery(ObjectClass objectClass, String query, ResultsHandler handler,
        OperationOptions options) {
    final ConnectorObjectBuilder builder = new ConnectorObjectBuilder();
    builder.setUid("3f50eca0-f5e9-11e3-a3ac-0800200c9a66");
    builder.setName("Foo");
    builder.addAttribute(AttributeBuilder.buildEnabled(true));

    for (ConnectorObject connectorObject : CollectionUtil.newSet(builder.build())) {
        if (!handler.handle(connectorObject)) {
            // Stop iterating because the handler stopped processing
            break;
        }
    }
    if (options.getPageSize() != null && 0 < options.getPageSize()) {
        logger.info("Paged Search was requested");
        ((SearchResultsHandler) handler).handleResult(new SearchResult("0", 0));
    }
}