| | |
| | | * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2012 ForgeRock AS. |
| | | * Copyright 2012-2013 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.rest2ldap; |
| | | |
| | | import static org.forgerock.opendj.rest2ldap.Utils.accumulate; |
| | | import static org.forgerock.opendj.rest2ldap.Utils.transform; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | import org.forgerock.json.fluent.JsonPointer; |
| | | import org.forgerock.json.fluent.JsonValue; |
| | | import org.forgerock.json.resource.ResourceException; |
| | | import org.forgerock.json.resource.ResultHandler; |
| | | import org.forgerock.json.resource.ServerContext; |
| | | import org.forgerock.opendj.ldap.Attribute; |
| | | import org.forgerock.opendj.ldap.Entry; |
| | | import org.forgerock.opendj.ldap.Filter; |
| | | import org.forgerock.opendj.ldap.Function; |
| | | |
| | | /** |
| | | * An attribute mapper which combines the results of a set of subordinate |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) { |
| | | public void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute, |
| | | final Set<String> ldapAttributes) { |
| | | for (final AttributeMapper attribute : attributeMappers) { |
| | | attribute.getLDAPAttributes(jsonAttribute, ldapAttributes); |
| | | attribute.getLDAPAttributes(c, jsonAttribute, ldapAttributes); |
| | | } |
| | | } |
| | | |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void toJSON(final ServerContext c, final Entry e, |
| | | final ResultHandler<Map<String, Object>> h) { |
| | | final ResultHandler<Map<String, Object>> resultAccumulater = new ResultHandler<Map<String, Object>>() { |
| | | private final AtomicInteger latch = new AtomicInteger(attributeMappers.size()); |
| | | private final List<Map<String, Object>> results = new ArrayList<Map<String, Object>>( |
| | | latch.get()); |
| | | public void getLDAPFilter(final Context c, final FilterType type, |
| | | final JsonPointer jsonAttribute, final String operator, final Object valueAssertion, |
| | | final ResultHandler<Filter> h) { |
| | | final ResultHandler<Filter> handler = |
| | | accumulate(attributeMappers.size(), transform( |
| | | new Function<List<Filter>, Filter, Void>() { |
| | | @Override |
| | | public Filter apply(final List<Filter> value, final Void p) { |
| | | // Remove unmapped filters and combine using logical-OR. |
| | | final Iterator<Filter> i = value.iterator(); |
| | | while (i.hasNext()) { |
| | | final Filter f = i.next(); |
| | | if (f == null) { |
| | | // No mapping so remove. |
| | | i.remove(); |
| | | } else if (f == c.getConfig().getFalseFilter()) { |
| | | return c.getConfig().getFalseFilter(); |
| | | } else if (f == c.getConfig().getTrueFilter()) { |
| | | return c.getConfig().getTrueFilter(); |
| | | } |
| | | } |
| | | switch (value.size()) { |
| | | case 0: |
| | | // No mappings found. |
| | | return null; |
| | | case 1: |
| | | return value.get(0); |
| | | default: |
| | | return Filter.or(value); |
| | | } |
| | | } |
| | | }, h)); |
| | | for (final AttributeMapper subMapper : attributeMappers) { |
| | | subMapper.getLDAPFilter(c, type, jsonAttribute, operator, valueAssertion, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void handleError(final ResourceException e) { |
| | | // Ensure that handler is only invoked once. |
| | | if (latch.getAndSet(0) > 0) { |
| | | h.handleError(e); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final Map<String, Object> result) { |
| | | if (result != null && !result.isEmpty()) { |
| | | 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); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void toJSON(final Context c, final Entry e, final ResultHandler<Map<String, Object>> h) { |
| | | final ResultHandler<Map<String, Object>> handler = |
| | | accumulate(attributeMappers.size(), transform( |
| | | new Function<List<Map<String, Object>>, Map<String, Object>, Void>() { |
| | | @Override |
| | | public Map<String, Object> apply(final List<Map<String, Object>> value, |
| | | final Void p) { |
| | | switch (value.size()) { |
| | | case 0: |
| | | return Collections.<String, Object> emptyMap(); |
| | | case 1: |
| | | return value.get(0) != null ? value.get(0) : Collections |
| | | .<String, Object> emptyMap(); |
| | | default: |
| | | return mergeJsonValues(value, |
| | | new LinkedHashMap<String, Object>()); |
| | | } |
| | | } |
| | | }, h)); |
| | | for (final AttributeMapper mapper : attributeMappers) { |
| | | mapper.toJSON(c, e, resultAccumulater); |
| | | mapper.toJSON(c, e, handler); |
| | | } |
| | | } |
| | | |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void toLDAP(final ServerContext c, final JsonValue v, |
| | | final ResultHandler<List<Attribute>> h) { |
| | | public void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) { |
| | | // TODO Auto-generated method stub |
| | | |
| | | } |
| | | |
| | | /** |
| | | * Merge one JSON value into another. |
| | | * |
| | | * @param srcValue |
| | | * The source value. |
| | | * @param dstValue |
| | | * The destination value, into which which the value should be |
| | | * merged. |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | private void mergeJsonValue(final Map<String, Object> srcValue, |
| | | final Map<String, Object> dstValue) { |
| | |
| | | } 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)) { |
| | | // Merge two lists- create a new List, in case the existing one |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 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, |
| | | private Map<String, Object> mergeJsonValues(final List<Map<String, Object>> srcValues, |
| | | final Map<String, Object> dstValue) { |
| | | for (final Map<String, Object> value : srcValues) { |
| | | mergeJsonValue(value, dstValue); |
| | | if (value != null) { |
| | | mergeJsonValue(value, dstValue); |
| | | } |
| | | } |
| | | return dstValue; |
| | | } |
| | | } |