Checkpoint local changes: add more attribute mapping support.
2 files added
8 files modified
| | |
| | | public interface AttributeMapper { |
| | | |
| | | /** |
| | | * Adds the names of the all the LDAP attributes required by this attribute |
| | | * mapper to the provided set. |
| | | * <p> |
| | | * Implementations should only add the names of attributes found in the LDAP |
| | | * entry directly associated with the resource. |
| | | * |
| | | * @param ldapAttributes |
| | | * The set into which the required LDAP attribute names should be |
| | | * put. |
| | | */ |
| | | void getLDAPAttributes(Set<String> ldapAttributes); |
| | | |
| | | /** |
| | | * Adds the names of the LDAP attributes required by this attribute mapper |
| | | * which are associated with the provided resource attribute to the provided |
| | | * set. |
| | | * <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 |
| | | * The set into which the required LDAP attribute names should be |
| | | * put. |
| | | * @param resourceAttribute |
| | | * The name of the resource attribute requested by the client. |
| | | */ |
| | | void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute); |
| | | void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes); |
| | | |
| | | /** |
| | | * Transforms attributes contained in the provided LDAP entry to JSON |
| | |
| | | */ |
| | | public ComplexAttributeMapper(String jsonAttributeName, AttributeMapper mapper) { |
| | | this.jsonAttributeName = jsonAttributeName; |
| | | this.normalizedJsonAttributeName = toLowerCase(jsonAttributeName); |
| | | this.mapper = mapper; |
| | | this.normalizedJsonAttributeName = toLowerCase(jsonAttributeName); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(Set<String> ldapAttributes) { |
| | | mapper.getLDAPAttributes(ldapAttributes); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) { |
| | | if (resourceAttribute.size() > 0) { |
| | | String rootName = resourceAttribute.get(0); |
| | | if (toLowerCase(rootName).equals(normalizedJsonAttributeName)) { |
| | | JsonPointer relativePointer = resourceAttribute.relativePointer(); |
| | | if (relativePointer == null) { |
| | | // User requested the entire contents of this complex |
| | | // attribute. |
| | | mapper.getLDAPAttributes(ldapAttributes); |
| | | } else { |
| | | // User requested partial contents of this complex |
| | | // attribute. |
| | | mapper.getLDAPAttributes(ldapAttributes, relativePointer); |
| | | } |
| | | } |
| | | public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) { |
| | | if (attributeMatchesPointer(jsonAttribute)) { |
| | | JsonPointer relativePointer = jsonAttribute.relativePointer(); |
| | | mapper.getLDAPAttributes(relativePointer, ldapAttributes); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | } |
| | | |
| | | private boolean attributeMatchesPointer(JsonPointer resourceAttribute) { |
| | | return resourceAttribute.isEmpty() |
| | | || toLowerCase(resourceAttribute.get(0)).equals(normalizedJsonAttributeName); |
| | | } |
| | | |
| | | } |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | * |
| | | */ |
| | | public final class CompositeAttributeMapper implements AttributeMapper { |
| | | private final Set<String> allLDAPAttributes = new LinkedHashSet<String>(); |
| | | private final List<AttributeMapper> attributeMappers = new LinkedList<AttributeMapper>(); |
| | | |
| | | /** |
| | |
| | | |
| | | public CompositeAttributeMapper addMapper(AttributeMapper mapper) { |
| | | attributeMappers.add(mapper); |
| | | mapper.getLDAPAttributes(allLDAPAttributes); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(Set<String> ldapAttributes) { |
| | | ldapAttributes.addAll(allLDAPAttributes); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) { |
| | | public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) { |
| | | for (AttributeMapper attribute : attributeMappers) { |
| | | attribute.getLDAPAttributes(ldapAttributes, resourceAttribute); |
| | | attribute.getLDAPAttributes(jsonAttribute, ldapAttributes); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * 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.Collections; |
| | | 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.Attribute; |
| | | import org.forgerock.opendj.ldap.Entry; |
| | | import org.forgerock.resource.provider.Context; |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | public class ConstantAttributeMapper implements AttributeMapper { |
| | | |
| | | private final String jsonAttributeName; |
| | | private final Object jsonAttributeValue; |
| | | |
| | | /** |
| | | * Creates a new constant attribute mapper which maps a single LDAP |
| | | * attribute to a fixed value. |
| | | * |
| | | * @param attributeName |
| | | * The name of the simple JSON attribute. |
| | | * @param attributeValue |
| | | * The value of the simple JSON attribute. |
| | | */ |
| | | public ConstantAttributeMapper(String attributeName, Object attributeValue) { |
| | | this.jsonAttributeName = attributeName; |
| | | this.jsonAttributeValue = attributeValue; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void toJson(Context c, Entry e, |
| | | final AttributeMapperCompletionHandler<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); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) { |
| | | // TODO Auto-generated method stub |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) { |
| | | String name = resourceAttribute.leaf(); |
| | | if (name != null) { |
| | | public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) { |
| | | switch (jsonAttribute.size()) { |
| | | case 0: |
| | | // Requested everything. |
| | | if (!includedAttributes.isEmpty()) { |
| | | ldapAttributes.addAll(includedAttributes.values()); |
| | | } else { |
| | | // All user attributes. |
| | | ldapAttributes.add("*"); |
| | | } |
| | | break; |
| | | default: |
| | | String name = jsonAttribute.get(0); |
| | | if (isIncludedAttribute(name)) { |
| | | ldapAttributes.add(name); |
| | | } else { |
| | | // FIXME: log something or return a ResourceException? |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | .includeAttribute("cn", "sn", "givenName"))).addMapper( |
| | | new ComplexAttributeMapper("contactInformation", |
| | | new CompositeAttributeMapper().addMapper( |
| | | new SimpleAttributeMapper("telephoneNumber")).addMapper( |
| | | new SimpleAttributeMapper("emailAddress", "mail")))); |
| | | 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! |
| | |
| | | if (requestedAttributes.isEmpty()) { |
| | | // Full read. |
| | | requestedLDAPAttributes = new LinkedHashSet<String>(); |
| | | attributeMapper.getLDAPAttributes(requestedLDAPAttributes); |
| | | attributeMapper.getLDAPAttributes(new JsonPointer(), requestedLDAPAttributes); |
| | | } else { |
| | | // Partial read. |
| | | requestedLDAPAttributes = new LinkedHashSet<String>(requestedAttributes.size()); |
| | | for (final JsonPointer requestedAttribute : requestedAttributes) { |
| | | attributeMapper.getLDAPAttributes(requestedLDAPAttributes, requestedAttribute); |
| | | attributeMapper.getLDAPAttributes(requestedAttribute, requestedLDAPAttributes); |
| | | } |
| | | } |
| | | return requestedLDAPAttributes; |
| New file |
| | |
| | | /* |
| | | * 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.opendj.ldap.Attribute; |
| | | import org.forgerock.opendj.ldap.Entry; |
| | | import org.forgerock.resource.provider.Context; |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | public class ReferenceAttributeMapper implements AttributeMapper { |
| | | |
| | | // private final EntryContainer referencedContainer; |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) { |
| | | // TODO Auto-generated method stub |
| | | |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void toJson(Context c, Entry e, AttributeMapperCompletionHandler<Map<String, Object>> h) { |
| | | // TODO Auto-generated method stub |
| | | |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) { |
| | | // TODO Auto-generated method stub |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | package org.forgerock.opendj.rest2ldap; |
| | | |
| | | import static org.forgerock.opendj.rest2ldap.Utils.attributeToJson; |
| | | import static org.forgerock.opendj.rest2ldap.Utils.byteStringToJson; |
| | | import static org.forgerock.opendj.rest2ldap.Utils.toLowerCase; |
| | | |
| | | import java.util.Collections; |
| | |
| | | import org.forgerock.json.fluent.JsonPointer; |
| | | import org.forgerock.json.fluent.JsonValue; |
| | | 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; |
| | | |
| | | /** |
| | |
| | | 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; |
| | | |
| | | /** |
| | | * Creates a new simple attribute mapper which maps a single LDAP attribute |
| | | * to an entry. |
| | |
| | | */ |
| | | public SimpleAttributeMapper(String jsonAttributeName, String ldapAttributeName) { |
| | | this.jsonAttributeName = jsonAttributeName; |
| | | this.normalizedJsonAttributeName = toLowerCase(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) { |
| | | this.forceSingleValued = singleValued; |
| | | return this; |
| | | } |
| | | |
| | | public SimpleAttributeMapper withDecoder(Function<ByteString, ?, Void> f) { |
| | | this.decoder = f; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(Set<String> ldapAttributes) { |
| | | public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) { |
| | | if (attributeMatchesPointer(jsonAttribute)) { |
| | | ldapAttributes.add(ldapAttributeName); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) { |
| | | if (toLowerCase(resourceAttribute.leaf()).equals(normalizedJsonAttributeName)) { |
| | | ldapAttributes.add(ldapAttributeName); |
| | | } |
| | | private boolean attributeMatchesPointer(JsonPointer resourceAttribute) { |
| | | return resourceAttribute.isEmpty() |
| | | || toLowerCase(resourceAttribute.get(0)).equals(normalizedJsonAttributeName); |
| | | } |
| | | |
| | | /** |
| | |
| | | final AttributeMapperCompletionHandler<Map<String, Object>> h) { |
| | | Attribute a = e.getAttribute(ldapAttributeName); |
| | | if (a != null) { |
| | | Map<String, Object> result = |
| | | Collections.singletonMap(jsonAttributeName, attributeToJson(a)); |
| | | Function<ByteString, ?, Void> f = |
| | | decoder == null ? Functions.fixedFunction(byteStringToJson(), a) : decoder; |
| | | final Object value; |
| | | if (forceSingleValued || a.getAttributeDescription().getAttributeType().isSingleValue()) { |
| | | value = a.parse().as(f, defaultValue); |
| | | } else { |
| | | value = a.parse().asSetOf(f, defaultValue); |
| | | } |
| | | Map<String, Object> result = Collections.singletonMap(jsonAttributeName, value); |
| | | h.onSuccess(result); |
| | | } |
| | | } |
| | |
| | | */ |
| | | final class Utils { |
| | | |
| | | private static final Function<ByteString, Object, Syntax> BYTESTRING_TO_JSON = |
| | | new Function<ByteString, Object, Syntax>() { |
| | | public Object apply(final ByteString value, final Syntax syntax) { |
| | | 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(); |
| | | if (syntax.equals(getBooleanSyntax())) { |
| | | return Functions.byteStringToBoolean().apply(value, null); |
| | | } else if (syntax.equals(getIntegerSyntax())) { |
| | |
| | | } |
| | | } |
| | | |
| | | static Function<ByteString, Object, Attribute> byteStringToJson() { |
| | | return BYTESTRING_TO_JSON; |
| | | } |
| | | |
| | | static Object attributeToJson(Attribute a) { |
| | | Syntax syntax = a.getAttributeDescription().getAttributeType().getSyntax(); |
| | | Function<ByteString, Object, Void> f = Functions.fixedFunction(BYTESTRING_TO_JSON, syntax); |
| | | 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)); |
| | | } |
| | |
| | | } |
| | | return object; |
| | | } |
| | | |
| | | } |