From db786032bf45be89c4a893281911364d158cfb6e Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Sat, 20 Oct 2012 10:10:53 +0000
Subject: [PATCH] Update to use new json-resource 2.0 APIs.
---
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java | 46 +-
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java | 69 +-
opendj3/opendj-rest2ldap/pom.xml | 57 +-
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java | 146 +++---
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java | 63 +-
opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java | 105 ++++
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java | 24
/dev/null | 244 -----------
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java | 61 ++
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java | 74 +-
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java | 56 +-
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java | 17
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java | 290 +++++++++++++
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java | 9
14 files changed, 747 insertions(+), 514 deletions(-)
diff --git a/opendj3/opendj-rest2ldap/pom.xml b/opendj3/opendj-rest2ldap/pom.xml
index 67ae69a..0c5d7ed 100644
--- a/opendj3/opendj-rest2ldap/pom.xml
+++ b/opendj3/opendj-rest2ldap/pom.xml
@@ -61,45 +61,32 @@
<dependency>
<groupId>org.forgerock.commons</groupId>
<artifactId>json-fluent</artifactId>
- <version>1.2.0-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
+ <groupId>org.forgerock.commons</groupId>
+ <artifactId>json-resource</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.forgerock.commons</groupId>
+ <artifactId>json-resource-servlet</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>2.3-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.forgerock.commons</groupId>
- <artifactId>org.forgerock.json.resource</artifactId>
- <version>1.3.0-SNAPSHOT</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.forgerock.commons</groupId>
- <artifactId>org.forgerock.json.resource.restlet</artifactId>
- <version>1.3.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.forgerock.commons</groupId>
- <artifactId>org.forgerock.restlet</artifactId>
- <version>1.1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.forgerock.commons</groupId>
- <artifactId>json-patch</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>org.restlet.jse</groupId>
- <artifactId>org.restlet</artifactId>
- <version>2.0.9</version>
- </dependency>
- <dependency>
- <groupId>org.restlet.jse</groupId>
- <artifactId>org.restlet.ext.jackson</artifactId>
- <version>2.0.9</version>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.0.1</version>
+ <scope>test</scope>
</dependency>
</dependencies>
<build>
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
index e906357..3590234 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
@@ -22,12 +22,14 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.ResultHandler;
+import org.forgerock.json.resource.ServerContext;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.resource.provider.Context;
/**
- *
+ * An attribute mapper is responsible for converting JSON values to and from
+ * LDAP attributes.
*/
public interface AttributeMapper {
@@ -38,6 +40,7 @@
* <p>
* Implementations should only add the names of attributes found in the LDAP
* entry directly associated with the resource.
+ *
* @param jsonAttribute
* The name of the resource attribute requested by the client.
* @param ldapAttributes
@@ -56,10 +59,13 @@
* requests.
*
* @param c
+ * The server context.
* @param e
+ * The LDAP entry to be converted to JSON.
* @param h
+ * The result handler.
*/
- void toJson(Context c, Entry e, AttributeMapperCompletionHandler<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,
@@ -70,10 +76,13 @@
* requests.
*
* @param c
+ * The server context.
* @param v
+ * The JSON value to be converted to LDAP attributes.
* @param h
+ * The result handler.
*/
- void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h);
+ void toLDAP(ServerContext c, JsonValue v, ResultHandler<List<Attribute>> h);
// TODO: methods for obtaining schema information (e.g. name, description,
// type information).
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java
deleted file mode 100644
index a6e92c9..0000000
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java
+++ /dev/null
@@ -1,29 +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 Copyrighted [year] [name of copyright owner]".
- *
- * Copyright 2012 ForgeRock AS. All rights reserved.
- */
-
-package org.forgerock.opendj.rest2ldap;
-
-import org.forgerock.resource.exception.ResourceException;
-
-/**
- *
- */
-public interface AttributeMapperCompletionHandler<T> {
-
- void onSuccess(T result);
-
- void onFailure(ResourceException e);
-}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java
index 3120ffc..0babf85 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ComplexAttributeMapper.java
@@ -25,19 +25,21 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+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;
-import org.forgerock.resource.exception.ResourceException;
-import org.forgerock.resource.provider.Context;
/**
- *
+ * An attribute mapper which will wrap the results of the provided mapper as a
+ * complex JSON object.
*/
public class ComplexAttributeMapper implements AttributeMapper {
- private final String normalizedJsonAttributeName;
private final String jsonAttributeName;
private final AttributeMapper mapper;
+ private final String normalizedJsonAttributeName;
/**
* Creates a new complex attribute mapper which will wrap the results of the
@@ -49,7 +51,7 @@
* The mapper which should be used to provide the contents of the
* complex attribute.
*/
- public ComplexAttributeMapper(String jsonAttributeName, AttributeMapper mapper) {
+ public ComplexAttributeMapper(final String jsonAttributeName, final AttributeMapper mapper) {
this.jsonAttributeName = jsonAttributeName;
this.mapper = mapper;
this.normalizedJsonAttributeName = toLowerCase(jsonAttributeName);
@@ -58,9 +60,9 @@
/**
* {@inheritDoc}
*/
- public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) {
+ public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
if (attributeMatchesPointer(jsonAttribute)) {
- JsonPointer relativePointer = jsonAttribute.relativePointer();
+ final JsonPointer relativePointer = jsonAttribute.relativePointer();
mapper.getLDAPAttributes(relativePointer, ldapAttributes);
}
}
@@ -68,33 +70,33 @@
/**
* {@inheritDoc}
*/
- public void toJson(Context c, Entry e,
- final AttributeMapperCompletionHandler<Map<String, Object>> h) {
- AttributeMapperCompletionHandler<Map<String, Object>> wrapper =
- new AttributeMapperCompletionHandler<Map<String, Object>>() {
+ 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>>() {
- public void onSuccess(Map<String, Object> result) {
- Map<String, Object> complexResult =
- Collections.singletonMap(jsonAttributeName, (Object) result);
- h.onSuccess(complexResult);
- }
+ public void handleError(final ResourceException e) {
+ h.handleError(e);
+ }
- public void onFailure(ResourceException e) {
- h.onFailure(e);
- }
- };
+ 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);
}
/**
* {@inheritDoc}
*/
- public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
+ public void toLDAP(final ServerContext c, final JsonValue v,
+ final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
- private boolean attributeMatchesPointer(JsonPointer resourceAttribute) {
+ private boolean attributeMatchesPointer(final JsonPointer resourceAttribute) {
return resourceAttribute.isEmpty()
|| toLowerCase(resourceAttribute.get(0)).equals(normalizedJsonAttributeName);
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
index 2d53f3e..bef1872 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
@@ -27,26 +27,34 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+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;
-import org.forgerock.resource.exception.ResourceException;
-import org.forgerock.resource.provider.Context;
/**
- *
+ * A collection of one or more attribute mappers whose content will be combined
+ * into a single JSON array.
*/
public final class CompositeAttributeMapper implements AttributeMapper {
private final List<AttributeMapper> attributeMappers = new LinkedList<AttributeMapper>();
/**
* Creates a new composite attribute mapper.
- *
*/
public CompositeAttributeMapper() {
// No implementation required.
}
- public CompositeAttributeMapper addMapper(AttributeMapper mapper) {
+ /**
+ * 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;
}
@@ -54,8 +62,8 @@
/**
* {@inheritDoc}
*/
- public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) {
- for (AttributeMapper attribute : attributeMappers) {
+ public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
+ for (final AttributeMapper attribute : attributeMappers) {
attribute.getLDAPAttributes(jsonAttribute, ldapAttributes);
}
}
@@ -63,45 +71,44 @@
/**
* {@inheritDoc}
*/
- public void toJson(Context c, Entry e,
- final AttributeMapperCompletionHandler<Map<String, Object>> h) {
- AttributeMapperCompletionHandler<Map<String, Object>> resultAccumulater =
- new AttributeMapperCompletionHandler<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());
+ 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());
- public void onFailure(ResourceException e) {
- // Ensure that handler is only invoked once.
- if (latch.getAndSet(0) > 0) {
- h.onFailure(e);
- }
+ public void handleError(final ResourceException e) {
+ // Ensure that handler is only invoked once.
+ if (latch.getAndSet(0) > 0) {
+ h.handleError(e);
+ }
+ }
+
+ public void handleResult(final Map<String, Object> result) {
+ synchronized (this) {
+ results.add(result);
+ }
+ if (latch.decrementAndGet() == 0) {
+ final Map<String, Object> mergeResult;
+ switch (results.size()) {
+ case 0:
+ mergeResult = Collections.<String, Object> emptyMap();
+ break;
+ case 1:
+ mergeResult = results.get(0);
+ break;
+ default:
+ mergeResult = new LinkedHashMap<String, Object>();
+ mergeJsonValues(results, mergeResult);
+ break;
}
+ h.handleResult(mergeResult);
+ }
+ }
+ };
- public void onSuccess(Map<String, Object> result) {
- synchronized (this) {
- results.add(result);
- }
- if (latch.decrementAndGet() == 0) {
- final Map<String, Object> mergeResult;
- switch (results.size()) {
- case 0:
- mergeResult = Collections.<String, Object> emptyMap();
- break;
- case 1:
- mergeResult = results.get(0);
- break;
- default:
- mergeResult = new LinkedHashMap<String, Object>();
- mergeJsonValues(results, mergeResult);
- break;
- }
- h.onSuccess(mergeResult);
- }
- }
- };
-
- for (AttributeMapper mapper : attributeMappers) {
+ for (final AttributeMapper mapper : attributeMappers) {
mapper.toJson(c, e, resultAccumulater);
}
}
@@ -109,27 +116,13 @@
/**
* {@inheritDoc}
*/
- public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
+ public void toLDAP(final ServerContext c, final JsonValue v,
+ final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
/**
- * Merge the provided list of JSON values into a single value.
- *
- * @param srcValues
- * The source values.
- * @param dstValue
- * The destination value, into which which the values should be
- * merged.
- */
- private void mergeJsonValues(List<Map<String, Object>> srcValues, Map<String, Object> dstValue) {
- for (Map<String, Object> value : srcValues) {
- mergeJsonValue(value, dstValue);
- }
- }
-
- /**
* Merge one JSON value into another.
*
* @param srcValue
@@ -139,24 +132,25 @@
* merged.
*/
@SuppressWarnings("unchecked")
- private void mergeJsonValue(Map<String, Object> srcValue, Map<String, Object> dstValue) {
- for (Map.Entry<String, Object> record : srcValue.entrySet()) {
- String key = record.getKey();
- Object newValue = record.getValue();
+ private void mergeJsonValue(final Map<String, Object> srcValue,
+ final Map<String, Object> dstValue) {
+ for (final Map.Entry<String, Object> record : srcValue.entrySet()) {
+ final String key = record.getKey();
+ final Object newValue = record.getValue();
Object existingValue = dstValue.get(key);
if (existingValue == null) {
// Value is new, so just add it.
dstValue.put(key, newValue);
- } else if (existingValue instanceof Map && newValue instanceof Map) {
+ } else if ((existingValue instanceof Map) && (newValue instanceof Map)) {
// Merge two maps - create a new Map, in case the existing one
// is unmodifiable.
- existingValue =
- new LinkedHashMap<String, Object>((Map<String, Object>) existingValue);
+ existingValue = new LinkedHashMap<String, Object>(
+ (Map<String, Object>) existingValue);
mergeJsonValue((Map<String, Object>) newValue, (Map<String, Object>) existingValue);
- } else if (existingValue instanceof List && newValue instanceof List) {
+ } else if ((existingValue instanceof List) && (newValue instanceof List)) {
// Merge two lists- create a new List, in case the existing one
// is unmodifiable.
- List<Object> tmp = new ArrayList<Object>((List<Object>) existingValue);
+ final List<Object> tmp = new ArrayList<Object>((List<Object>) existingValue);
tmp.addAll((List<Object>) newValue);
existingValue = tmp;
}
@@ -165,4 +159,20 @@
dstValue.put(key, newValue);
}
}
+
+ /**
+ * Merge the provided list of JSON values into a single value.
+ *
+ * @param srcValues
+ * The source values.
+ * @param dstValue
+ * The destination value, into which which the values should be
+ * merged.
+ */
+ private void mergeJsonValues(final List<Map<String, Object>> srcValues,
+ final Map<String, Object> dstValue) {
+ for (final Map<String, Object> value : srcValues) {
+ mergeJsonValue(value, dstValue);
+ }
+ }
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java
index 2d29263..5a2b251 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ConstantAttributeMapper.java
@@ -23,12 +23,13 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.ResultHandler;
+import org.forgerock.json.resource.ServerContext;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.resource.provider.Context;
/**
- *
+ * An attribute mapper which maps a single JSON attribute to a fixed value.
*/
public class ConstantAttributeMapper implements AttributeMapper {
@@ -36,7 +37,7 @@
private final Object jsonAttributeValue;
/**
- * Creates a new constant attribute mapper which maps a single LDAP
+ * Creates a new constant attribute mapper which maps a single JSON
* attribute to a fixed value.
*
* @param attributeName
@@ -44,7 +45,7 @@
* @param attributeValue
* The value of the simple JSON attribute.
*/
- public ConstantAttributeMapper(String attributeName, Object attributeValue) {
+ public ConstantAttributeMapper(final String attributeName, final Object attributeValue) {
this.jsonAttributeName = attributeName;
this.jsonAttributeValue = attributeValue;
}
@@ -52,26 +53,27 @@
/**
* {@inheritDoc}
*/
- public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) {
+ public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
// Nothing to do.
}
/**
* {@inheritDoc}
*/
- public void toJson(Context c, Entry e,
- final AttributeMapperCompletionHandler<Map<String, Object>> h) {
+ 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???
- Map<String, Object> result =
- Collections.singletonMap(jsonAttributeName, jsonAttributeValue);
- h.onSuccess(result);
+ final Map<String, Object> result = Collections.singletonMap(jsonAttributeName,
+ jsonAttributeValue);
+ h.handleResult(result);
}
/**
* {@inheritDoc}
*/
- public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
+ public void toLDAP(final ServerContext c, final JsonValue v,
+ final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java
index 45f5ead..36e2c57 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DefaultAttributeMapper.java
@@ -27,47 +27,32 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.ResultHandler;
+import org.forgerock.json.resource.ServerContext;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.resource.provider.Context;
/**
*
*/
public final class DefaultAttributeMapper implements AttributeMapper {
+ private final Map<String, String> excludedAttributes = new LinkedHashMap<String, String>();
// All user attributes by default.
private final Map<String, String> includedAttributes = new LinkedHashMap<String, String>();
- private final Map<String, String> excludedAttributes = new LinkedHashMap<String, String>();
public DefaultAttributeMapper() {
// No implementation required.
}
- public DefaultAttributeMapper includeAttribute(String... attributes) {
- for (String attribute : attributes) {
- includedAttributes.put(toLowerCase(attribute), attribute);
- }
- return this;
- }
-
- public DefaultAttributeMapper excludeAttribute(String... attributes) {
- for (String attribute : attributes) {
+ public DefaultAttributeMapper excludeAttribute(final String... attributes) {
+ for (final String attribute : attributes) {
excludedAttributes.put(toLowerCase(attribute), attribute);
}
return this;
}
- public void getLDAPAttributes(Set<String> ldapAttributes) {
- if (!includedAttributes.isEmpty()) {
- ldapAttributes.addAll(includedAttributes.values());
- } else {
- // All user attributes.
- ldapAttributes.add("*");
- }
- }
-
- public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) {
+ public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
switch (jsonAttribute.size()) {
case 0:
// Requested everything.
@@ -79,7 +64,7 @@
}
break;
default:
- String name = jsonAttribute.get(0);
+ final String name = jsonAttribute.get(0);
if (isIncludedAttribute(name)) {
ldapAttributes.add(name);
}
@@ -87,19 +72,41 @@
}
}
- public void toJson(Context c, Entry e, AttributeMapperCompletionHandler<Map<String, Object>> h) {
- Map<String, Object> result = new LinkedHashMap<String, Object>(e.getAttributeCount());
- for (Attribute a : e.getAllAttributes()) {
- String name = getAttributeName(a);
+ public void getLDAPAttributes(final Set<String> ldapAttributes) {
+ if (!includedAttributes.isEmpty()) {
+ ldapAttributes.addAll(includedAttributes.values());
+ } else {
+ // All user attributes.
+ ldapAttributes.add("*");
+ }
+ }
+
+ public DefaultAttributeMapper includeAttribute(final String... attributes) {
+ for (final String attribute : attributes) {
+ includedAttributes.put(toLowerCase(attribute), attribute);
+ }
+ return this;
+ }
+
+ 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()) {
+ final String name = getAttributeName(a);
if (isIncludedAttribute(name)) {
result.put(name, attributeToJson(a));
}
}
- h.onSuccess(result);
+ h.handleResult(result);
}
- private boolean isIncludedAttribute(String name) {
- String lowerName = toLowerCase(name);
+ public void toLDAP(final ServerContext c, final JsonValue v,
+ final ResultHandler<List<Attribute>> h) {
+ // TODO:
+ }
+
+ private boolean isIncludedAttribute(final String name) {
+ final String lowerName = toLowerCase(name);
// Ignore the requested attribute if it has been excluded.
if (excludedAttributes.containsKey(lowerName)) {
@@ -113,8 +120,4 @@
return false;
}
-
- public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
- // TODO:
- }
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
index b2ff886..a40b006 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
@@ -18,6 +18,7 @@
import java.util.Collection;
+import org.forgerock.json.resource.Context;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.DN;
@@ -32,25 +33,15 @@
import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.responses.SearchResultReference;
-import org.forgerock.resource.provider.Context;
/**
*
*/
public final class EntryContainer {
- // FIXME: make this configurable, also allow use of DN.
- private static final String UUID_ATTRIBUTE = "entryUUID";
-
- // FIXME: make this configurable.
- private static final String ETAG_ATTRIBUTE = "etag";
-
- private final ConnectionFactory factory;
- private final DN baseDN;
-
private abstract class AbstractRequestCompletionHandler<R, H extends ResultHandler<? super R>>
implements ResultHandler<R> {
- final H resultHandler;
final Connection connection;
+ final H resultHandler;
AbstractRequestCompletionHandler(final Connection connection, final H resultHandler) {
this.connection = connection;
@@ -123,12 +114,32 @@
}
- public EntryContainer(DN baseDN, ConnectionFactory factory) {
+ // FIXME: make this configurable.
+ private static final String ETAG_ATTRIBUTE = "etag";
+
+ // FIXME: make this configurable, also allow use of DN.
+ private static final String UUID_ATTRIBUTE = "entryUUID";
+
+ private final DN baseDN;
+
+ private final ConnectionFactory factory;
+
+ public EntryContainer(final DN baseDN, final ConnectionFactory factory) {
this.baseDN = baseDN;
this.factory = factory;
}
- public void listEntries(final Context context, final SearchResultHandler handler) {
+ public String getEtagFromEntry(final Entry entry) {
+ return entry.parseAttribute(ETAG_ATTRIBUTE).asString();
+ }
+
+ public String getIDFromEntry(final Entry entry) {
+ return entry.parseAttribute(UUID_ATTRIBUTE).asString();
+ }
+
+ 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) {
@@ -136,9 +147,9 @@
public void handleResult(final Connection connection) {
final SearchRequestCompletionHandler innerHandler =
new SearchRequestCompletionHandler(connection, handler);
- SearchRequest request =
+ final SearchRequest request =
Requests.newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter
- .objectClassPresent(), UUID_ATTRIBUTE, ETAG_ATTRIBUTE);
+ .objectClassPresent(), tmp);
connection.searchAsync(request, null, innerHandler);
}
@@ -149,6 +160,7 @@
public void readEntry(final Context c, final String id, final Collection<String> attributes,
final ResultHandler<SearchResultEntry> handler) {
+ final String[] tmp = getSearchAttributes(attributes);
final ConnectionCompletionHandler<SearchResultEntry> outerHandler =
new ConnectionCompletionHandler<SearchResultEntry>(handler) {
@@ -156,13 +168,7 @@
public void handleResult(final Connection connection) {
final RequestCompletionHandler<SearchResultEntry> innerHandler =
new RequestCompletionHandler<SearchResultEntry>(connection, handler);
- // FIXME: who is responsible for adding the UUID and
- // etag attributes to this search?
- String[] tmp = attributes.toArray(new String[attributes.size() + 2]);
- tmp[tmp.length - 2] = UUID_ATTRIBUTE;
- tmp[tmp.length - 1] = ETAG_ATTRIBUTE;
-
- SearchRequest request =
+ final SearchRequest request =
Requests.newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter
.equality(UUID_ATTRIBUTE, id), tmp);
connection.searchSingleEntryAsync(request, innerHandler);
@@ -173,12 +179,13 @@
factory.getConnectionAsync(outerHandler);
}
- public String getIDFromEntry(final Entry entry) {
- return entry.parseAttribute(UUID_ATTRIBUTE).asString();
- }
-
- public String getEtagFromEntry(final Entry entry) {
- return entry.parseAttribute(ETAG_ATTRIBUTE).asString();
+ 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;
}
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java
deleted file mode 100644
index e807869..0000000
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java
+++ /dev/null
@@ -1,104 +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 Copyrighted [year] [name of copyright owner]".
- *
- * Copyright © 2012 ForgeRock AS. All rights reserved.
- */
-
-package org.forgerock.opendj.rest2ldap;
-
-import org.forgerock.json.resource.restlet.JsonResourceRestlet;
-import org.forgerock.opendj.ldap.ConnectionFactory;
-import org.forgerock.opendj.ldap.Connections;
-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;
-import org.forgerock.resource.framework.JsonResourceProvider;
-import org.forgerock.resource.framework.impl.ResourceInvoker;
-import org.restlet.Application;
-import org.restlet.Component;
-import org.restlet.Restlet;
-import org.restlet.data.Protocol;
-import org.restlet.routing.Router;
-import org.restlet.routing.Template;
-
-/**
- * Example
- */
-public class Example {
-
- private Application application = new Application();
- private final Router router = new Router();
-
- private void bindJsonResource(JsonResourceProvider resource, String path) {
- Restlet restlet = new JsonResourceRestlet(resource);
- restlet.setContext(application.getContext());
- router.attach(path, restlet, Template.MODE_EQUALS);
- router.attach(path + (path.equals("/") ? "" : "/"), restlet, Template.MODE_STARTS_WITH);
- }
-
- public void start() throws Exception {
- // All LDAP resources will use this connection factory.
- ConnectionFactory factory =
- Connections.newAuthenticatedConnectionFactory(new LDAPConnectionFactory(
- "localhost", 1389), Requests.newSimpleBindRequest("cn=directory manager",
- "password".toCharArray()));
-
- // Create two entry containers whose members reference each other.
- EntryContainer userContainer =
- new EntryContainer(DN.valueOf("ou=people,dc=example,dc=com"), factory);
- EntryContainer groupContainer =
- new EntryContainer(DN.valueOf("ou=groups,dc=example,dc=com"), factory);
-
- // Create user resource.
- AttributeMapper userMapper =
- new CompositeAttributeMapper().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)).addMapper(
- new SimpleAttributeMapper("emailAddress", "mail")
- .forceSingleValued(true))));
- LDAPResource userResource = new LDAPResource(userContainer, userMapper);
- ResourceInvoker userResourceInvoker = new ResourceInvoker();
- userResourceInvoker.resource = userResource; // FIXME: Yuk!
- bindJsonResource(userResourceInvoker, "/users");
-
- // Create group resource.
- AttributeMapper groupMapper =
- new DefaultAttributeMapper().includeAttribute("cn", "ou", "description",
- "uniquemember");
- LDAPResource groupResource = new LDAPResource(groupContainer, groupMapper);
- ResourceInvoker groupResourceInvoker = new ResourceInvoker();
- groupResourceInvoker.resource = groupResource; // FIXME: Yuk!
- bindJsonResource(groupResourceInvoker, "/groups");
-
- // Configure and start the application.
- application.getTunnelService().setQueryTunnel(false);
- application.setInboundRoot(router);
- Component component = new Component();
- component.getServers().add(Protocol.HTTP, 8080);
- component.getDefaultHost().attach("", application);
- component.start();
- }
-
- public static void main(String[] args) throws Exception {
- Example instance = new Example();
- instance.start();
- }
-}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
new file mode 100644
index 0000000..d5b2f67
--- /dev/null
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
@@ -0,0 +1,290 @@
+/*
+ * 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 Copyrighted [year] [name of copyright owner]".
+ *
+ * Copyright 2012 ForgeRock AS. All rights reserved.
+ */
+
+package org.forgerock.opendj.rest2ldap;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.forgerock.json.fluent.JsonPointer;
+import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.*;
+import org.forgerock.opendj.ldap.AssertionFailureException;
+import org.forgerock.opendj.ldap.AuthenticationException;
+import org.forgerock.opendj.ldap.AuthorizationException;
+import org.forgerock.opendj.ldap.ConnectionException;
+import org.forgerock.opendj.ldap.EntryNotFoundException;
+import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.MultipleEntriesFoundException;
+import org.forgerock.opendj.ldap.SearchResultHandler;
+import org.forgerock.opendj.ldap.TimeoutResultException;
+import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.opendj.ldap.responses.SearchResultReference;
+
+/**
+ *
+ */
+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);
+
+ /**
+ * Creates a new LDAP resource.
+ */
+ public LDAPCollectionResourceProvider(final EntryContainer container, final AttributeMapper mapper) {
+ this.entryContainer = container;
+ this.attributeMapper = mapper;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void actionCollection(ServerContext context, ActionRequest request,
+ ResultHandler<JsonValue> handler) {
+ handler.handleError(new NotSupportedException("Not yet implemented"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void actionInstance(ServerContext context, String resourceId, ActionRequest request,
+ ResultHandler<JsonValue> handler) {
+ handler.handleError(new NotSupportedException("Not yet implemented"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void createInstance(ServerContext context, CreateRequest request,
+ ResultHandler<Resource> handler) {
+ handler.handleError(new NotSupportedException("Not yet implemented"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void deleteInstance(ServerContext context, String resourceId, DeleteRequest request,
+ ResultHandler<Resource> handler) {
+ handler.handleError(new NotSupportedException("Not yet implemented"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void patchInstance(ServerContext context, String resourceId, PatchRequest request,
+ 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 Set<JsonPointer> requestedAttributes = new LinkedHashSet<JsonPointer>();
+ final Collection<String> requestedLDAPAttributes = getRequestedLDAPAttributes(requestedAttributes);
+
+ // List the entries.
+ final SearchResultHandler searchHandler = new SearchResultHandler() {
+ private final AtomicInteger pendingResourceCount = new AtomicInteger();
+ private final AtomicReference<ResourceException> pendingResult = new AtomicReference<ResourceException>();
+ private final AtomicBoolean resultSent = new AtomicBoolean();
+
+ /*
+ * Close out the query result set if there are no more pending
+ * resources and the LDAP result has been received.
+ */
+ private void completeIfNecessary() {
+ if (pendingResourceCount.get() == 0) {
+ final ResourceException result = pendingResult.get();
+ if (result != null && resultSent.compareAndSet(false, true)) {
+ if (result == SUCCESS) {
+ handler.handleResult(null);
+ } else {
+ handler.handleError(result);
+ }
+ }
+ }
+ }
+
+ 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);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void readInstance(final ServerContext context, final String resourceId,
+ 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>() {
+ public void handleErrorResult(final ErrorResultException error) {
+ handler.handleError(adaptErrorResult(error));
+ }
+
+ public void handleResult(final SearchResultEntry entry) {
+ final String revision = entryContainer.getEtagFromEntry(entry);
+ final ResultHandler<Map<String, Object>> mapHandler = new ResultHandler<Map<String, Object>>() {
+ public void handleError(final ResourceException e) {
+ handler.handleError(e);
+ }
+
+ public void handleResult(final Map<String, Object> result) {
+ Resource resource = new Resource(resourceId, revision,
+ new JsonValue(result));
+ handler.handleResult(resource);
+ }
+ };
+ attributeMapper.toJson(context, entry, mapHandler);
+ }
+ };
+ entryContainer.readEntry(context, resourceId, requestedLDAPAttributes, searchHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateInstance(ServerContext context, String resourceId, UpdateRequest request,
+ ResultHandler<Resource> handler) {
+ handler.handleError(new NotSupportedException("Not yet implemented"));
+ }
+
+ /**
+ * Adapts an LDAP result code to a resource exception.
+ *
+ * @param error
+ * The LDAP error that should be adapted.
+ * @return The equivalent resource exception.
+ */
+ private ResourceException adaptErrorResult(final ErrorResultException error) {
+ int resourceResultCode;
+ try {
+ throw error;
+ } catch (final AssertionFailureException e) {
+ resourceResultCode = ResourceException.VERSION_MISMATCH;
+ } catch (final AuthenticationException e) {
+ resourceResultCode = 401;
+ } catch (final AuthorizationException e) {
+ resourceResultCode = ResourceException.FORBIDDEN;
+ } catch (final ConnectionException e) {
+ resourceResultCode = ResourceException.UNAVAILABLE;
+ } catch (final EntryNotFoundException e) {
+ resourceResultCode = ResourceException.NOT_FOUND;
+ } catch (final MultipleEntriesFoundException e) {
+ resourceResultCode = ResourceException.INTERNAL_ERROR;
+ } catch (final TimeoutResultException e) {
+ resourceResultCode = 408;
+ } catch (final ErrorResultException e) {
+ resourceResultCode = ResourceException.INTERNAL_ERROR;
+ }
+ return ResourceException.getException(resourceResultCode, null, error.getMessage(), error);
+ }
+
+ /**
+ * Determines the set of LDAP attributes to request in an LDAP read (search,
+ * post-read), based on the provided set of JSON pointers.
+ *
+ * @param requestedAttributes
+ * The set of resource attributes to be read.
+ * @return The set of LDAP attributes associated with the resource
+ * attributes.
+ */
+ private Collection<String> getRequestedLDAPAttributes(final Set<JsonPointer> requestedAttributes) {
+ final Set<String> requestedLDAPAttributes;
+ if (requestedAttributes.isEmpty()) {
+ // Full read.
+ requestedLDAPAttributes = new LinkedHashSet<String>();
+ attributeMapper.getLDAPAttributes(new JsonPointer(), requestedLDAPAttributes);
+ } else {
+ // Partial read.
+ requestedLDAPAttributes = new LinkedHashSet<String>(requestedAttributes.size());
+ for (final JsonPointer requestedAttribute : requestedAttributes) {
+ attributeMapper.getLDAPAttributes(requestedAttribute, requestedLDAPAttributes);
+ }
+ }
+ return requestedLDAPAttributes;
+ }
+
+}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java
deleted file mode 100644
index 890fb00..0000000
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java
+++ /dev/null
@@ -1,244 +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 Copyrighted [year] [name of copyright owner]".
- *
- * Copyright 2012 ForgeRock AS. All rights reserved.
- */
-
-package org.forgerock.opendj.rest2ldap;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-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.opendj.ldap.AssertionFailureException;
-import org.forgerock.opendj.ldap.AuthenticationException;
-import org.forgerock.opendj.ldap.AuthorizationException;
-import org.forgerock.opendj.ldap.ConnectionException;
-import org.forgerock.opendj.ldap.EntryNotFoundException;
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.MultipleEntriesFoundException;
-import org.forgerock.opendj.ldap.ResultHandler;
-import org.forgerock.opendj.ldap.SearchResultHandler;
-import org.forgerock.opendj.ldap.TimeoutResultException;
-import org.forgerock.opendj.ldap.responses.Result;
-import org.forgerock.opendj.ldap.responses.SearchResultEntry;
-import org.forgerock.opendj.ldap.responses.SearchResultReference;
-import org.forgerock.resource.exception.NotSupportedException;
-import org.forgerock.resource.exception.ResourceException;
-import org.forgerock.resource.provider.ActionRequest;
-import org.forgerock.resource.provider.ActionResultHandler;
-import org.forgerock.resource.provider.Context;
-import org.forgerock.resource.provider.CreateRequest;
-import org.forgerock.resource.provider.CreateResultHandler;
-import org.forgerock.resource.provider.DeleteRequest;
-import org.forgerock.resource.provider.DeleteResultHandler;
-import org.forgerock.resource.provider.PatchRequest;
-import org.forgerock.resource.provider.PatchResultHandler;
-import org.forgerock.resource.provider.QueryRequest;
-import org.forgerock.resource.provider.QueryResultHandler;
-import org.forgerock.resource.provider.ReadRequest;
-import org.forgerock.resource.provider.ReadResultHandler;
-import org.forgerock.resource.provider.Resource;
-import org.forgerock.resource.provider.UpdateRequest;
-import org.forgerock.resource.provider.UpdateResultHandler;
-
-/**
- *
- */
-public class LDAPResource implements Resource {
- private final EntryContainer entryContainer;
- private final AttributeMapper attributeMapper;
-
- /**
- * Creates a new LDAP resource.
- */
- public LDAPResource(final EntryContainer container, final AttributeMapper mapper) {
- this.entryContainer = container;
- this.attributeMapper = mapper;
- }
-
- /**
- * {@inheritDoc}
- */
- public void action(final ActionRequest request, final Context context,
- final ActionResultHandler out) {
- out.setFailure(new NotSupportedException("Not yet implemented"));
- }
-
- /**
- * {@inheritDoc}
- */
- public void create(final CreateRequest request, final Context context,
- final CreateResultHandler out) {
- out.setFailure(new NotSupportedException("Not yet implemented"));
- }
-
- /**
- * {@inheritDoc}
- */
- public void delete(final DeleteRequest request, final Context context,
- final DeleteResultHandler out) {
- out.setFailure(new NotSupportedException("Not yet implemented"));
- }
-
- /**
- * {@inheritDoc}
- */
- public void patch(final PatchRequest request, final Context context,
- final PatchResultHandler out) {
- out.setFailure(new NotSupportedException("Not yet implemented"));
- }
-
- /**
- * {@inheritDoc}
- */
- public void query(final QueryRequest request, final Context context,
- final QueryResultHandler out) {
- out.setFailure(new NotSupportedException("Not yet implemented"));
- }
-
- /**
- * {@inheritDoc}
- */
- public void read(final ReadRequest request, final Context context, final ReadResultHandler out) {
- final String id = request.getId();
- if (id == null) {
- // List the entries.
- final SearchResultHandler handler = new SearchResultHandler() {
- private final List<String> resourceIDs = new ArrayList<String>();
-
- public boolean handleEntry(final SearchResultEntry entry) {
- // TODO: should the resource or the container define the ID
- // mapping?
- resourceIDs.add(entryContainer.getIDFromEntry(entry));
- return true;
- }
-
- public void handleErrorResult(final ErrorResultException error) {
- out.setFailure(adaptErrorResult(error));
- }
-
- 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) {
- out.setResult(id, null, new JsonValue(resourceIDs));
- }
- };
- entryContainer.listEntries(context, handler);
- } else {
- // Read a single entry.
-
- // 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 ResultHandler<SearchResultEntry> handler =
- new ResultHandler<SearchResultEntry>() {
- public void handleErrorResult(final ErrorResultException error) {
- out.setFailure(adaptErrorResult(error));
- }
-
- public void handleResult(final SearchResultEntry entry) {
- final String revision = entryContainer.getEtagFromEntry(entry);
- final AttributeMapperCompletionHandler<Map<String, Object>> mapHandler =
- new AttributeMapperCompletionHandler<Map<String, Object>>() {
- public void onFailure(final ResourceException e) {
- out.setFailure(e);
- }
-
- public void onSuccess(final Map<String, Object> result) {
- out.setResult(id, revision, new JsonValue(result));
- }
- };
- attributeMapper.toJson(context, entry, mapHandler);
- }
- };
- entryContainer.readEntry(context, id, requestedLDAPAttributes, handler);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void update(final UpdateRequest request, final Context context,
- final UpdateResultHandler out) {
- out.setFailure(new NotSupportedException("Not yet implemented"));
- }
-
- /**
- * Adapts an LDAP result code to a resource exception.
- *
- * @param error
- * The LDAP error that should be adapted.
- * @return The equivalent resource exception.
- */
- private ResourceException adaptErrorResult(final ErrorResultException error) {
- int resourceResultCode;
- try {
- throw error;
- } catch (AssertionFailureException e) {
- resourceResultCode = ResourceException.VERSION_MISMATCH;
- } catch (AuthenticationException e) {
- resourceResultCode = 401;
- } catch (AuthorizationException e) {
- resourceResultCode = ResourceException.FORBIDDEN;
- } catch (ConnectionException e) {
- resourceResultCode = ResourceException.UNAVAILABLE;
- } catch (EntryNotFoundException e) {
- resourceResultCode = ResourceException.NOT_FOUND;
- } catch (MultipleEntriesFoundException e) {
- resourceResultCode = ResourceException.INTERNAL_ERROR;
- } catch (TimeoutResultException e) {
- resourceResultCode = 408;
- } catch (ErrorResultException e) {
- resourceResultCode = ResourceException.INTERNAL_ERROR;
- }
- return ResourceException.getException(resourceResultCode, null, error.getMessage(), error);
- }
-
- /**
- * Determines the set of LDAP attributes to request in an LDAP read (search,
- * post-read), based on the provided set of JSON pointers.
- *
- * @param requestedAttributes
- * The set of resource attributes to be read.
- * @return The set of LDAP attributes associated with the resource
- * attributes.
- */
- private Collection<String> getRequestedLDAPAttributes(final Set<JsonPointer> requestedAttributes) {
- final Set<String> requestedLDAPAttributes;
- if (requestedAttributes.isEmpty()) {
- // Full read.
- requestedLDAPAttributes = new LinkedHashSet<String>();
- attributeMapper.getLDAPAttributes(new JsonPointer(), requestedLDAPAttributes);
- } else {
- // Partial read.
- requestedLDAPAttributes = new LinkedHashSet<String>(requestedAttributes.size());
- for (final JsonPointer requestedAttribute : requestedAttributes) {
- attributeMapper.getLDAPAttributes(requestedAttribute, requestedLDAPAttributes);
- }
- }
- return requestedLDAPAttributes;
- }
-
-}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
index 9e1dcac..a4deee4 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
@@ -22,9 +22,10 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.ResultHandler;
+import org.forgerock.json.resource.ServerContext;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.resource.provider.Context;
/**
*
@@ -36,7 +37,7 @@
/**
* {@inheritDoc}
*/
- public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) {
+ public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
// TODO Auto-generated method stub
}
@@ -44,7 +45,7 @@
/**
* {@inheritDoc}
*/
- public void toJson(Context c, Entry e, AttributeMapperCompletionHandler<Map<String, Object>> h) {
+ public void toJson(final ServerContext c, final Entry e, final ResultHandler<Map<String, Object>> h) {
// TODO Auto-generated method stub
}
@@ -52,7 +53,7 @@
/**
* {@inheritDoc}
*/
- public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
+ public void toLDAP(final ServerContext c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
// TODO Auto-generated method stub
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
index 0c92b63..214950b 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
@@ -26,26 +26,27 @@
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.ResultHandler;
+import org.forgerock.json.resource.ServerContext;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.Function;
import org.forgerock.opendj.ldap.Functions;
-import org.forgerock.resource.provider.Context;
/**
*
*/
public class SimpleAttributeMapper implements AttributeMapper {
- private final String ldapAttributeName;
- private final String jsonAttributeName;
- private final String normalizedJsonAttributeName;
-
- private boolean forceSingleValued = false;
- private Object defaultValue = null;
- private boolean isReadOnly = false;
private Function<ByteString, ?, Void> decoder = null;
+ private Object defaultValue = null;
+ private boolean forceSingleValued = false;
+
+ private boolean isReadOnly = false;
+ private final String jsonAttributeName;
+ private final String ldapAttributeName;
+ private final String normalizedJsonAttributeName;
/**
* Creates a new simple attribute mapper which maps a single LDAP attribute
@@ -54,7 +55,7 @@
* @param attributeName
* The name of the simple JSON and LDAP attribute.
*/
- public SimpleAttributeMapper(String attributeName) {
+ public SimpleAttributeMapper(final String attributeName) {
this(attributeName, attributeName);
}
@@ -67,54 +68,38 @@
* @param ldapAttributeName
* The name of the LDAP attribute.
*/
- public SimpleAttributeMapper(String jsonAttributeName, String ldapAttributeName) {
+ public SimpleAttributeMapper(final String jsonAttributeName, final String ldapAttributeName) {
this.jsonAttributeName = jsonAttributeName;
this.ldapAttributeName = ldapAttributeName;
this.normalizedJsonAttributeName = toLowerCase(jsonAttributeName);
}
- public SimpleAttributeMapper withDefaultValue(Object defaultValue) {
- this.defaultValue = defaultValue;
- return this;
- }
-
- public SimpleAttributeMapper isReadOnly(boolean readOnly) {
- this.isReadOnly = readOnly;
- return this;
- }
-
- public SimpleAttributeMapper forceSingleValued(boolean singleValued) {
+ public SimpleAttributeMapper forceSingleValued(final boolean singleValued) {
this.forceSingleValued = singleValued;
return this;
}
- public SimpleAttributeMapper withDecoder(Function<ByteString, ?, Void> f) {
- this.decoder = f;
- return this;
- }
-
/**
* {@inheritDoc}
*/
- public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) {
+ public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
if (attributeMatchesPointer(jsonAttribute)) {
ldapAttributes.add(ldapAttributeName);
}
}
- private boolean attributeMatchesPointer(JsonPointer resourceAttribute) {
- return resourceAttribute.isEmpty()
- || toLowerCase(resourceAttribute.get(0)).equals(normalizedJsonAttributeName);
+ public SimpleAttributeMapper isReadOnly(final boolean readOnly) {
+ this.isReadOnly = readOnly;
+ return this;
}
/**
* {@inheritDoc}
*/
- public void toJson(Context c, Entry e,
- final AttributeMapperCompletionHandler<Map<String, Object>> h) {
- Attribute a = e.getAttribute(ldapAttributeName);
+ public void toJson(final ServerContext c, final Entry e, final ResultHandler<Map<String, Object>> h) {
+ final Attribute a = e.getAttribute(ldapAttributeName);
if (a != null) {
- Function<ByteString, ?, Void> f =
+ final Function<ByteString, ?, Void> f =
decoder == null ? Functions.fixedFunction(byteStringToJson(), a) : decoder;
final Object value;
if (forceSingleValued || a.getAttributeDescription().getAttributeType().isSingleValue()) {
@@ -122,17 +107,32 @@
} else {
value = a.parse().asSetOf(f, defaultValue);
}
- Map<String, Object> result = Collections.singletonMap(jsonAttributeName, value);
- h.onSuccess(result);
+ final Map<String, Object> result = Collections.singletonMap(jsonAttributeName, value);
+ h.handleResult(result);
}
}
/**
* {@inheritDoc}
*/
- public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
+ 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);
+ }
+
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java
new file mode 100644
index 0000000..58bdc72
--- /dev/null
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubContainerAttributeMapper.java
@@ -0,0 +1,61 @@
+/*
+ * 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 Copyrighted [year] [name of copyright owner]".
+ *
+ * Copyright 2012 ForgeRock AS. All rights reserved.
+ */
+
+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.json.resource.ServerContext;
+import org.forgerock.opendj.ldap.Attribute;
+import org.forgerock.opendj.ldap.Entry;
+
+/**
+ *
+ */
+public class SubContainerAttributeMapper implements AttributeMapper {
+
+ // private final EntryContainer referencedContainer;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void toJson(final ServerContext c, final Entry e, final ResultHandler<Map<String, Object>> h) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void toLDAP(final ServerContext c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
index 2446095..df1bb12 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
@@ -41,7 +41,8 @@
private static final Function<ByteString, Object, Attribute> BYTESTRING_TO_JSON =
new Function<ByteString, Object, Attribute>() {
public Object apply(final ByteString value, final Attribute a) {
- Syntax syntax = a.getAttributeDescription().getAttributeType().getSyntax();
+ final Syntax syntax =
+ a.getAttributeDescription().getAttributeType().getSyntax();
if (syntax.equals(getBooleanSyntax())) {
return Functions.byteStringToBoolean().apply(value, null);
} else if (syntax.equals(getIntegerSyntax())) {
@@ -58,39 +59,17 @@
}
};
- // Prevent instantiation.
- private Utils() {
- // No implementation required.
- }
-
- private static <T> List<T> asList(Collection<T> c) {
- if (c instanceof List) {
- return (List<T>) c;
- } else {
- List<T> result = new ArrayList<T>(c.size());
- result.addAll(c);
- return result;
- }
+ 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();
+ return isSingleValued ? a.parse().as(f) : asList(a.parse().asSetOf(f));
}
static Function<ByteString, Object, Attribute> byteStringToJson() {
return BYTESTRING_TO_JSON;
}
- static Object attributeToJson(Attribute a) {
- Function<ByteString, Object, Void> f = Functions.fixedFunction(BYTESTRING_TO_JSON, a);
- boolean isSingleValued = a.getAttributeDescription().getAttributeType().isSingleValue();
- return isSingleValued ? a.parse().as(f) : asList(a.parse().asSetOf(f));
- }
-
- static String getAttributeName(Attribute a) {
- return a.getAttributeDescription().withoutOption("binary").toString();
- }
-
- static String toLowerCase(String s) {
- return s != null ? s.toLowerCase(Locale.ENGLISH) : null;
- }
-
static <T> T ensureNotNull(final T object) {
if (object == null) {
throw new NullPointerException();
@@ -105,4 +84,25 @@
return object;
}
+ static String getAttributeName(final Attribute a) {
+ return a.getAttributeDescription().withoutOption("binary").toString();
+ }
+
+ static String toLowerCase(final String s) {
+ return s != null ? s.toLowerCase(Locale.ENGLISH) : null;
+ }
+
+ private static <T> List<T> asList(final Collection<T> c) {
+ if (c instanceof List) {
+ return (List<T>) c;
+ } else {
+ return new ArrayList<T>(c);
+ }
+ }
+
+ // Prevent instantiation.
+ private Utils() {
+ // No implementation required.
+ }
+
}
diff --git a/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java b/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
new file mode 100644
index 0000000..ccd5a03
--- /dev/null
+++ b/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
@@ -0,0 +1,105 @@
+/*
+ * 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 Copyrighted [year] [name of copyright owner]".
+ *
+ * Copyright © 2012 ForgeRock AS. All rights reserved.
+ */
+
+package org.forgerock.opendj.rest2ldap;
+
+import static org.forgerock.json.resource.Resources.newInternalConnectionFactory;
+import static org.forgerock.opendj.ldap.Connections.newAuthenticatedConnectionFactory;
+
+import java.util.logging.Logger;
+
+import org.forgerock.json.resource.Router;
+import org.forgerock.json.resource.RoutingMode;
+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;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.servlet.ServletRegistration;
+import org.glassfish.grizzly.servlet.WebappContext;
+
+/**
+ * Example
+ */
+public class Example {
+
+ private static final Logger LOGGER = Logger.getLogger(Example.class.getName());
+ private static final int PORT = 18890;
+
+ public static void main(final String[] args) throws Exception {
+ // All LDAP resources will use this connection factory.
+ final ConnectionFactory ldapFactory = newAuthenticatedConnectionFactory(
+ new LDAPConnectionFactory("localhost", 1389), Requests.newSimpleBindRequest(
+ "cn=directory manager", "password".toCharArray()));
+
+ // Create two entry containers whose members reference each other.
+ final EntryContainer userContainer = new EntryContainer(DN
+ .valueOf("ou=people,dc=example,dc=com"), ldapFactory);
+ final EntryContainer groupContainer = new EntryContainer(DN
+ .valueOf("ou=groups,dc=example,dc=com"), ldapFactory);
+
+ // Create user resource.
+ final AttributeMapper userMapper = new CompositeAttributeMapper().addMapper(
+ new SimpleAttributeMapper("id", "entryUUID").forceSingleValued(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))
+ .addMapper(
+ new SimpleAttributeMapper("emailAddress", "mail")
+ .forceSingleValued(true))));
+ final LDAPCollectionResourceProvider userResource = new LDAPCollectionResourceProvider(
+ userContainer, userMapper);
+
+ // Create group resource.
+ final AttributeMapper groupMapper = new DefaultAttributeMapper().includeAttribute("cn",
+ "ou", "description", "uniquemember");
+ final LDAPCollectionResourceProvider groupResource = new LDAPCollectionResourceProvider(
+ groupContainer, groupMapper);
+
+ // Create the router.
+ Router router = new Router();
+ router.addRoute(RoutingMode.EQUALS, "/users", userResource);
+ router.addRoute(RoutingMode.EQUALS, "/groups", groupResource);
+
+ final org.forgerock.json.resource.ConnectionFactory resourceFactory = newInternalConnectionFactory(router);
+ final HttpServer httpServer = HttpServer.createSimpleServer("./", PORT);
+ try {
+ final WebappContext ctx = new WebappContext("example", "/example");
+ final ServletRegistration reg = ctx.addServlet("managed", new HttpServlet(
+ resourceFactory));
+ reg.addMapping("/managed/*");
+ ctx.deploy(httpServer);
+
+ LOGGER.info("Starting server...");
+ httpServer.start();
+ LOGGER.info("Server started");
+ LOGGER.info("Press any key to stop the server...");
+ System.in.read();
+ } finally {
+ LOGGER.info("Stopping server...");
+ httpServer.stop();
+ LOGGER.info("Server stopped");
+ }
+ }
+
+}
--
Gitblit v1.10.0