mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
22.14.2012 fd794cb26c7e4ce55a7230f7f0ea755c024d38c6
Fix checkstyle errors.
14 files modified
658 ■■■■■ changed files
opendj3/opendj-rest2ldap/pom.xml 39 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java 7 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java 20 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java 20 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java 10 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java 40 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java 97 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java 187 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java 16 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java 106 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java 17 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java 49 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/package-info.java 30 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java 20 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/pom.xml
@@ -1,29 +1,19 @@
<?xml version="1.0"?>
<!--
 ! CDDL HEADER START
 !
 ! The contents of this file are subject to the terms of the
 ! Common Development and Distribution License, Version 1.0 only
 ! (the "License").  You may not use this file except in compliance
 ! with the License.
 !
 ! You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 ! or http://forgerock.org/license/CDDLv1.0.html.
 ! See the License for the specific language governing permissions
 ! and limitations under the License.
 !
 ! When distributing Covered Code, include this CDDL HEADER in each
 ! file and include the License file at legal-notices/CDDLv1_0.txt.
 ! If applicable, add the following below this CDDL HEADER, with the
 ! fields enclosed by brackets "[]" replaced with your own identifying
 ! information:
 !      Portions Copyright [yyyy] [name of copyright owner]
 !
 ! CDDL HEADER END
 !
 !      Copyright 2012 ForgeRock AS
 !
 -->
  The contents of this file are subject to the terms of the Common Development and
  Distribution License (the License). You may not use this file except in compliance with the
  License.
  You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
  specific language governing permission and limitations under the License.
  When distributing Covered Software, include this CDDL Header Notice in each file and include
  the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
  Header, with the fields enclosed by brackets [] replaced by your own identifying
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2012 ForgeRock AS.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
@@ -40,6 +30,7 @@
    <packaging>jar</packaging>
    <properties>
        <forgerockRestVersion>2.0.0-SNAPSHOT</forgerockRestVersion>
        <checkstyleHeaderLocation>org/forgerock/checkstyle/default-java-header</checkstyleHeaderLocation>
    </properties>
    <dependencies>
        <dependency>
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import java.util.List;
@@ -65,7 +64,7 @@
     * @param h
     *            The result handler.
     */
    void toJson(ServerContext c, Entry e, ResultHandler<Map<String, Object>> h);
    void toJSON(ServerContext c, Entry e, ResultHandler<Map<String, Object>> h);
    /**
     * Transforms JSON content in the provided JSON value to LDAP attributes,
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import static org.forgerock.opendj.rest2ldap.Utils.toLowerCase;
@@ -25,15 +24,15 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResultHandler;
import org.forgerock.json.resource.ServerContext;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.Entry;
/**
 * An attribute mapper which will wrap the results of the provided mapper as a
 * complex JSON object.
 * An attribute mapper which maps a single JSON attribute to the result of
 * another attribute mapper.
 */
public class ComplexAttributeMapper implements AttributeMapper {
@@ -60,6 +59,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        if (attributeMatchesPointer(jsonAttribute)) {
            final JsonPointer relativePointer = jsonAttribute.relativePointer();
@@ -70,26 +70,30 @@
    /**
     * {@inheritDoc}
     */
    public void toJson(final ServerContext c, final Entry e,
    @Override
    public void toJSON(final ServerContext c, final Entry e,
            final ResultHandler<Map<String, Object>> h) {
        final ResultHandler<Map<String, Object>> wrapper = new ResultHandler<Map<String, Object>>() {
            @Override
            public void handleError(final ResourceException e) {
                h.handleError(e);
            }
            @Override
            public void handleResult(final Map<String, Object> result) {
                final Map<String, Object> complexResult = Collections.singletonMap(
                        jsonAttributeName, (Object) result);
                h.handleResult(complexResult);
            }
        };
        mapper.toJson(c, e, wrapper);
        mapper.toJSON(c, e, wrapper);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void toLDAP(final ServerContext c, final JsonValue v,
            final ResultHandler<List<Attribute>> h) {
        // TODO Auto-generated method stub
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import java.util.ArrayList;
@@ -27,15 +26,15 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResultHandler;
import org.forgerock.json.resource.ServerContext;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.Entry;
/**
 * A collection of one or more attribute mappers whose content will be combined
 * into a single JSON array.
 * An attribute mapper which combines the results of a set of subordinate
 * attribute mappers into a single JSON object.
 */
public final class CompositeAttributeMapper implements AttributeMapper {
    private final List<AttributeMapper> attributeMappers = new LinkedList<AttributeMapper>();
@@ -62,6 +61,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        for (final AttributeMapper attribute : attributeMappers) {
            attribute.getLDAPAttributes(jsonAttribute, ldapAttributes);
@@ -71,13 +71,15 @@
    /**
     * {@inheritDoc}
     */
    public void toJson(final ServerContext c, final Entry e,
    @Override
    public void toJSON(final ServerContext c, final Entry e,
            final ResultHandler<Map<String, Object>> h) {
        final ResultHandler<Map<String, Object>> resultAccumulater = new ResultHandler<Map<String, Object>>() {
            private final AtomicInteger latch = new AtomicInteger(attributeMappers.size());
            private final List<Map<String, Object>> results = new ArrayList<Map<String, Object>>(
                    latch.get());
            @Override
            public void handleError(final ResourceException e) {
                // Ensure that handler is only invoked once.
                if (latch.getAndSet(0) > 0) {
@@ -85,6 +87,7 @@
                }
            }
            @Override
            public void handleResult(final Map<String, Object> result) {
                if (result != null && !result.isEmpty()) {
                    synchronized (this) {
@@ -111,13 +114,14 @@
        };
        for (final AttributeMapper mapper : attributeMappers) {
            mapper.toJson(c, e, resultAccumulater);
            mapper.toJSON(c, e, resultAccumulater);
        }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void toLDAP(final ServerContext c, final JsonValue v,
            final ResultHandler<List<Attribute>> h) {
        // TODO Auto-generated method stub
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import java.util.Collections;
@@ -53,6 +52,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        // Nothing to do.
    }
@@ -60,7 +60,8 @@
    /**
     * {@inheritDoc}
     */
    public void toJson(final ServerContext c, final Entry e,
    @Override
    public void toJSON(final ServerContext c, final Entry e,
            final ResultHandler<Map<String, Object>> h) {
        // FIXME: how do we know if the user requested it???
        h.handleResult(Collections.singletonMap(jsonAttributeName, jsonAttributeValue));
@@ -70,6 +71,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public void toLDAP(final ServerContext c, final JsonValue v,
            final ResultHandler<List<Attribute>> h) {
        // TODO Auto-generated method stub
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import static org.forgerock.opendj.rest2ldap.Utils.attributeToJson;
@@ -33,7 +32,8 @@
import org.forgerock.opendj.ldap.Entry;
/**
 *
 * An attribute mapper that directly maps a configurable selection of attributes
 * to and from LDAP without any transformation.
 */
public final class DefaultAttributeMapper implements AttributeMapper {
@@ -41,10 +41,21 @@
    // All user attributes by default.
    private final Map<String, String> includedAttributes = new LinkedHashMap<String, String>();
    /**
     * Creates a new default attribute mapper which will map all user attributes
     * to JSON by default.
     */
    public DefaultAttributeMapper() {
        // No implementation required.
    }
    /**
     * Excludes one or more LDAP attributes from this mapping.
     *
     * @param attributes
     *            The attributes to be excluded.
     * @return This attribute mapper.
     */
    public DefaultAttributeMapper excludeAttribute(final String... attributes) {
        for (final String attribute : attributes) {
            excludedAttributes.put(toLowerCase(attribute), attribute);
@@ -52,6 +63,7 @@
        return this;
    }
    @Override
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        switch (jsonAttribute.size()) {
        case 0:
@@ -72,15 +84,13 @@
        }
    }
    public void getLDAPAttributes(final Set<String> ldapAttributes) {
        if (!includedAttributes.isEmpty()) {
            ldapAttributes.addAll(includedAttributes.values());
        } else {
            // All user attributes.
            ldapAttributes.add("*");
        }
    }
    /**
     * Includes one or more LDAP attributes in this mapping.
     *
     * @param attributes
     *            The attributes to be included.
     * @return This attribute mapper.
     */
    public DefaultAttributeMapper includeAttribute(final String... attributes) {
        for (final String attribute : attributes) {
            includedAttributes.put(toLowerCase(attribute), attribute);
@@ -88,7 +98,8 @@
        return this;
    }
    public void toJson(final ServerContext c, final Entry e,
    @Override
    public void toJSON(final ServerContext c, final Entry e,
            final ResultHandler<Map<String, Object>> h) {
        final Map<String, Object> result = new LinkedHashMap<String, Object>(e.getAttributeCount());
        for (final Attribute a : e.getAllAttributes()) {
@@ -100,6 +111,7 @@
        h.handleResult(result);
    }
    @Override
    public void toLDAP(final ServerContext c, final JsonValue v,
            final ResultHandler<List<Attribute>> h) {
        // TODO:
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import java.util.Collection;
@@ -35,7 +34,7 @@
import org.forgerock.opendj.ldap.responses.SearchResultReference;
/**
 *
 * An entry container.
 */
public final class EntryContainer {
    private abstract class AbstractRequestCompletionHandler<R, H extends ResultHandler<? super R>>
@@ -124,58 +123,102 @@
    private final ConnectionFactory factory;
    /**
     * Creates a new entry container for the provided base DN and LDAP
     * connection factory.
     *
     * @param baseDN
     *            The base DN.
     * @param factory
     *            The LDAP connection factory.
     */
    public EntryContainer(final DN baseDN, final ConnectionFactory factory) {
        this.baseDN = baseDN;
        this.factory = factory;
    }
    /**
     * Returns the ETag for the provided entry.
     *
     * @param entry
     *            The entry.
     * @return The ETag.
     */
    public String getEtagFromEntry(final Entry entry) {
        return entry.parseAttribute(ETAG_ATTRIBUTE).asString();
    }
    /**
     * Returns the resource ID for the provided entry.
     *
     * @param entry
     *            The entry.
     * @return The resource ID.
     */
    public String getIDFromEntry(final Entry entry) {
        return entry.parseAttribute(UUID_ATTRIBUTE).asString();
    }
    /**
     * Lists the entries contained in this container.
     *
     * @param context
     *            The request context.
     * @param attributes
     *            The list of LDAP attributes to be returned.
     * @param handler
     *            The search result handler.
     */
    public void listEntries(final Context context, final Collection<String> attributes,
            final SearchResultHandler handler) {
        final String[] tmp = getSearchAttributes(attributes);
        final ConnectionCompletionHandler<Result> outerHandler =
                new ConnectionCompletionHandler<Result>(handler) {
        final ConnectionCompletionHandler<Result> outerHandler = new ConnectionCompletionHandler<Result>(
                handler) {
                    @Override
                    public void handleResult(final Connection connection) {
                        final SearchRequestCompletionHandler innerHandler =
                                new SearchRequestCompletionHandler(connection, handler);
                        final SearchRequest request =
                                Requests.newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter
                                        .objectClassPresent(), tmp);
                        connection.searchAsync(request, null, innerHandler);
                    }
            @Override
            public void handleResult(final Connection connection) {
                final SearchRequestCompletionHandler innerHandler = new SearchRequestCompletionHandler(
                        connection, handler);
                final SearchRequest request = Requests.newSearchRequest(baseDN,
                        SearchScope.SINGLE_LEVEL, Filter.objectClassPresent(), tmp);
                connection.searchAsync(request, null, innerHandler);
            }
                };
        };
        factory.getConnectionAsync(outerHandler);
    }
    /**
     * Reads the entry having the specified resource ID.
     *
     * @param c
     *            The request context.
     * @param id
     *            The resource ID.
     * @param attributes
     *            The list of LDAP attributes to be returned.
     * @param handler
     *            The search result handler.
     */
    public void readEntry(final Context c, final String id, final Collection<String> attributes,
            final ResultHandler<SearchResultEntry> handler) {
        final String[] tmp = getSearchAttributes(attributes);
        // @Checkstyle:off
        final ConnectionCompletionHandler<SearchResultEntry> outerHandler =
                new ConnectionCompletionHandler<SearchResultEntry>(handler) {
                    @Override
                    public void handleResult(final Connection connection) {
                        final RequestCompletionHandler<SearchResultEntry> innerHandler =
                                new RequestCompletionHandler<SearchResultEntry>(connection, handler);
                        final SearchRequest request =
                                Requests.newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter
                                        .equality(UUID_ATTRIBUTE, id), tmp);
                        connection.searchSingleEntryAsync(request, innerHandler);
                    }
            @Override
            public void handleResult(final Connection connection) {
                final RequestCompletionHandler<SearchResultEntry> innerHandler =
                        new RequestCompletionHandler<SearchResultEntry>(connection, handler);
                final SearchRequest request = Requests.newSearchRequest(baseDN,
                        SearchScope.SINGLE_LEVEL, Filter.equality(UUID_ATTRIBUTE, id), tmp);
                connection.searchSingleEntryAsync(request, innerHandler);
            }
                };
        };
        // @Checkstyle:on
        factory.getConnectionAsync(outerHandler);
    }
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import java.util.Collection;
@@ -26,7 +25,22 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
import org.forgerock.json.resource.*;
import org.forgerock.json.resource.ActionRequest;
import org.forgerock.json.resource.CollectionResourceProvider;
import org.forgerock.json.resource.CreateRequest;
import org.forgerock.json.resource.DeleteRequest;
import org.forgerock.json.resource.NotSupportedException;
import org.forgerock.json.resource.PatchRequest;
import org.forgerock.json.resource.QueryRequest;
import org.forgerock.json.resource.QueryResult;
import org.forgerock.json.resource.QueryResultHandler;
import org.forgerock.json.resource.ReadRequest;
import org.forgerock.json.resource.Resource;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResultHandler;
import org.forgerock.json.resource.ServerContext;
import org.forgerock.json.resource.UncategorizedException;
import org.forgerock.json.resource.UpdateRequest;
import org.forgerock.opendj.ldap.AssertionFailureException;
import org.forgerock.opendj.ldap.AuthenticationException;
import org.forgerock.opendj.ldap.AuthorizationException;
@@ -41,19 +55,27 @@
import org.forgerock.opendj.ldap.responses.SearchResultReference;
/**
 *
 * A {@code CollectionResourceProvider} implementation which maps a JSON
 * resource collection to LDAP entries beneath a base DN.
 */
public class LDAPCollectionResourceProvider implements CollectionResourceProvider {
    private final AttributeMapper attributeMapper;
    private final EntryContainer entryContainer;
    // Dummy exception used for signalling search success.
    private static final ResourceException SUCCESS = new UncategorizedException(0, null, null);
    private final AttributeMapper attributeMapper;
    private final EntryContainer entryContainer;
    /**
     * Creates a new LDAP resource.
     *
     * @param container
     *            The LDAP entry container.
     * @param mapper
     *            The attribute mapper which will be used for mapping LDAP
     *            attributes to JSON attributes.
     */
    public LDAPCollectionResourceProvider(final EntryContainer container, final AttributeMapper mapper) {
    public LDAPCollectionResourceProvider(final EntryContainer container,
            final AttributeMapper mapper) {
        this.entryContainer = container;
        this.attributeMapper = mapper;
    }
@@ -62,8 +84,8 @@
     * {@inheritDoc}
     */
    @Override
    public void actionCollection(ServerContext context, ActionRequest request,
            ResultHandler<JsonValue> handler) {
    public void actionCollection(final ServerContext context, final ActionRequest request,
            final ResultHandler<JsonValue> handler) {
        handler.handleError(new NotSupportedException("Not yet implemented"));
    }
@@ -71,8 +93,8 @@
     * {@inheritDoc}
     */
    @Override
    public void actionInstance(ServerContext context, String resourceId, ActionRequest request,
            ResultHandler<JsonValue> handler) {
    public void actionInstance(final ServerContext context, final String resourceId,
            final ActionRequest request, final ResultHandler<JsonValue> handler) {
        handler.handleError(new NotSupportedException("Not yet implemented"));
    }
@@ -80,8 +102,8 @@
     * {@inheritDoc}
     */
    @Override
    public void createInstance(ServerContext context, CreateRequest request,
            ResultHandler<Resource> handler) {
    public void createInstance(final ServerContext context, final CreateRequest request,
            final ResultHandler<Resource> handler) {
        handler.handleError(new NotSupportedException("Not yet implemented"));
    }
@@ -89,8 +111,8 @@
     * {@inheritDoc}
     */
    @Override
    public void deleteInstance(ServerContext context, String resourceId, DeleteRequest request,
            ResultHandler<Resource> handler) {
    public void deleteInstance(final ServerContext context, final String resourceId,
            final DeleteRequest request, final ResultHandler<Resource> handler) {
        handler.handleError(new NotSupportedException("Not yet implemented"));
    }
@@ -98,8 +120,8 @@
     * {@inheritDoc}
     */
    @Override
    public void patchInstance(ServerContext context, String resourceId, PatchRequest request,
            ResultHandler<Resource> handler) {
    public void patchInstance(final ServerContext context, final String resourceId,
            final PatchRequest request, final ResultHandler<Resource> handler) {
        handler.handleError(new NotSupportedException("Not yet implemented"));
    }
@@ -118,6 +140,62 @@
            private final AtomicReference<ResourceException> pendingResult = new AtomicReference<ResourceException>();
            private final AtomicBoolean resultSent = new AtomicBoolean();
            @Override
            public boolean handleEntry(final SearchResultEntry entry) {
                /*
                 * Search result entries will be returned before the search
                 * result/error so the only reason pendingResult will be
                 * non-null is if a mapping error has occurred.
                 */
                if (pendingResult.get() != null) {
                    return false;
                }
                // TODO: should the resource or the container define the ID
                // mapping?
                final String id = entryContainer.getIDFromEntry(entry);
                final String revision = entryContainer.getEtagFromEntry(entry);
                final ResultHandler<Map<String, Object>> mapHandler = new ResultHandler<Map<String, Object>>() {
                    @Override
                    public void handleError(final ResourceException e) {
                        pendingResult.compareAndSet(null, e);
                        pendingResourceCount.decrementAndGet();
                        completeIfNecessary();
                    }
                    @Override
                    public void handleResult(final Map<String, Object> result) {
                        final Resource resource = new Resource(id, revision, new JsonValue(result));
                        handler.handleResource(resource);
                        pendingResourceCount.decrementAndGet();
                        completeIfNecessary();
                    }
                };
                pendingResourceCount.incrementAndGet();
                attributeMapper.toJSON(context, entry, mapHandler);
                return true;
            }
            @Override
            public void handleErrorResult(final ErrorResultException error) {
                pendingResult.compareAndSet(null, adaptErrorResult(error));
                completeIfNecessary();
            }
            @Override
            public boolean handleReference(final SearchResultReference reference) {
                // TODO: should this be classed as an error since rest2ldap
                // assumes entries are all colocated?
                return true;
            }
            @Override
            public void handleResult(final Result result) {
                pendingResult.compareAndSet(null, SUCCESS);
                completeIfNecessary();
            }
            /*
             * Close out the query result set if there are no more pending
             * resources and the LDAP result has been received.
@@ -134,56 +212,6 @@
                    }
                }
            }
            public boolean handleEntry(final SearchResultEntry entry) {
                /*
                 * Search result entries will be returned before the search
                 * result/error so the only reason pendingResult will be
                 * non-null is if a mapping error has occurred.
                 */
                if (pendingResult.get() != null) {
                    return false;
                }
                // TODO: should the resource or the container define the ID
                // mapping?
                final String id = entryContainer.getIDFromEntry(entry);
                final String revision = entryContainer.getEtagFromEntry(entry);
                final ResultHandler<Map<String, Object>> mapHandler = new ResultHandler<Map<String, Object>>() {
                    public void handleError(final ResourceException e) {
                        pendingResult.compareAndSet(null, e);
                        pendingResourceCount.decrementAndGet();
                        completeIfNecessary();
                    }
                    public void handleResult(final Map<String, Object> result) {
                        Resource resource = new Resource(id, revision, new JsonValue(result));
                        handler.handleResource(resource);
                        pendingResourceCount.decrementAndGet();
                        completeIfNecessary();
                    }
                };
                pendingResourceCount.incrementAndGet();
                attributeMapper.toJson(context, entry, mapHandler);
                return true;
            }
            public void handleErrorResult(final ErrorResultException error) {
                pendingResult.compareAndSet(null, adaptErrorResult(error));
                completeIfNecessary();
            }
            public boolean handleReference(final SearchResultReference reference) {
                // TODO: should this be classed as an error since rest2ldap
                // assumes entries are all colocated?
                return true;
            }
            public void handleResult(final Result result) {
                pendingResult.compareAndSet(null, SUCCESS);
                completeIfNecessary();
            }
        };
        entryContainer.listEntries(context, requestedLDAPAttributes, searchHandler);
    }
@@ -193,32 +221,39 @@
     */
    @Override
    public void readInstance(final ServerContext context, final String resourceId,
            ReadRequest request, final ResultHandler<Resource> handler) {
            final ReadRequest request, final ResultHandler<Resource> handler) {
        // TODO: Determine the set of LDAP attributes that need to be read.
        final Set<JsonPointer> requestedAttributes = new LinkedHashSet<JsonPointer>();
        final Collection<String> requestedLDAPAttributes = getRequestedLDAPAttributes(requestedAttributes);
        final org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry> searchHandler = new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
        // @Checkstyle:off
        final org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry> searchHandler =
                new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
            @Override
            public void handleErrorResult(final ErrorResultException error) {
                handler.handleError(adaptErrorResult(error));
            }
            @Override
            public void handleResult(final SearchResultEntry entry) {
                final String revision = entryContainer.getEtagFromEntry(entry);
                final ResultHandler<Map<String, Object>> mapHandler = new ResultHandler<Map<String, Object>>() {
                    @Override
                    public void handleError(final ResourceException e) {
                        handler.handleError(e);
                    }
                    @Override
                    public void handleResult(final Map<String, Object> result) {
                        Resource resource = new Resource(resourceId, revision,
                                new JsonValue(result));
                        final Resource resource = new Resource(resourceId, revision, new JsonValue(
                                result));
                        handler.handleResult(resource);
                    }
                };
                attributeMapper.toJson(context, entry, mapHandler);
                attributeMapper.toJSON(context, entry, mapHandler);
            }
        };
        // @Checkstyle:on
        entryContainer.readEntry(context, resourceId, requestedLDAPAttributes, searchHandler);
    }
@@ -226,8 +261,8 @@
     * {@inheritDoc}
     */
    @Override
    public void updateInstance(ServerContext context, String resourceId, UpdateRequest request,
            ResultHandler<Resource> handler) {
    public void updateInstance(final ServerContext context, final String resourceId,
            final UpdateRequest request, final ResultHandler<Resource> handler) {
        handler.handleError(new NotSupportedException("Not yet implemented"));
    }
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import java.util.List;
@@ -28,7 +27,7 @@
import org.forgerock.opendj.ldap.Entry;
/**
 *
 * An attribute mapper which maps DN valued LDAP attributes to resource IDs.
 */
public class ReferenceAttributeMapper implements AttributeMapper {
@@ -37,6 +36,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        // TODO Auto-generated method stub
@@ -45,7 +45,9 @@
    /**
     * {@inheritDoc}
     */
    public void toJson(final ServerContext c, final Entry e, final ResultHandler<Map<String, Object>> h) {
    @Override
    public void toJSON(final ServerContext c, final Entry e,
            final ResultHandler<Map<String, Object>> h) {
        // TODO Auto-generated method stub
    }
@@ -53,7 +55,9 @@
    /**
     * {@inheritDoc}
     */
    public void toLDAP(final ServerContext c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
    @Override
    public void toLDAP(final ServerContext c, final JsonValue v,
            final ResultHandler<List<Attribute>> h) {
        // TODO Auto-generated method stub
    }
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import static org.forgerock.opendj.rest2ldap.Utils.byteStringToJson;
@@ -35,7 +34,8 @@
import org.forgerock.opendj.ldap.Functions;
/**
 *
 * An attribute mapper which maps a single JSON attribute to a single LDAP
 * attribute.
 */
public class SimpleAttributeMapper implements AttributeMapper {
@@ -43,7 +43,7 @@
    private Object defaultValue = null;
    private boolean forceSingleValued = false;
    private boolean isReadOnly = false;
    // private boolean isReadOnly = false;
    private final String jsonAttributeName;
    private final String ldapAttributeName;
    private final String normalizedJsonAttributeName;
@@ -74,7 +74,65 @@
        this.normalizedJsonAttributeName = toLowerCase(jsonAttributeName);
    }
    public SimpleAttributeMapper forceSingleValued(final boolean singleValued) {
    /**
     * Sets the decoder which will be used for converting LDAP attribute values
     * to JSON values.
     *
     * @param f
     *            The function to use for decoding LDAP attribute values.
     * @return This attribute mapper.
     */
    public SimpleAttributeMapper decoder(final Function<ByteString, ?, Void> f) {
        this.decoder = f;
        return this;
    }
    /**
     * Sets the default JSON value which should be substituted when the LDAP
     * attribute is not found in the LDAP entry.
     *
     * @param defaultValue
     *            The default JSON value.
     * @return This attribute mapper.
     */
    public SimpleAttributeMapper defaultJSONValue(final Object defaultValue) {
        this.defaultValue = defaultValue;
        return this;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        if (attributeMatchesPointer(jsonAttribute)) {
            ldapAttributes.add(ldapAttributeName);
        }
    }
    /**
     * Prevents the LDAP attribute from being updated.
     *
     * @param readOnly
     *            {@code true} if the LDAP attribute is read-only.
     * @return This attribute mapper.
     */
    public SimpleAttributeMapper readOnly(final boolean readOnly) {
        // TODO: enforcement policy: ignore, warn, or reject.
        // this.isReadOnly = readOnly;
        return this;
    }
    /**
     * Forces a multi-valued LDAP attribute to be represented as a single-valued
     * JSON value, rather than an array of values.
     *
     * @param singleValued
     *            {@code true} if the LDAP attribute should be treated as a
     *            single-valued attribute.
     * @return This attribute mapper.
     */
    public SimpleAttributeMapper singleValued(final boolean singleValued) {
        this.forceSingleValued = singleValued;
        return this;
    }
@@ -82,25 +140,13 @@
    /**
     * {@inheritDoc}
     */
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        if (attributeMatchesPointer(jsonAttribute)) {
            ldapAttributes.add(ldapAttributeName);
        }
    }
    public SimpleAttributeMapper isReadOnly(final boolean readOnly) {
        this.isReadOnly = readOnly;
        return this;
    }
    /**
     * {@inheritDoc}
     */
    public void toJson(final ServerContext c, final Entry e, final ResultHandler<Map<String, Object>> h) {
    @Override
    public void toJSON(final ServerContext c, final Entry e,
            final ResultHandler<Map<String, Object>> h) {
        final Attribute a = e.getAttribute(ldapAttributeName);
        if (a != null) {
            final Function<ByteString, ?, Void> f =
                    decoder == null ? Functions.fixedFunction(byteStringToJson(), a) : decoder;
            final Function<ByteString, ?, Void> f = decoder == null ? Functions.fixedFunction(
                    byteStringToJson(), a) : decoder;
            final Object value;
            if (forceSingleValued || a.getAttributeDescription().getAttributeType().isSingleValue()) {
                value = a.parse().as(f, defaultValue);
@@ -116,21 +162,13 @@
    /**
     * {@inheritDoc}
     */
    public void toLDAP(final ServerContext c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
    @Override
    public void toLDAP(final ServerContext c, final JsonValue v,
            final ResultHandler<List<Attribute>> h) {
        // TODO Auto-generated method stub
    }
    public SimpleAttributeMapper withDecoder(final Function<ByteString, ?, Void> f) {
        this.decoder = f;
        return this;
    }
    public SimpleAttributeMapper withDefaultValue(final Object defaultValue) {
        this.defaultValue = defaultValue;
        return this;
    }
    private boolean attributeMatchesPointer(final JsonPointer resourceAttribute) {
        return resourceAttribute.isEmpty()
                || toLowerCase(resourceAttribute.get(0)).equals(normalizedJsonAttributeName);
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import java.util.List;
@@ -28,7 +27,8 @@
import org.forgerock.opendj.ldap.Entry;
/**
 *
 * An attribute mapper which inlines LDAP attributes from subordinate LDAP
 * entries.
 */
public class SubContainerAttributeMapper implements AttributeMapper {
@@ -37,6 +37,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
        // TODO Auto-generated method stub
@@ -45,7 +46,9 @@
    /**
     * {@inheritDoc}
     */
    public void toJson(final ServerContext c, final Entry e, final ResultHandler<Map<String, Object>> h) {
    @Override
    public void toJSON(final ServerContext c, final Entry e,
            final ResultHandler<Map<String, Object>> h) {
        // TODO Auto-generated method stub
    }
@@ -53,7 +56,9 @@
    /**
     * {@inheritDoc}
     */
    public void toLDAP(final ServerContext c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
    @Override
    public void toLDAP(final ServerContext c, final JsonValue v,
            final ResultHandler<List<Attribute>> h) {
        // TODO Auto-generated method stub
    }
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
@@ -9,11 +9,10 @@
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyrighted [year] [name of copyright owner]".
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS. All rights reserved.
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
import static org.forgerock.opendj.ldap.schema.CoreSchema.getBooleanSyntax;
@@ -34,35 +33,37 @@
import org.forgerock.opendj.ldap.schema.Syntax;
/**
 *
 * Internal utility methods.
 */
final class Utils {
    // @Checkstyle:off
    private static final Function<ByteString, Object, Attribute> BYTESTRING_TO_JSON =
            new Function<ByteString, Object, Attribute>() {
                public Object apply(final ByteString value, final Attribute a) {
                    final Syntax syntax =
                            a.getAttributeDescription().getAttributeType().getSyntax();
                    if (syntax.equals(getBooleanSyntax())) {
                        return Functions.byteStringToBoolean().apply(value, null);
                    } else if (syntax.equals(getIntegerSyntax())) {
                        return Functions.byteStringToLong().apply(value, null);
                    } else if (syntax.equals(getGeneralizedTimeSyntax())) {
                        return DatatypeConverter.printDateTime(Functions
                                .byteStringToGeneralizedTime().apply(value, null).toCalendar());
                    } else if (syntax.isHumanReadable()) {
                        return Functions.byteStringToString().apply(value, null);
                    } else {
                        // Base 64 encoded binary.
                        return DatatypeConverter.printBase64Binary(value.toByteArray());
                    }
                }
            };
        @Override
        public Object apply(final ByteString value, final Attribute a) {
            final Syntax syntax = a.getAttributeDescription().getAttributeType().getSyntax();
            if (syntax.equals(getBooleanSyntax())) {
                return Functions.byteStringToBoolean().apply(value, null);
            } else if (syntax.equals(getIntegerSyntax())) {
                return Functions.byteStringToLong().apply(value, null);
            } else if (syntax.equals(getGeneralizedTimeSyntax())) {
                return DatatypeConverter.printDateTime(Functions.byteStringToGeneralizedTime()
                        .apply(value, null).toCalendar());
            } else if (syntax.isHumanReadable()) {
                return Functions.byteStringToString().apply(value, null);
            } else {
                // Base 64 encoded binary.
                return DatatypeConverter.printBase64Binary(value.toByteArray());
            }
        }
    };
    // @Checkstyle:on
    static Object attributeToJson(final Attribute a) {
        final Function<ByteString, Object, Void> f = Functions.fixedFunction(BYTESTRING_TO_JSON, a);
        final boolean isSingleValued =
                a.getAttributeDescription().getAttributeType().isSingleValue();
        final boolean isSingleValued = a.getAttributeDescription().getAttributeType()
                .isSingleValue();
        return isSingleValued ? a.parse().as(f) : asList(a.parse().asSetOf(f));
    }
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/package-info.java
@@ -1,27 +1,17 @@
/*
 * CDDL HEADER START
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2012 ForgeRock AS.
 * Copyright 2012 ForgeRock AS.
 */
/**
opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
@@ -34,13 +34,21 @@
import org.glassfish.grizzly.servlet.WebappContext;
/**
 * Example
 * Example.
 */
public class Example {
    private static final Logger LOGGER = Logger.getLogger(Example.class.getName());
    private static final int PORT = 18890;
    /**
     * REST 2 LDAP example application.
     *
     * @param args
     *            Command line arguments.
     * @throws Exception
     *             If an unexpected error occurred.
     */
    public static void main(final String[] args) throws Exception {
        // All LDAP resources will use this connection factory.
        final ConnectionFactory ldapFactory = newAuthenticatedConnectionFactory(
@@ -55,18 +63,18 @@
        // Create user resource.
        final AttributeMapper userMapper = new CompositeAttributeMapper().addMapper(
                new SimpleAttributeMapper("id", "entryUUID").forceSingleValued(true)).addMapper(
                new SimpleAttributeMapper("id", "entryUUID").singleValued(true)).addMapper(
                new DefaultAttributeMapper().includeAttribute("uid", "isMemberOf",
                        "modifyTimestamp")).addMapper(
                new ComplexAttributeMapper("name", new DefaultAttributeMapper().includeAttribute(
                        "cn", "sn", "givenName"))).addMapper(
                new ComplexAttributeMapper("contactInformation", new CompositeAttributeMapper()
                        .addMapper(
                                new SimpleAttributeMapper("telephoneNumber").withDecoder(
                                        Functions.byteStringToString()).forceSingleValued(true))
                                new SimpleAttributeMapper("telephoneNumber").decoder(
                                        Functions.byteStringToString()).singleValued(true))
                        .addMapper(
                                new SimpleAttributeMapper("emailAddress", "mail")
                                        .forceSingleValued(true))));
                                        .singleValued(true))));
        final LDAPCollectionResourceProvider userResource = new LDAPCollectionResourceProvider(
                userContainer, userMapper);
@@ -77,7 +85,7 @@
                groupContainer, groupMapper);
        // Create the router.
        Router router = new Router();
        final Router router = new Router();
        router.addRoute(RoutingMode.EQUALS, "/users", userResource);
        router.addRoute(RoutingMode.EQUALS, "/groups", groupResource);