From b09a9d843c32f9d4127d6a8db31a98cfdec9cbad Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 08 Feb 2013 11:37:59 +0000
Subject: [PATCH] Checkpoint changes: clean up APIs, separate out MVCC and naming strategies.
---
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java | 96 ++---
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java | 2
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java | 29 -
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java | 15
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java | 33 -
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java | 20
opendj-sdk/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java | 54 +-
/dev/null | 73 ----
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java | 37 -
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java | 45 -
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java | 321 +++++++++++++++++
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/MVCCStrategy.java | 60 +++
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/NameStrategy.java | 95 +++++
opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java | 162 +++-----
14 files changed, 660 insertions(+), 382 deletions(-)
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
index 9240bac..cdb9c5c 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
@@ -30,7 +30,15 @@
* An attribute mapper is responsible for converting JSON values to and from
* LDAP attributes.
*/
-public interface AttributeMapper {
+public abstract class AttributeMapper {
+ /*
+ * This interface is an abstract class so that methods can be made package
+ * private until API is finalized.
+ */
+
+ AttributeMapper() {
+ // Nothing to do.
+ }
/**
* Adds the names of the LDAP attributes required by this attribute mapper
@@ -48,7 +56,7 @@
* The set into which the required LDAP attribute names should be
* put.
*/
- void getLDAPAttributes(Context c, JsonPointer jsonAttribute, Set<String> ldapAttributes);
+ abstract void getLDAPAttributes(Context c, JsonPointer jsonAttribute, Set<String> ldapAttributes);
/**
* Transforms the provided REST comparison filter parameters to an LDAP
@@ -80,8 +88,8 @@
* @param h
* The result handler.
*/
- void getLDAPFilter(Context c, FilterType type, JsonPointer jsonAttribute, String operator,
- Object valueAssertion, ResultHandler<Filter> h);
+ abstract void getLDAPFilter(Context c, FilterType type, JsonPointer jsonAttribute,
+ String operator, Object valueAssertion, ResultHandler<Filter> h);
/**
* Transforms attributes contained in the provided LDAP entry to JSON
@@ -99,7 +107,7 @@
* @param h
* The result handler.
*/
- void toJSON(Context c, Entry e, ResultHandler<Map<String, Object>> h);
+ abstract void toJSON(Context c, Entry e, ResultHandler<Map<String, Object>> h);
/**
* Transforms JSON content in the provided JSON value to LDAP attributes,
@@ -116,7 +124,7 @@
* @param h
* The result handler.
*/
- void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h);
+ abstract void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h);
// TODO: methods for obtaining schema information (e.g. name, description,
// type information).
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java
index a5e5705..78a6672 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java
@@ -34,7 +34,7 @@
* An attribute mapper which maps a single JSON attribute to the result of
* another attribute mapper.
*/
-public class ComplexAttributeMapper implements AttributeMapper {
+final class ComplexAttributeMapper extends AttributeMapper {
private final String jsonAttributeName;
private final AttributeMapper mapper;
@@ -50,17 +50,14 @@
* The mapper which should be used to provide the contents of the
* complex attribute.
*/
- public ComplexAttributeMapper(final String jsonAttributeName, final AttributeMapper mapper) {
+ ComplexAttributeMapper(final String jsonAttributeName, final AttributeMapper mapper) {
this.jsonAttributeName = jsonAttributeName;
this.mapper = mapper;
this.normalizedJsonAttributeName = toLowerCase(jsonAttributeName);
}
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
+ void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
final Set<String> ldapAttributes) {
if (jsonAttribute.isEmpty() || matches(jsonAttribute)) {
final JsonPointer relativePointer = jsonAttribute.relativePointer();
@@ -68,13 +65,9 @@
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPFilter(final Context c, final FilterType type,
- final JsonPointer jsonAttribute, final String operator, final Object valueAssertion,
- final ResultHandler<Filter> h) {
+ void getLDAPFilter(final Context c, final FilterType type, final JsonPointer jsonAttribute,
+ final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
if (matches(jsonAttribute)) {
final JsonPointer relativePointer = jsonAttribute.relativePointer();
mapper.getLDAPFilter(c, type, relativePointer, operator, valueAssertion, h);
@@ -84,12 +77,8 @@
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toJSON(final Context c, final Entry e,
- final ResultHandler<Map<String, Object>> h) {
+ void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
final ResultHandler<Map<String, Object>> wrapper =
new ResultHandler<Map<String, Object>>() {
@@ -108,12 +97,8 @@
mapper.toJSON(c, e, wrapper);
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toLDAP(final Context c, final JsonValue v,
- final ResultHandler<List<Attribute>> h) {
+ void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
index c5dfa31..ca359ed 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
@@ -19,10 +19,10 @@
import static org.forgerock.opendj.rest2ldap.Utils.transform;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -39,46 +39,27 @@
* 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>();
+final class CompositeAttributeMapper extends AttributeMapper {
+ private final List<AttributeMapper> attributeMappers;
/**
* Creates a new composite attribute mapper.
*/
- public CompositeAttributeMapper() {
- // No implementation required.
+ CompositeAttributeMapper(final Collection<AttributeMapper> mappers) {
+ this.attributeMappers = new ArrayList<AttributeMapper>(mappers);
}
- /**
- * Adds a subordinate attribute mapper to this composite attribute mapper.
- *
- * @param mapper
- * The subordinate attribute mapper.
- * @return This composite attribute mapper.
- */
- public CompositeAttributeMapper addMapper(final AttributeMapper mapper) {
- attributeMappers.add(mapper);
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
+ void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
final Set<String> ldapAttributes) {
for (final AttributeMapper attribute : attributeMappers) {
attribute.getLDAPAttributes(c, jsonAttribute, ldapAttributes);
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPFilter(final Context c, final FilterType type,
- final JsonPointer jsonAttribute, final String operator, final Object valueAssertion,
- final ResultHandler<Filter> h) {
+ void getLDAPFilter(final Context c, final FilterType type, final JsonPointer jsonAttribute,
+ final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
final ResultHandler<Filter> handler =
accumulate(attributeMappers.size(), transform(
new Function<List<Filter>, Filter, Void>() {
@@ -113,11 +94,8 @@
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
+ void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
final ResultHandler<Map<String, Object>> handler =
accumulate(attributeMappers.size(), transform(
new Function<List<Map<String, Object>>, Map<String, Object>, Void>() {
@@ -141,11 +119,8 @@
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
+ void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java
index fec587e..6484101 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java
@@ -32,7 +32,7 @@
/**
* An attribute mapper which maps a single JSON attribute to a fixed value.
*/
-public class ConstantAttributeMapper implements AttributeMapper {
+final class ConstantAttributeMapper extends AttributeMapper {
private final String jsonAttributeName;
private final Object jsonAttributeValue;
@@ -45,27 +45,20 @@
* @param attributeValue
* The value of the simple JSON attribute.
*/
- public ConstantAttributeMapper(final String attributeName, final Object attributeValue) {
+ ConstantAttributeMapper(final String attributeName, final Object attributeValue) {
this.jsonAttributeName = attributeName;
this.jsonAttributeValue = attributeValue;
}
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
+ void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
final Set<String> ldapAttributes) {
// Nothing to do.
}
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPFilter(final Context c, final FilterType type,
- final JsonPointer jsonAttribute, final String operator, final Object valueAssertion,
- final ResultHandler<Filter> h) {
+ void getLDAPFilter(final Context c, final FilterType type, final JsonPointer jsonAttribute,
+ final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
if (jsonAttribute.size() == 1 && jsonAttribute.get(0).equalsIgnoreCase(jsonAttributeName)) {
final Filter filter;
if (type == FilterType.PRESENT) {
@@ -107,26 +100,20 @@
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
+ void toJSON(final Context 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));
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
+ void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
- private <T extends Comparable<T>> Filter compare(Context c, final FilterType type, final T v1,
- final T v2) {
+ private <T extends Comparable<T>> Filter compare(final Context c, final FilterType type,
+ final T v1, final T v2) {
final Filter filter;
switch (type) {
case EQUAL_TO:
@@ -134,8 +121,7 @@
break;
case GREATER_THAN:
filter =
- v1.compareTo(v2) > 0 ? c.getConfig().trueFilter() : c.getConfig()
- .falseFilter();
+ v1.compareTo(v2) > 0 ? c.getConfig().trueFilter() : c.getConfig().falseFilter();
break;
case GREATER_THAN_OR_EQUAL_TO:
filter =
@@ -144,8 +130,7 @@
break;
case LESS_THAN:
filter =
- v1.compareTo(v2) < 0 ? c.getConfig().trueFilter() : c.getConfig()
- .falseFilter();
+ v1.compareTo(v2) < 0 ? c.getConfig().trueFilter() : c.getConfig().falseFilter();
break;
case LESS_THAN_OR_EQUAL_TO:
filter =
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
index 5faf14f..cee7d06 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
@@ -24,7 +24,7 @@
private final Config config;
private final ServerContext context;
- Context(Config config, ServerContext context) {
+ Context(final Config config, final ServerContext context) {
this.config = config;
this.context = context;
}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java
index 8314c1b..7c8fe43 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java
@@ -36,7 +36,7 @@
* An attribute mapper that directly maps a configurable selection of attributes
* to and from LDAP without any transformation.
*/
-public final class DefaultAttributeMapper implements AttributeMapper {
+final class DefaultAttributeMapper extends AttributeMapper {
// All user attributes by default.
private final Map<String, String> excludedAttributes = new LinkedHashMap<String, String>();
private final Map<String, String> includedAttributes = new LinkedHashMap<String, String>();
@@ -45,7 +45,7 @@
* Creates a new default attribute mapper which will map all user attributes
* to JSON by default.
*/
- public DefaultAttributeMapper() {
+ DefaultAttributeMapper() {
// No implementation required.
}
@@ -56,18 +56,15 @@
* The attributes to be excluded.
* @return This attribute mapper.
*/
- public DefaultAttributeMapper excludeAttribute(final String... attributes) {
+ DefaultAttributeMapper excludeAttribute(final String... attributes) {
for (final String attribute : attributes) {
excludedAttributes.put(toLowerCase(attribute), attribute);
}
return this;
}
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
+ void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
final Set<String> ldapAttributes) {
switch (jsonAttribute.size()) {
case 0:
@@ -88,13 +85,9 @@
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void getLDAPFilter(final Context c, final FilterType type,
- final JsonPointer jsonAttribute, final String operator, final Object valueAssertion,
- final ResultHandler<Filter> h) {
+ void getLDAPFilter(final Context c, final FilterType type, final JsonPointer jsonAttribute,
+ final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
if (jsonAttribute.size() == 1 && isIncludedAttribute(jsonAttribute.get(0))) {
h.handleResult(toFilter(c, type, jsonAttribute.get(0), valueAssertion));
} else {
@@ -110,18 +103,17 @@
* The attributes to be included.
* @return This attribute mapper.
*/
- public DefaultAttributeMapper includeAttribute(final String... attributes) {
+ DefaultAttributeMapper includeAttribute(final String... attributes) {
for (final String attribute : attributes) {
includedAttributes.put(toLowerCase(attribute), attribute);
}
return this;
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
+ void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
+ // FIXME: this will leave out attributes which were not included in the LDAP entry. We should
+ // ensure that JSON attributes are present, even if they are null or an empty array.
final Map<String, Object> result = new LinkedHashMap<String, Object>(e.getAttributeCount());
for (final Attribute a : e.getAllAttributes()) {
final String name = getAttributeName(a);
@@ -132,11 +124,8 @@
h.handleResult(result);
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
+ void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
// TODO:
}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
index dd3b78f..8c4200b 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
@@ -49,13 +49,13 @@
import org.forgerock.json.resource.UncategorizedException;
import org.forgerock.json.resource.UpdateRequest;
import org.forgerock.opendj.ldap.AssertionFailureException;
+import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.AuthenticationException;
import org.forgerock.opendj.ldap.AuthorizationException;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionException;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.DN;
-import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.EntryNotFoundException;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.Filter;
@@ -64,6 +64,7 @@
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.TimeoutResultException;
+import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
import org.forgerock.opendj.ldap.responses.Result;
@@ -74,7 +75,7 @@
* A {@code CollectionResourceProvider} implementation which maps a JSON
* resource collection to LDAP entries beneath a base DN.
*/
-public class LDAPCollectionResourceProvider implements CollectionResourceProvider {
+final class LDAPCollectionResourceProvider implements CollectionResourceProvider {
private abstract class AbstractRequestCompletionHandler<R,
H extends org.forgerock.opendj.ldap.ResultHandler<? super R>>
@@ -137,17 +138,11 @@
super(connection, resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public final boolean handleEntry(final SearchResultEntry entry) {
return resultHandler.handleEntry(entry);
}
- /**
- * {@inheritDoc}
- */
@Override
public final boolean handleReference(final SearchResultReference reference) {
return resultHandler.handleReference(reference);
@@ -155,95 +150,93 @@
}
- // FIXME: make this configurable.
- private static final String ETAG_ATTRIBUTE = "etag";
-
// Dummy exception used for signalling search success.
private static final ResourceException SUCCESS = new UncategorizedException(0, null, null);
- // FIXME: make this configurable, also allow use of DN.
- private static final String UUID_ATTRIBUTE = "entryUUID";
-
private final AttributeMapper attributeMapper;
private final DN baseDN; // TODO: support template variables.
private final Config config;
private final ConnectionFactory factory;
+ private final MVCCStrategy mvccStrategy;
+ private final NameStrategy nameStrategy;
- /**
- * Creates a new LDAP resource.
- *
- * @param baseDN
- * The parent of all entries contained in this LDAP collection.
- * @param mapper
- * The attribute mapper which will be used for mapping LDAP
- * attributes to JSON attributes.
- * @param factory
- * The LDAP connection factory which will be used for performing
- * LDAP operations.
- * @param config
- * Common configuration options.
- */
- public LDAPCollectionResourceProvider(final DN baseDN, final AttributeMapper mapper,
- final ConnectionFactory factory, final Config config) {
+ LDAPCollectionResourceProvider(final DN baseDN, final AttributeMapper mapper,
+ final ConnectionFactory factory, final Config config, final NameStrategy nameStrategy,
+ final MVCCStrategy mvccStrategy) {
this.baseDN = baseDN;
this.attributeMapper = mapper;
this.factory = factory;
this.config = config;
+ this.nameStrategy = nameStrategy;
+ this.mvccStrategy = mvccStrategy;
}
- /**
- * {@inheritDoc}
- */
@Override
public void actionCollection(final ServerContext context, final ActionRequest request,
final ResultHandler<JsonValue> handler) {
handler.handleError(new NotSupportedException("Not yet implemented"));
}
- /**
- * {@inheritDoc}
- */
@Override
public void actionInstance(final ServerContext context, final String resourceId,
final ActionRequest request, final ResultHandler<JsonValue> handler) {
handler.handleError(new NotSupportedException("Not yet implemented"));
}
- /**
- * {@inheritDoc}
- */
@Override
public void createInstance(final ServerContext context, final CreateRequest request,
final ResultHandler<Resource> handler) {
- handler.handleError(new NotSupportedException("Not yet implemented"));
+ // We will support three use-cases:
+ //
+ // 1) client provided: the RDN is derived from the ID
+ // 2) client provided: the RDN is derived from a JSON attribute, the ID maps to a user attribute
+ // 3) server provided: the RDN is derived from a JSON attribute
+ //
+ // Procedure:
+ //
+ // 1) Generate LDAP attributes and create entry
+ // 2) Apply ID mapper: create RDN from entry/ID, store ID in entry
+ // 3) Create add request
+ // 4) Add post read control if policy rfc
+ // 5) Do add request
+ // 6) If add failed then return error
+ // 7) If policy is rfc then return entry
+ // 8) If policy is search then read entry
+ //
+ final Context c = wrap(context);
+ final AddRequest addRequest = Requests.newAddRequest(DN.rootDN());
+ attributeMapper.toLDAP(c, request.getContent(), new ResultHandler<List<Attribute>>() {
+ @Override
+ public void handleError(final ResourceException error) {
+ handler.handleError(error);
+ }
+
+ @Override
+ public void handleResult(final List<Attribute> result) {
+ for (final Attribute attribute : result) {
+ addRequest.addAttribute(attribute);
+ }
+ nameStrategy.setResourceId(c, baseDN, request.getNewResourceId(), addRequest);
+ }
+ });
}
- /**
- * {@inheritDoc}
- */
@Override
public void deleteInstance(final ServerContext context, final String resourceId,
final DeleteRequest request, final ResultHandler<Resource> handler) {
handler.handleError(new NotSupportedException("Not yet implemented"));
}
- /**
- * {@inheritDoc}
- */
@Override
public void patchInstance(final ServerContext context, final String resourceId,
final PatchRequest request, final ResultHandler<Resource> handler) {
handler.handleError(new NotSupportedException("Not yet implemented"));
}
- /**
- * {@inheritDoc}
- */
@Override
public void queryCollection(final ServerContext context, final QueryRequest request,
final QueryResultHandler handler) {
final Context c = wrap(context);
- final Collection<String> ldapAttributes = getLDAPAttributes(c, request.getFieldFilters());
// The handler which will be invoked for each LDAP search result.
final SearchResultHandler searchHandler = new SearchResultHandler() {
@@ -263,10 +256,8 @@
return false;
}
- // TODO: should the resource or the container define the ID
- // mapping?
- final String id = getIDFromEntry(entry);
- final String revision = getEtagFromEntry(entry);
+ final String id = nameStrategy.getResourceId(c, entry);
+ final String revision = mvccStrategy.getRevisionFromEntry(c, entry);
final ResultHandler<Map<String, Object>> mapHandler =
new ResultHandler<Map<String, Object>>() {
@Override
@@ -341,7 +332,6 @@
if (ldapFilter == null || ldapFilter == c.getConfig().falseFilter()) {
handler.handleResult(new QueryResult());
} else {
- final String[] tmp = getSearchAttributes(ldapAttributes);
final ConnectionCompletionHandler<Result> outerHandler =
new ConnectionCompletionHandler<Result>(searchHandler) {
@@ -350,9 +340,12 @@
final SearchRequestCompletionHandler innerHandler =
new SearchRequestCompletionHandler(connection,
searchHandler);
+ final String[] attributes =
+ getLDAPAttributes(c, request.getFieldFilters());
final SearchRequest request =
- Requests.newSearchRequest(baseDN,
- SearchScope.SINGLE_LEVEL, ldapFilter, tmp);
+ Requests.newSearchRequest(getBaseDN(c),
+ SearchScope.SINGLE_LEVEL, ldapFilter,
+ attributes);
connection.searchAsync(request, null, innerHandler);
}
@@ -366,15 +359,10 @@
getLDAPFilter(c, request.getQueryFilter(), filterHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void readInstance(final ServerContext context, final String resourceId,
final ReadRequest request, final ResultHandler<Resource> handler) {
final Context c = wrap(context);
- final Collection<String> ldapAttributes = getLDAPAttributes(c, request.getFieldFilters());
- final String[] tmp = getSearchAttributes(ldapAttributes);
// The handler which will be invoked for the LDAP search result.
final org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry> searchHandler =
@@ -386,7 +374,7 @@
@Override
public void handleResult(final SearchResultEntry entry) {
- final String revision = getEtagFromEntry(entry);
+ final String revision = mvccStrategy.getRevisionFromEntry(c, entry);
final ResultHandler<Map<String, Object>> mapHandler =
new ResultHandler<Map<String, Object>>() {
@Override
@@ -415,9 +403,10 @@
final RequestCompletionHandler<SearchResultEntry> innerHandler =
new RequestCompletionHandler<SearchResultEntry>(connection,
searchHandler);
+ final String[] attributes = getLDAPAttributes(c, request.getFieldFilters());
final SearchRequest request =
- Requests.newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter
- .equality(UUID_ATTRIBUTE, resourceId), tmp);
+ nameStrategy.createSearchRequest(c, getBaseDN(c), resourceId)
+ .addAttribute(attributes);
connection.searchSingleEntryAsync(request, innerHandler);
}
@@ -426,9 +415,6 @@
factory.getConnectionAsync(outerHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void updateInstance(final ServerContext context, final String resourceId,
final UpdateRequest request, final ResultHandler<Resource> handler) {
@@ -466,26 +452,8 @@
return ResourceException.getException(resourceResultCode, null, error.getMessage(), error);
}
- /**
- * Returns the ETag for the provided entry.
- *
- * @param entry
- * The entry.
- * @return The ETag.
- */
- private 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.
- */
- private String getIDFromEntry(final Entry entry) {
- return entry.parseAttribute(UUID_ATTRIBUTE).asString();
+ private DN getBaseDN(final Context context) {
+ return baseDN;
}
/**
@@ -497,8 +465,9 @@
* @return The set of LDAP attributes associated with the resource
* attributes.
*/
- private Collection<String> getLDAPAttributes(final Context c,
+ private String[] getLDAPAttributes(final Context c,
final Collection<JsonPointer> requestedAttributes) {
+ // Get all the LDAP attributes required by the attribute mappers.
final Set<String> requestedLDAPAttributes;
if (requestedAttributes.isEmpty()) {
// Full read.
@@ -511,7 +480,11 @@
attributeMapper.getLDAPAttributes(c, requestedAttribute, requestedLDAPAttributes);
}
}
- return requestedLDAPAttributes;
+
+ // Get the LDAP attributes required by the Etag and name stategies.
+ nameStrategy.getLDAPAttributes(c, requestedLDAPAttributes);
+ mvccStrategy.getLDAPAttributes(c, requestedLDAPAttributes);
+ return requestedLDAPAttributes.toArray(new String[requestedLDAPAttributes.size()]);
}
private void getLDAPFilter(final Context c, final QueryFilter queryFilter,
@@ -700,15 +673,6 @@
queryFilter.accept(visitor, h);
}
- private String[] getSearchAttributes(final Collection<String> attributes) {
- // FIXME: who is responsible for adding the UUID and etag attributes to
- // this search?
- final String[] tmp = attributes.toArray(new String[attributes.size() + 2]);
- tmp[tmp.length - 2] = UUID_ATTRIBUTE;
- tmp[tmp.length - 1] = ETAG_ATTRIBUTE;
- return tmp;
- }
-
private Context wrap(final ServerContext context) {
return new Context(config, context);
}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/MVCCStrategy.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/MVCCStrategy.java
new file mode 100644
index 0000000..8e04aaf
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/MVCCStrategy.java
@@ -0,0 +1,60 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+
+package org.forgerock.opendj.rest2ldap;
+
+import java.util.Set;
+
+import org.forgerock.opendj.ldap.Entry;
+
+/**
+ * A multi-version concurrency control strategy is responsible for ensuring that
+ * clients can perform atomic updates to LDAP resources.
+ */
+public abstract class MVCCStrategy {
+ /*
+ * This interface is an abstract class so that methods can be made package
+ * private until API is finalized.
+ */
+
+ MVCCStrategy() {
+ // Nothing to do.
+ }
+
+ /**
+ * Retrieves the revision value (etag) from the provided LDAP entry.
+ *
+ * @param c
+ * The context.
+ * @param entry
+ * The LDAP entry.
+ * @return The revision value.
+ */
+ abstract String getRevisionFromEntry(Context c, Entry entry);
+
+ /**
+ * Adds the name of any LDAP attribute required by this MVCC strategy to the
+ * provided set.
+ *
+ * @param c
+ * The context.
+ * @param ldapAttributes
+ * The set into which any required LDAP attribute name should be
+ * put.
+ */
+ abstract void getLDAPAttributes(Context c, Set<String> ldapAttributes);
+
+}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/NameStrategy.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/NameStrategy.java
new file mode 100644
index 0000000..3010cc3
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/NameStrategy.java
@@ -0,0 +1,95 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+
+package org.forgerock.opendj.rest2ldap;
+
+import java.util.Set;
+
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+
+/**
+ * A name strategy is responsible for naming REST resources and LDAP entries.
+ */
+public abstract class NameStrategy {
+ /*
+ * This interface is an abstract class so that methods can be made package
+ * private until API is finalized.
+ */
+
+ NameStrategy() {
+ // Nothing to do.
+ }
+
+ /**
+ * Returns a search request which can be used to obtain the specified REST
+ * resource.
+ *
+ * @param c
+ * The context.
+ * @param baseDN
+ * The search base DN.
+ * @param resourceId
+ * The resource ID.
+ * @return A search request which can be used to obtain the specified REST
+ * resource.
+ */
+ abstract SearchRequest createSearchRequest(Context c, DN baseDN, String resourceId);
+
+ /**
+ * Adds the name of any LDAP attribute required by this name strategy to the
+ * provided set.
+ *
+ * @param c
+ * The context.
+ * @param ldapAttributes
+ * The set into which any required LDAP attribute name should be
+ * put.
+ */
+ abstract void getLDAPAttributes(Context c, Set<String> ldapAttributes);
+
+ /**
+ * Retrieves the resource ID from the provided LDAP entry. Implementations
+ * may use the entry DN as well as any attributes in order to determine the
+ * resource ID.
+ *
+ * @param c
+ * The context.
+ * @param entry
+ * The LDAP entry from which the resource ID should be obtained.
+ * @return The resource ID.
+ */
+ abstract String getResourceId(Context c, Entry entry);
+
+ /**
+ * Sets the resource ID in the provided LDAP entry. Implementations are
+ * responsible for setting the entry DN as well as any attributes associated
+ * with the resource ID.
+ *
+ * @param c
+ * The context.
+ * @param baseDN
+ * The baseDN to use when constructing the entry's DN.
+ * @param resourceId
+ * The resource ID.
+ * @param entry
+ * The LDAP entry whose DN and resource ID attributes are to be
+ * set.
+ */
+ abstract void setResourceId(Context c, DN baseDN, String resourceId, Entry entry);
+
+}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
deleted file mode 100644
index 645c14c..0000000
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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-2013 ForgeRock AS.
- */
-package org.forgerock.opendj.rest2ldap;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.forgerock.json.fluent.JsonPointer;
-import org.forgerock.json.fluent.JsonValue;
-import org.forgerock.json.resource.ResultHandler;
-import org.forgerock.opendj.ldap.Attribute;
-import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.opendj.ldap.Filter;
-
-/**
- * An attribute mapper which maps DN valued LDAP attributes to resource IDs.
- */
-public class ReferenceAttributeMapper implements AttributeMapper {
-
- // private final EntryContainer referencedContainer;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
- final Set<String> ldapAttributes) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void getLDAPFilter(final Context c, final FilterType type,
- final JsonPointer jsonAttribute, final String operator, final Object valueAssertion,
- final ResultHandler<Filter> h) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
- // TODO Auto-generated method stub
- }
-
-}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java
new file mode 100644
index 0000000..46ad0f4
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java
@@ -0,0 +1,321 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+
+package org.forgerock.opendj.rest2ldap;
+
+import static org.forgerock.opendj.ldap.requests.Requests.newSearchRequest;
+import static org.forgerock.opendj.ldap.schema.CoreSchema.getEntryUUIDAttributeType;
+import static org.forgerock.opendj.rest2ldap.Utils.ensureNotNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.forgerock.json.resource.CollectionResourceProvider;
+import org.forgerock.opendj.ldap.AttributeDescription;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ConnectionFactory;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.Filter;
+import org.forgerock.opendj.ldap.LinkedAttribute;
+import org.forgerock.opendj.ldap.RDN;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.schema.AttributeType;
+import org.forgerock.opendj.ldap.schema.Schema;
+
+/**
+ * Provides core factory methods and builders for constructing LDAP resource
+ * collections.
+ */
+public final class Rest2LDAP {
+ // @Checkstyle:off
+
+ /**
+ * A builder for incrementally constructing LDAP resource collections.
+ */
+ public static final class Builder {
+ private DN baseDN; // TODO: support template variables.
+ private Config config = Config.defaultConfig();
+ private ConnectionFactory factory;
+ private final List<AttributeMapper> mappers = new LinkedList<AttributeMapper>();
+ private MVCCStrategy mvccStrategy = mvccUsingEtag();
+ private NameStrategy nameStrategy = nameByEntryUUID("uid");
+
+ Builder() {
+ // No implementation required.
+ }
+
+ public Builder baseDN(final DN dn) {
+ ensureNotNull(dn);
+ this.baseDN = dn;
+ return this;
+ }
+
+ public Builder baseDN(final String dn) {
+ ensureNotNull(dn);
+ this.baseDN = DN.valueOf(dn);
+ return this;
+ }
+
+ public CollectionResourceProvider build() {
+ ensureNotNull(factory);
+ ensureNotNull(baseDN);
+ if (mappers.isEmpty()) {
+ throw new IllegalStateException("No mappings provided");
+ }
+ return new LDAPCollectionResourceProvider(baseDN, mapOf(mappers), factory, config,
+ nameStrategy, mvccStrategy);
+ }
+
+ public Builder config(final Config config) {
+ ensureNotNull(config);
+ this.config = config;
+ return this;
+ }
+
+ public Builder factory(final ConnectionFactory factory) {
+ ensureNotNull(factory);
+ this.factory = factory;
+ return this;
+ }
+
+ public Builder map(final AttributeMapper... mappers) {
+ ensureNotNull(mappers);
+ this.mappers.addAll(Arrays.asList(mappers));
+ return this;
+ }
+
+ public Builder map(final Collection<AttributeMapper> mappers) {
+ ensureNotNull(mappers);
+ this.mappers.addAll(mappers);
+ return this;
+ }
+
+ public Builder with(final MVCCStrategy strategy) {
+ ensureNotNull(strategy);
+ this.mvccStrategy = strategy;
+ return this;
+ }
+
+ public Builder with(final NameStrategy strategy) {
+ ensureNotNull(strategy);
+ this.nameStrategy = strategy;
+ return this;
+ }
+ }
+
+ private static final class AttributeMVCCStrategy extends MVCCStrategy {
+ private final AttributeDescription ldapAttribute;
+
+ private AttributeMVCCStrategy(final AttributeDescription ldapAttribute) {
+ this.ldapAttribute = ldapAttribute;
+ }
+
+ @Override
+ String getRevisionFromEntry(final Context c, final Entry entry) {
+ return entry.parseAttribute(ldapAttribute).asString();
+ }
+
+ @Override
+ void getLDAPAttributes(final Context c, final Set<String> ldapAttributes) {
+ ldapAttributes.add(ldapAttribute.toString());
+ }
+ }
+
+ private static final class AttributeNameStrategy extends NameStrategy {
+ private final AttributeDescription dnAttribute;
+ private final AttributeDescription idAttribute;
+ private final boolean isServerProvided;
+
+ private AttributeNameStrategy(final AttributeType dnAttribute,
+ final AttributeDescription idAttribute, final boolean isServerProvided) {
+ this.dnAttribute = AttributeDescription.create(dnAttribute);
+ if (dnAttribute.equals(idAttribute)) {
+ throw new IllegalArgumentException("DN and ID attributes must be different");
+ }
+ this.idAttribute = ensureNotNull(idAttribute);
+ this.isServerProvided = isServerProvided;
+ }
+
+ @Override
+ SearchRequest createSearchRequest(final Context c, final DN baseDN, final String resourceId) {
+ return newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter.equality(idAttribute
+ .toString(), resourceId));
+ }
+
+ @Override
+ void getLDAPAttributes(final Context c, final Set<String> ldapAttributes) {
+ ldapAttributes.add(idAttribute.toString());
+ }
+
+ @Override
+ String getResourceId(final Context c, final Entry entry) {
+ return entry.parseAttribute(idAttribute).asString();
+ }
+
+ @Override
+ void setResourceId(final Context c, final DN baseDN, final String resourceId,
+ final Entry entry) {
+ if (!isServerProvided) {
+ entry.addAttribute(new LinkedAttribute(idAttribute, ByteString.valueOf(resourceId)));
+ }
+ final String rdnValue = entry.parseAttribute(dnAttribute).asString();
+ final RDN rdn = new RDN(dnAttribute.getAttributeType(), rdnValue);
+ entry.setName(baseDN.child(rdn));
+
+ }
+ }
+
+ private static final class DNNameStrategy extends NameStrategy {
+ private final AttributeDescription attribute;
+
+ private DNNameStrategy(final AttributeType attribute) {
+ this.attribute = AttributeDescription.create(attribute);
+ }
+
+ @Override
+ SearchRequest createSearchRequest(final Context c, final DN baseDN, final String resourceId) {
+ return newSearchRequest(baseDN.child(rdn(resourceId)), SearchScope.BASE_OBJECT, c
+ .getConfig().trueFilter());
+ }
+
+ @Override
+ void getLDAPAttributes(final Context c, final Set<String> ldapAttributes) {
+ ldapAttributes.add(attribute.toString());
+ }
+
+ @Override
+ String getResourceId(final Context c, final Entry entry) {
+ return entry.parseAttribute(attribute).asString();
+ }
+
+ @Override
+ void setResourceId(final Context c, final DN baseDN, final String resourceId,
+ final Entry entry) {
+ entry.setName(baseDN.child(rdn(resourceId)));
+ entry.addAttribute(new LinkedAttribute(attribute, ByteString.valueOf(resourceId)));
+ }
+
+ private RDN rdn(final String resourceId) {
+ return new RDN(attribute.getAttributeType(), resourceId);
+ }
+
+ }
+
+ public static SimpleAttributeMapper map(final AttributeDescription attribute) {
+ return map(attribute.toString(), attribute);
+ }
+
+ public static SimpleAttributeMapper map(final String attribute) {
+ return map(attribute, attribute);
+ }
+
+ public static SimpleAttributeMapper map(final String jsonAttribute,
+ final AttributeDescription ldapAttribute) {
+ return new SimpleAttributeMapper(jsonAttribute, ldapAttribute);
+ }
+
+ public static SimpleAttributeMapper map(final String jsonAttribute, final String ldapAttribute) {
+ return map(jsonAttribute, AttributeDescription.valueOf(ldapAttribute));
+ }
+
+ public static AttributeMapper mapAllExcept(final String... attributes) {
+ return new DefaultAttributeMapper().excludeAttribute(attributes);
+ }
+
+ public static AttributeMapper mapAllOf(final String... attributes) {
+ return new DefaultAttributeMapper().includeAttribute(attributes);
+ }
+
+ public static AttributeMapper mapComplex(final String jsonAttribute,
+ final AttributeMapper... mappers) {
+ return mapComplex(jsonAttribute, Arrays.asList(mappers));
+ }
+
+ public static AttributeMapper mapComplex(final String jsonAttribute,
+ final Collection<AttributeMapper> mappers) {
+ return new ComplexAttributeMapper(jsonAttribute, mapOf(mappers));
+ }
+
+ public static AttributeMapper mapConstant(final String attribute, final Object attributeValue) {
+ return new ConstantAttributeMapper(attribute, attributeValue);
+ }
+
+ public static MVCCStrategy mvccUsingAttribute(final AttributeDescription attribute) {
+ return new AttributeMVCCStrategy(attribute);
+ }
+
+ public static MVCCStrategy mvccUsingAttribute(final String attribute) {
+ return mvccUsingAttribute(AttributeDescription.valueOf(attribute));
+ }
+
+ public static MVCCStrategy mvccUsingEtag() {
+ return mvccUsingAttribute("etag");
+ }
+
+ public static NameStrategy nameByClient(final AttributeType dnAttribute,
+ final AttributeDescription idAttribute) {
+ return new AttributeNameStrategy(dnAttribute, idAttribute, false);
+ }
+
+ public static NameStrategy nameByClient(final String dnAttribute, final String idAttribute) {
+ return nameByClient(Schema.getDefaultSchema().getAttributeType(dnAttribute),
+ AttributeDescription.valueOf(idAttribute));
+ }
+
+ public static NameStrategy nameByDN(final AttributeType attribute) {
+ return new DNNameStrategy(attribute);
+ }
+
+ public static NameStrategy nameByDN(final String attribute) {
+ return nameByDN(Schema.getDefaultSchema().getAttributeType(attribute));
+ }
+
+ public static NameStrategy nameByEntryUUID(final AttributeType dnAttribute) {
+ return nameByServer(dnAttribute, AttributeDescription.create(getEntryUUIDAttributeType()));
+ }
+
+ public static NameStrategy nameByEntryUUID(final String dnAttribute) {
+ return nameByEntryUUID(Schema.getDefaultSchema().getAttributeType(dnAttribute));
+ }
+
+ public static NameStrategy nameByServer(final AttributeType dnAttribute,
+ final AttributeDescription idAttribute) {
+ return new AttributeNameStrategy(dnAttribute, idAttribute, true);
+ }
+
+ public static NameStrategy nameByServer(final String dnAttribute, final String idAttribute) {
+ return nameByServer(Schema.getDefaultSchema().getAttributeType(dnAttribute),
+ AttributeDescription.valueOf(idAttribute));
+ }
+
+ public static Builder collection() {
+ return new Builder();
+ }
+
+ private static AttributeMapper mapOf(final Collection<AttributeMapper> mappers) {
+ return new CompositeAttributeMapper(mappers);
+ }
+
+ private Rest2LDAP() {
+ // Prevent instantiation.
+ }
+
+}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
index 8d6a1c5..dabc613 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
@@ -19,6 +19,7 @@
import static org.forgerock.opendj.rest2ldap.Utils.toFilter;
import static org.forgerock.opendj.rest2ldap.Utils.toLowerCase;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -28,6 +29,7 @@
import org.forgerock.json.fluent.JsonValue;
import org.forgerock.json.resource.ResultHandler;
import org.forgerock.opendj.ldap.Attribute;
+import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.Filter;
@@ -38,38 +40,29 @@
* An attribute mapper which maps a single JSON attribute to a single LDAP
* attribute.
*/
-public class SimpleAttributeMapper implements AttributeMapper {
+public final class SimpleAttributeMapper extends AttributeMapper {
private Function<ByteString, ?, Void> decoder = null;
private Object defaultValue = null;
+ private Collection<Object> defaultValues = Collections.emptySet();
private boolean forceSingleValued = false;
// private boolean isReadOnly = false;
private final String jsonAttributeName;
- private final String ldapAttributeName;
+ private final AttributeDescription ldapAttributeName;
private final String normalizedJsonAttributeName;
/**
* Creates a new simple attribute mapper which maps a single LDAP attribute
* to an entry.
*
- * @param attributeName
- * The name of the simple JSON and LDAP attribute.
- */
- public SimpleAttributeMapper(final String attributeName) {
- this(attributeName, attributeName);
- }
-
- /**
- * Creates a new simple attribute mapper which maps a single LDAP attribute
- * to an entry.
- *
* @param jsonAttributeName
* The name of the simple JSON attribute.
* @param ldapAttributeName
* The name of the LDAP attribute.
*/
- public SimpleAttributeMapper(final String jsonAttributeName, final String ldapAttributeName) {
+ SimpleAttributeMapper(final String jsonAttributeName,
+ final AttributeDescription ldapAttributeName) {
this.jsonAttributeName = jsonAttributeName;
this.ldapAttributeName = ldapAttributeName;
this.normalizedJsonAttributeName = toLowerCase(jsonAttributeName);
@@ -98,36 +91,12 @@
*/
public SimpleAttributeMapper defaultJSONValue(final Object defaultValue) {
this.defaultValue = defaultValue;
+ this.defaultValues =
+ defaultValue != null ? Collections.singleton(defaultValue) : Collections.emptySet();
return this;
}
/**
- * {@inheritDoc}
- */
- @Override
- public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
- final Set<String> ldapAttributes) {
- if (jsonAttribute.isEmpty() || matches(jsonAttribute)) {
- ldapAttributes.add(ldapAttributeName);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void getLDAPFilter(final Context c, final FilterType type,
- final JsonPointer jsonAttribute, final String operator, final Object valueAssertion,
- final ResultHandler<Filter> h) {
- if (matches(jsonAttribute)) {
- h.handleResult(toFilter(c, type, ldapAttributeName, valueAssertion));
- } else {
- // This attribute mapper cannot handle the provided filter component.
- h.handleResult(null);
- }
- }
-
- /**
* Prevents the LDAP attribute from being updated.
*
* @param readOnly
@@ -154,32 +123,41 @@
return this;
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toJSON(final Context 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 Object value;
- if (forceSingleValued || a.getAttributeDescription().getAttributeType().isSingleValue()) {
- value = a.parse().as(f, defaultValue);
- } else {
- value = a.parse().asSetOf(f, defaultValue);
- }
- h.handleResult(Collections.singletonMap(jsonAttributeName, value));
+ void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
+ final Set<String> ldapAttributes) {
+ if (jsonAttribute.isEmpty() || matches(jsonAttribute)) {
+ ldapAttributes.add(ldapAttributeName.toString());
+ }
+ }
+
+ @Override
+ void getLDAPFilter(final Context c, final FilterType type, final JsonPointer jsonAttribute,
+ final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
+ if (matches(jsonAttribute)) {
+ h.handleResult(toFilter(c, type, ldapAttributeName.toString(), valueAssertion));
} else {
+ // This attribute mapper cannot handle the provided filter component.
h.handleResult(null);
}
}
- /**
- * {@inheritDoc}
- */
@Override
- public void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
+ void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
+ final Function<ByteString, ?, Void> f =
+ decoder == null ? Functions.fixedFunction(byteStringToJson(), ldapAttributeName)
+ : decoder;
+ final Object value;
+ if (forceSingleValued || ldapAttributeName.getAttributeType().isSingleValue()) {
+ value = e.parseAttribute(ldapAttributeName).as(f, defaultValue);
+ } else {
+ value = e.parseAttribute(ldapAttributeName).asSetOf(f, defaultValues);
+ }
+ h.handleResult(Collections.singletonMap(jsonAttributeName, value));
+ }
+
+ @Override
+ void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java
deleted file mode 100644
index 5b5de74..0000000
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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-2013 ForgeRock AS.
- */
-package org.forgerock.opendj.rest2ldap;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.forgerock.json.fluent.JsonPointer;
-import org.forgerock.json.fluent.JsonValue;
-import org.forgerock.json.resource.ResultHandler;
-import org.forgerock.opendj.ldap.Attribute;
-import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.opendj.ldap.Filter;
-
-/**
- * An attribute mapper which inlines LDAP attributes from subordinate LDAP
- * entries.
- */
-public class SubContainerAttributeMapper implements AttributeMapper {
-
- // private final EntryContainer referencedContainer;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
- final Set<String> ldapAttributes) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void getLDAPFilter(final Context c, final FilterType type,
- final JsonPointer jsonAttribute, final String operator, final Object valueAssertion,
- final ResultHandler<Filter> h) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
- // TODO Auto-generated method stub
-
- }
-
-}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
index 7fa9bac..43c47a5 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
@@ -31,6 +31,7 @@
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResultHandler;
import org.forgerock.opendj.ldap.Attribute;
+import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.Filter;
import org.forgerock.opendj.ldap.Function;
@@ -85,12 +86,11 @@
}
// @Checkstyle:off
- private static final Function<ByteString, Object, Attribute> BYTESTRING_TO_JSON =
- new Function<ByteString, Object, Attribute>() {
+ private static final Function<ByteString, Object, AttributeDescription> BYTESTRING_TO_JSON =
+ new Function<ByteString, Object, AttributeDescription>() {
@Override
- public Object apply(final ByteString value, final Attribute a) {
- final Syntax syntax =
- a.getAttributeDescription().getAttributeType().getSyntax();
+ public Object apply(final ByteString value, final AttributeDescription ad) {
+ final Syntax syntax = ad.getAttributeType().getSyntax();
if (syntax.equals(getBooleanSyntax())) {
return Functions.byteStringToBoolean().apply(value, null);
} else if (syntax.equals(getIntegerSyntax())) {
@@ -112,7 +112,8 @@
}
static Object attributeToJson(final Attribute a) {
- final Function<ByteString, Object, Void> f = Functions.fixedFunction(BYTESTRING_TO_JSON, a);
+ final Function<ByteString, Object, Void> f =
+ Functions.fixedFunction(BYTESTRING_TO_JSON, a.getAttributeDescription());
final boolean isSingleValued =
a.getAttributeDescription().getAttributeType().isSingleValue();
return isSingleValued ? a.parse().as(f) : asList(a.parse().asSetOf(f));
@@ -120,7 +121,7 @@
// @Checkstyle:on
- static Function<ByteString, Object, Attribute> byteStringToJson() {
+ static Function<ByteString, Object, AttributeDescription> byteStringToJson() {
return BYTESTRING_TO_JSON;
}
diff --git a/opendj-sdk/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java b/opendj-sdk/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
index 720ea47..0b06eeb 100644
--- a/opendj-sdk/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
+++ b/opendj-sdk/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
@@ -18,13 +18,17 @@
import static org.forgerock.json.resource.Resources.newInternalConnectionFactory;
import static org.forgerock.opendj.ldap.Connections.newAuthenticatedConnectionFactory;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.collection;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.map;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.mapAllOf;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.mapComplex;
import java.util.logging.Logger;
+import org.forgerock.json.resource.CollectionResourceProvider;
import org.forgerock.json.resource.Router;
import org.forgerock.json.resource.servlet.HttpServlet;
import org.forgerock.opendj.ldap.ConnectionFactory;
-import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.Functions;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.requests.Requests;
@@ -55,39 +59,25 @@
Requests.newSimpleBindRequest("cn=directory manager", "password"
.toCharArray()));
- // Create user resource.
- final AttributeMapper userMapper =
- new CompositeAttributeMapper().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").decoder(
- Functions.byteStringToString()).singleValued(true))
- .addMapper(
- new SimpleAttributeMapper("emailAddress", "mail")
- .singleValued(true))));
-
- final LDAPCollectionResourceProvider userResource =
- new LDAPCollectionResourceProvider(DN.valueOf("ou=people,dc=example,dc=com"),
- userMapper, ldapFactory, Config.defaultConfig());
-
- // Create group resource.
- final AttributeMapper groupMapper =
- new DefaultAttributeMapper().includeAttribute("cn", "ou", "description",
- "uniquemember");
-
- final LDAPCollectionResourceProvider groupResource =
- new LDAPCollectionResourceProvider(DN.valueOf("ou=groups,dc=example,dc=com"),
- groupMapper, ldapFactory, Config.defaultConfig());
-
// Create the router.
final Router router = new Router();
- router.addRoute("/users", userResource);
- router.addRoute("/groups", groupResource);
+
+ // Create user resource.
+ CollectionResourceProvider users =
+ collection().factory(ldapFactory).baseDN("ou=people,dc=example,dc=com").map(
+ map("id", "entryUUID").singleValued(true),
+ mapAllOf("uid", "isMemberOf", "modifyTimestamp"),
+ mapComplex("name", mapAllOf("cn", "sn", "givenName")),
+ mapComplex("contactInformation", map("telephoneNumber").decoder(
+ Functions.byteStringToString()).singleValued(true), map(
+ "emailAddress", "mail").singleValued(true))).build();
+ router.addRoute("/users", users);
+
+ // Create group resource.
+ CollectionResourceProvider groups =
+ collection().factory(ldapFactory).baseDN("ou=groups,dc=example,dc=com").map(
+ mapAllOf("cn", "ou", "description", "uniquemember")).build();
+ router.addRoute("/groups", groups);
final org.forgerock.json.resource.ConnectionFactory resourceFactory =
newInternalConnectionFactory(router);
--
Gitblit v1.10.0