From 65f47d9c24da91fdeac1eb6f012f44cc056ac4e4 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 25 Aug 2016 15:15:46 +0000
Subject: [PATCH] OPENDJ-3160 Support DN templates in reference property base DNs
---
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java | 5 +
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/RoutingContext.java | 16 +++++
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java | 3
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DnTemplate.java | 13 ++--
opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/DnTemplateTest.java | 3
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java | 68 ++++++++++++++--------
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferencePropertyMapper.java | 17 +++--
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2Ldap.java | 23 ++++---
8 files changed, 95 insertions(+), 53 deletions(-)
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DnTemplate.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DnTemplate.java
index b8e7ea2..83d561b 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DnTemplate.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/DnTemplate.java
@@ -44,10 +44,11 @@
* </table>
*/
final class DnTemplate {
- private static final Pattern TEMPLATE_KEY_RE = Pattern.compile("\\{([^}]+)\\}");
+ private static final Pattern TEMPLATE_VARIABLE_RE = Pattern.compile("\\{([^}]+)\\}");
private final String template;
private final String formatString;
private final List<String> variables;
+ /** A value of -1 means that this DN template is absolute. */
private final int relativeOffset;
/**
@@ -65,8 +66,7 @@
/**
* Compiles a DN template which will resolve LDAP entries relative to the root DSE by default, but MAY include
- * relative RDNs indicating that that the DN template will be resolved against current routing state
- * instead.
+ * relative RDNs indicating that the DN template will be resolved against current routing state instead.
*
* @param template
* The string representation of the DN template.
@@ -100,7 +100,7 @@
}
final List<String> templateVariables = new ArrayList<>();
- final Matcher matcher = TEMPLATE_KEY_RE.matcher(trimmedTemplate);
+ final Matcher matcher = TEMPLATE_VARIABLE_RE.matcher(trimmedTemplate);
final StringBuffer buffer = new StringBuffer(trimmedTemplate.length());
while (matcher.find()) {
matcher.appendReplacement(buffer, "%s");
@@ -121,7 +121,8 @@
// First determine the base DN based on the context DN and the relative offset.
DN baseDn = null;
if (relativeOffset >= 0 && context.containsContext(RoutingContext.class)) {
- baseDn = context.asContext(RoutingContext.class).getDn().parent(relativeOffset);
+ final RoutingContext routingContext = context.asContext(RoutingContext.class);
+ baseDn = routingContext.getDn().parent(routingContext.isCollection() ? relativeOffset - 1 : relativeOffset);
}
if (baseDn == null) {
baseDn = DN.rootDN();
@@ -152,7 +153,7 @@
return value;
}
if (!uriRouterContext.getParent().containsContext(UriRouterContext.class)) {
- throw new IllegalStateException("DN template parameter " + parameter + " cannot be resolved");
+ throw new IllegalStateException("DN template parameter \"" + parameter + "\" cannot be resolved");
}
uriRouterContext = uriRouterContext.getParent().asContext(UriRouterContext.class);
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferencePropertyMapper.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferencePropertyMapper.java
index f20052b..a1496b3 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferencePropertyMapper.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferencePropertyMapper.java
@@ -72,18 +72,19 @@
*/
private static final int SEARCH_MAX_CANDIDATES = 1000;
- private final DN baseDn;
+ private final DnTemplate baseDnTemplate;
private final Schema schema;
private Filter filter;
private final PropertyMapper mapper;
private final AttributeDescription primaryKey;
private SearchScope scope = SearchScope.WHOLE_SUBTREE;
- ReferencePropertyMapper(final Schema schema, final AttributeDescription ldapAttributeName, final DN baseDn,
- final AttributeDescription primaryKey, final PropertyMapper mapper) {
+ ReferencePropertyMapper(final Schema schema, final AttributeDescription ldapAttributeName,
+ final String baseDnTemplate, final AttributeDescription primaryKey,
+ final PropertyMapper mapper) {
super(ldapAttributeName);
this.schema = schema;
- this.baseDn = baseDn;
+ this.baseDnTemplate = DnTemplate.compile(baseDnTemplate);
this.primaryKey = primaryKey;
this.mapper = mapper;
}
@@ -144,7 +145,7 @@
@Override
public Promise<Filter, ResourceException> apply(final Filter result) {
// Search for all referenced entries and construct a filter.
- final SearchRequest request = createSearchRequest(result);
+ final SearchRequest request = createSearchRequest(context, result);
final List<Filter> subFilters = new LinkedList<>();
return connectionFrom(context).searchAsync(request, new SearchResultHandler() {
@@ -224,7 +225,7 @@
// Now search for the referenced entry in to get its DN.
final ByteString primaryKeyValue = primaryKeyAttribute.firstValue();
final Filter filter = Filter.equality(primaryKey.toString(), primaryKeyValue);
- final SearchRequest search = createSearchRequest(filter);
+ final SearchRequest search = createSearchRequest(context, filter);
connectionFrom(context).searchSingleEntryAsync(search)
.thenOnResult(new ResultHandler<SearchResultEntry>() {
@Override
@@ -325,9 +326,9 @@
}
}
- private SearchRequest createSearchRequest(final Filter result) {
+ private SearchRequest createSearchRequest(final Context context, final Filter result) {
final Filter searchFilter = filter != null ? Filter.and(filter, result) : result;
- return newSearchRequest(baseDn, scope, searchFilter, "1.1");
+ return newSearchRequest(baseDnTemplate.format(context), scope, searchFilter, "1.1");
}
private Promise<JsonValue, ResourceException> readEntry(
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2Ldap.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2Ldap.java
index 1b7b2e5..0ed6cba 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2Ldap.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2Ldap.java
@@ -54,7 +54,6 @@
import org.forgerock.opendj.ldap.AuthorizationException;
import org.forgerock.opendj.ldap.ConnectionException;
import org.forgerock.opendj.ldap.ConstraintViolationException;
-import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DecodeOptions;
import org.forgerock.opendj.ldap.EntryNotFoundException;
import org.forgerock.opendj.ldap.LdapException;
@@ -244,18 +243,21 @@
*
* @param attribute
* The DN valued LDAP attribute to be mapped.
- * @param baseDN
- * The search base DN for performing reverse lookups.
+ * @param baseDnTemplate
+ * The DN template which will be used as the search base when performing reverse lookups. The DN template
+ * may include template parameters and also parent RDNs using ".." notation. For example, the DN template
+ * "ou=groups,..,.." specifies that the search base DN should be computed by appending the RDN
+ * "ou=groups" to the grand-parent of the current resource's LDAP entry.
* @param primaryKey
* The search primary key LDAP attribute to use for performing reverse lookups.
* @param mapper
* An property mapper which will be used to map LDAP attributes in the referenced entry.
* @return The property mapper.
*/
- public static ReferencePropertyMapper reference(final AttributeDescription attribute, final DN baseDN,
+ public static ReferencePropertyMapper reference(final AttributeDescription attribute, final String baseDnTemplate,
final AttributeDescription primaryKey,
final PropertyMapper mapper) {
- return new ReferencePropertyMapper(Schema.getDefaultSchema(), attribute, baseDN, primaryKey, mapper);
+ return new ReferencePropertyMapper(Schema.getDefaultSchema(), attribute, baseDnTemplate, primaryKey, mapper);
}
/**
@@ -263,18 +265,21 @@
*
* @param attribute
* The DN valued LDAP attribute to be mapped.
- * @param baseDN
- * The search base DN for performing reverse lookups.
+ * @param baseDnTemplate
+ * The DN template which will be used as the search base when performing reverse lookups. The DN template
+ * may include template parameters and also parent RDNs using ".." notation. For example, the DN template
+ * "ou=groups,..,.." specifies that the search base DN should be computed by appending the RDN
+ * "ou=groups" to the grand-parent of the current resource's LDAP entry.
* @param primaryKey
* The search primary key LDAP attribute to use for performing reverse lookups.
* @param mapper
* An property mapper which will be used to map LDAP attributes in the referenced entry.
* @return The property mapper.
*/
- public static ReferencePropertyMapper reference(final String attribute, final String baseDN,
+ public static ReferencePropertyMapper reference(final String attribute, final String baseDnTemplate,
final String primaryKey, final PropertyMapper mapper) {
return reference(AttributeDescription.valueOf(attribute),
- DN.valueOf(baseDN),
+ baseDnTemplate,
AttributeDescription.valueOf(primaryKey),
mapper);
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/RoutingContext.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/RoutingContext.java
index fb2a3ae..9e4f41b 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/RoutingContext.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/RoutingContext.java
@@ -24,13 +24,23 @@
* A {@link Context} which communicates the current Rest2Ldap routing state to downstream handlers.
*/
final class RoutingContext extends AbstractContext {
+ static RoutingContext newCollectionRoutingContext(Context parent, DN collectionDn, Resource resource) {
+ return new RoutingContext(parent, collectionDn, resource, true);
+ }
+
+ static RoutingContext newRoutingContext(Context parent, DN resourceDn, Resource resource) {
+ return new RoutingContext(parent, resourceDn, resource, false);
+ }
+
private final DN dn;
private final Resource resource;
+ private final boolean isCollection;
- RoutingContext(final Context parent, final DN dn, final Resource resource) {
+ private RoutingContext(Context parent, DN dn, Resource resource, boolean isCollection) {
super(parent, "routing context");
this.dn = dn;
this.resource = resource;
+ this.isCollection = isCollection;
}
DN getDn() {
@@ -40,4 +50,8 @@
Resource getType() {
return resource;
}
+
+ boolean isCollection() {
+ return isCollection;
+ }
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java
index 4dad784..3cfe97a 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java
@@ -25,6 +25,7 @@
import static org.forgerock.opendj.ldap.requests.Requests.newSearchRequest;
import static org.forgerock.opendj.rest2ldap.Rest2Ldap.asResourceException;
import static org.forgerock.opendj.rest2ldap.Rest2ldapMessages.*;
+import static org.forgerock.opendj.rest2ldap.RoutingContext.newRoutingContext;
import static org.forgerock.opendj.rest2ldap.Utils.newBadRequestException;
import static org.forgerock.util.promise.Promises.newResultPromise;
@@ -234,7 +235,7 @@
final SearchRequest searchRequest = namingStrategy.createSearchRequest(dnFrom(context), idFrom(context));
if (searchRequest.getScope().equals(BASE_OBJECT) && !resource.hasSubTypesWithSubResources()) {
// There's no point in doing a search because we already know the DN and sub-resources.
- return newResultPromise(new RoutingContext(context, searchRequest.getName(), resource));
+ return newResultPromise(newRoutingContext(context, searchRequest.getName(), resource));
}
searchRequest.addAttribute("objectClass");
return conn.searchSingleEntryAsync(searchRequest)
@@ -243,7 +244,7 @@
public Promise<RoutingContext, ResourceException> apply(SearchResultEntry entry)
throws ResourceException {
final Resource subType = resource.resolveSubTypeFromObjectClasses(entry);
- return newResultPromise(new RoutingContext(context, entry.getName(), subType));
+ return newResultPromise(newRoutingContext(context, entry.getName(), subType));
}
}, new AsyncFunction<LdapException, RoutingContext, ResourceException>() {
@Override
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java
index 5e6f81c..7cec13f 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java
@@ -34,6 +34,8 @@
import static org.forgerock.opendj.ldap.SearchScope.SINGLE_LEVEL;
import static org.forgerock.opendj.ldap.requests.Requests.*;
import static org.forgerock.opendj.rest2ldap.ReadOnUpdatePolicy.CONTROLS;
+import static org.forgerock.opendj.rest2ldap.RoutingContext.newCollectionRoutingContext;
+import static org.forgerock.opendj.rest2ldap.RoutingContext.newRoutingContext;
import static org.forgerock.opendj.rest2ldap.Utils.connectionFrom;
import static org.forgerock.opendj.rest2ldap.Utils.newBadRequestException;
import static org.forgerock.opendj.rest2ldap.Utils.newNotSupportedException;
@@ -260,10 +262,15 @@
return e.asPromise();
}
+ // Temporary routing context which will be used for encoding LDAP attributes. Note that the DN represents the
+ // DN of the collection, not the resource being created. The DN of the resource can only be determined once
+ // the LDAP attributes have been encoded.
+ final RoutingContext parentDnAndType = newCollectionRoutingContext(context, baseDn, subType);
+
// Now build the LDAP representation and add it.
final Connection connection = connectionFrom(context);
return subType.getPropertyMapper()
- .create(context, subType, ROOT, request.getContent())
+ .create(parentDnAndType, subType, ROOT, request.getContent())
.thenAsync(new AsyncFunction<List<Attribute>, ResourceResponse, ResourceException>() {
@Override
public Promise<ResourceResponse, ResourceException> apply(final List<Attribute> attributes) {
@@ -284,9 +291,12 @@
getLdapAttributesForKnownType(request.getFields(), subType);
addRequest.addControl(PostReadRequestControl.newControl(false, ldapAttributes));
}
+ // Use a routing context which refers to the created entry when computing the response.
+ final RoutingContext dnAndType =
+ newRoutingContext(context, addRequest.getName(), subType);
return connection.addAsync(addRequest)
.thenCatchAsync(lazilyAddGlueEntry(connection, addRequest))
- .thenAsync(encodeUpdateResourceResponse(context, subType),
+ .thenAsync(encodeUpdateResourceResponse(dnAndType, subType),
adaptLdapException(ResourceResponse.class));
}
});
@@ -346,7 +356,7 @@
return connection.applyChangeAsync(deleteRequest)
.thenCatchAsync(deleteSubtreeWithoutUsingSubtreeDeleteControl(connection,
deleteRequest))
- .thenAsync(encodeUpdateResourceResponse(context, dnAndType.getType()),
+ .thenAsync(encodeUpdateResourceResponse(dnAndType, dnAndType.getType()),
adaptLdapException(ResourceResponse.class));
}
});
@@ -433,7 +443,7 @@
final Resource subType = dnAndType.getType();
final PropertyMapper propertyMapper = subType.getPropertyMapper();
for (final PatchOperation operation : request.getPatchOperations()) {
- promises.add(propertyMapper.patch(context, subType, ROOT, operation));
+ promises.add(propertyMapper.patch(dnAndType, subType, ROOT, operation));
}
return when(promises);
}
@@ -457,7 +467,7 @@
if (modifyRequest.getModifications().isEmpty()) {
// This patch is a no-op so just read the entry and check its version.
return connection.readEntryAsync(dnAndType.getDn(), attributes)
- .thenAsync(encodeEmptyPatchResourceResponse(context, subType, request),
+ .thenAsync(encodeEmptyPatchResourceResponse(dnAndType, subType, request),
adaptLdapException(ResourceResponse.class));
} else {
// Add controls and perform the modify request.
@@ -469,7 +479,7 @@
}
addAssertionControl(modifyRequest, request.getRevision());
return connection.applyChangeAsync(modifyRequest)
- .thenAsync(encodeUpdateResourceResponse(context, subType),
+ .thenAsync(encodeUpdateResourceResponse(dnAndType, subType),
adaptLdapException(ResourceResponse.class));
}
}
@@ -503,6 +513,9 @@
if (queryFilter == null) {
return new BadRequestException(ERR_QUERY_BY_ID_OR_EXPRESSION_NOT_SUPPORTED.get().toString()).asPromise();
}
+
+ // Temporary routing context which will be used for encoding the LDAP filter.
+ final RoutingContext parentDnAndType = newCollectionRoutingContext(context, baseDn, resource);
final PropertyMapper propertyMapper = resource.getPropertyMapper();
final QueryFilterVisitor<Promise<Filter, ResourceException>, Void, JsonPointer> visitor =
new QueryFilterVisitor<Promise<Filter, ResourceException>, Void, JsonPointer>() {
@@ -549,14 +562,14 @@
public Promise<Filter, ResourceException> visitContainsFilter(
final Void unused, final JsonPointer field, final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, CONTAINS, null, valueAssertion);
+ parentDnAndType, resource, ROOT, field, CONTAINS, null, valueAssertion);
}
@Override
public Promise<Filter, ResourceException> visitEqualsFilter(
final Void unused, final JsonPointer field, final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, EQUAL_TO, null, valueAssertion);
+ parentDnAndType, resource, ROOT, field, EQUAL_TO, null, valueAssertion);
}
@Override
@@ -565,35 +578,35 @@
final String operator,
final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, EXTENDED, operator, valueAssertion);
+ parentDnAndType, resource, ROOT, field, EXTENDED, operator, valueAssertion);
}
@Override
public Promise<Filter, ResourceException> visitGreaterThanFilter(
final Void unused, final JsonPointer field, final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, GREATER_THAN, null, valueAssertion);
+ parentDnAndType, resource, ROOT, field, GREATER_THAN, null, valueAssertion);
}
@Override
public Promise<Filter, ResourceException> visitGreaterThanOrEqualToFilter(
final Void unused, final JsonPointer field, final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, GREATER_THAN_OR_EQUAL_TO, null, valueAssertion);
+ parentDnAndType, resource, ROOT, field, GREATER_THAN_OR_EQUAL_TO, null, valueAssertion);
}
@Override
public Promise<Filter, ResourceException> visitLessThanFilter(
final Void unused, final JsonPointer field, final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, LESS_THAN, null, valueAssertion);
+ parentDnAndType, resource, ROOT, field, LESS_THAN, null, valueAssertion);
}
@Override
public Promise<Filter, ResourceException> visitLessThanOrEqualToFilter(
final Void unused, final JsonPointer field, final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, LESS_THAN_OR_EQUAL_TO, null, valueAssertion);
+ parentDnAndType, resource, ROOT, field, LESS_THAN_OR_EQUAL_TO, null, valueAssertion);
}
@Override
@@ -649,14 +662,15 @@
@Override
public Promise<Filter, ResourceException> visitPresentFilter(
final Void unused, final JsonPointer field) {
- return propertyMapper.getLdapFilter(context, resource, ROOT, field, PRESENT, null, null);
+ return propertyMapper.getLdapFilter(
+ parentDnAndType, resource, ROOT, field, PRESENT, null, null);
}
@Override
public Promise<Filter, ResourceException> visitStartsWithFilter(
final Void unused, final JsonPointer field, final Object valueAssertion) {
return propertyMapper.getLdapFilter(
- context, resource, ROOT, field, STARTS_WITH, null, valueAssertion);
+ parentDnAndType, resource, ROOT, field, STARTS_WITH, null, valueAssertion);
}
};
// Note that the returned LDAP filter may be null if it could not be mapped by any property mappers.
@@ -741,8 +755,9 @@
final String id = namingStrategy.decodeResourceId(entry);
final String revision = getRevisionFromEntry(entry);
final Resource subType = resource.resolveSubTypeFromObjectClasses(entry);
+ final RoutingContext dnAndType = newRoutingContext(context, entry.getName(), subType);
final PropertyMapper propertyMapper = subType.getPropertyMapper();
- propertyMapper.read(context, subType, ROOT, entry)
+ propertyMapper.read(dnAndType, subType, ROOT, entry)
.thenOnResult(new ResultHandler<JsonValue>() {
@Override
public void handleResult(final JsonValue result) {
@@ -845,7 +860,8 @@
@Override
public Promise<ResourceResponse, ResourceException> apply(SearchResultEntry entry) {
final Resource subType = resource.resolveSubTypeFromObjectClasses(entry);
- return encodeResourceResponse(context, subType, entry);
+ final RoutingContext dnAndType = newRoutingContext(context, entry.getName(), subType);
+ return encodeResourceResponse(dnAndType, subType, entry);
}
});
}
@@ -854,7 +870,7 @@
final Context context, final String resourceId, final UpdateRequest request) {
final Connection connection = connectionFrom(context);
final AtomicReference<Entry> entryHolder = new AtomicReference<>();
- final AtomicReference<Resource> subTypeHolder = new AtomicReference<>();
+ final AtomicReference<RoutingContext> dnAndTypeHolder = new AtomicReference<>();
return connection
.searchSingleEntryAsync(searchRequestForUnknownType(resourceId, Collections.<JsonPointer>emptyList()))
.thenCatchAsync(adaptLdapException(SearchResultEntry.class))
@@ -869,18 +885,20 @@
// Determine the type of resource and set of changes that need to be performed.
final Resource subType = resource.resolveSubTypeFromObjectClasses(entry);
- subTypeHolder.set(subType);
+ final RoutingContext dnAndType = newRoutingContext(context, entry.getName(), subType);
+ dnAndTypeHolder.set(dnAndType);
final PropertyMapper propertyMapper = subType.getPropertyMapper();
- return propertyMapper.update(context, subType , ROOT, entry, request.getContent());
+ return propertyMapper.update(dnAndType, subType , ROOT, entry, request.getContent());
}
}).thenAsync(new AsyncFunction<List<Modification>, ResourceResponse, ResourceException>() {
@Override
public Promise<ResourceResponse, ResourceException> apply(List<Modification> modifications)
throws ResourceException {
- final Resource subType = subTypeHolder.get();
+ final RoutingContext dnAndType = dnAndTypeHolder.get();
+ final Resource subType = dnAndType.getType();
if (modifications.isEmpty()) {
// No changes to be performed so just return the entry that we read.
- return encodeResourceResponse(context, subType, entryHolder.get());
+ return encodeResourceResponse(dnAndType, subType, entryHolder.get());
}
// Perform the modify operation.
final ModifyRequest modifyRequest = newModifyRequest(entryHolder.get().getName());
@@ -894,7 +912,7 @@
addAssertionControl(modifyRequest, request.getRevision());
modifyRequest.getModifications().addAll(modifications);
return connection.applyChangeAsync(modifyRequest)
- .thenAsync(encodeUpdateResourceResponse(context, subType),
+ .thenAsync(encodeUpdateResourceResponse(dnAndType, subType),
adaptLdapException(ResourceResponse.class));
}
});
@@ -928,7 +946,7 @@
final SearchRequest searchRequest = namingStrategy.createSearchRequest(baseDn, resourceId);
if (searchRequest.getScope().equals(BASE_OBJECT) && !resource.hasSubTypes()) {
// There's no point in doing a search because we already know the DN and sub-resources.
- return newResultPromise(new RoutingContext(context, searchRequest.getName(), resource));
+ return newResultPromise(newRoutingContext(context, searchRequest.getName(), resource));
}
if (etagAttribute != null && revision != null) {
searchRequest.addAttribute(etagAttribute.toString());
@@ -943,7 +961,7 @@
// Fail-fast if there is a version mismatch.
ensureMvccVersionMatches(entry, revision);
final Resource subType = resource.resolveSubTypeFromObjectClasses(entry);
- return newResultPromise(new RoutingContext(context, entry.getName(), subType));
+ return newResultPromise(newRoutingContext(context, entry.getName(), subType));
}
}, adaptLdapException(RoutingContext.class));
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java
index 2e4076e..1fe6eb4 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java
@@ -23,6 +23,7 @@
import static org.forgerock.opendj.ldap.SearchScope.BASE_OBJECT;
import static org.forgerock.opendj.ldap.requests.Requests.newSearchRequest;
import static org.forgerock.opendj.rest2ldap.Rest2ldapMessages.ERR_UNSUPPORTED_REQUEST_AGAINST_SINGLETON;
+import static org.forgerock.opendj.rest2ldap.RoutingContext.newRoutingContext;
import static org.forgerock.util.promise.Promises.newResultPromise;
import org.forgerock.json.resource.ActionRequest;
@@ -135,7 +136,7 @@
}
private Promise<RoutingContext, ResourceException> route(final Context context) {
- return newResultPromise(new RoutingContext(context, dnFrom(context), resource));
+ return newResultPromise(newRoutingContext(context, dnFrom(context), resource));
}
private SubResourceImpl singleton(final Context context) {
diff --git a/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/DnTemplateTest.java b/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/DnTemplateTest.java
index 7f7b3cf..cc847dc 100644
--- a/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/DnTemplateTest.java
+++ b/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/DnTemplateTest.java
@@ -18,6 +18,7 @@
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.forgerock.opendj.rest2ldap.Rest2Ldap.rest2Ldap;
+import static org.forgerock.opendj.rest2ldap.RoutingContext.newRoutingContext;
import static org.forgerock.util.Options.defaultOptions;
import org.forgerock.http.routing.UriRouterContext;
@@ -36,7 +37,7 @@
Context ctx = new RootContext();
ctx = new Rest2LdapContext(ctx, rest2Ldap(defaultOptions()));
ctx = new UriRouterContext(ctx, "", "", singletonMap("subdomain", "www"));
- ctx = new RoutingContext(ctx, DN.valueOf("dc=example,dc=com"), null);
+ ctx = newRoutingContext(ctx, DN.valueOf("dc=example,dc=com"), null);
ctx = new UriRouterContext(ctx, "", "", singletonMap("tenant", "acme"));
context = ctx;
}
--
Gitblit v1.10.0