Update to use new json-resource 2.0 APIs.
3 files deleted
3 files added
10 files modified
| | |
| | | <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> |
| | |
| | | |
| | | 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 { |
| | | |
| | |
| | | * <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 |
| | |
| | | * 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, |
| | |
| | | * 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). |
| | |
| | | |
| | | 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 |
| | |
| | | * 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); |
| | |
| | | /** |
| | | * {@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); |
| | | } |
| | | } |
| | |
| | | /** |
| | | * {@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); |
| | | } |
| | |
| | | |
| | | 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; |
| | | } |
| | |
| | | /** |
| | | * {@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); |
| | | } |
| | | } |
| | |
| | | /** |
| | | * {@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); |
| | | } |
| | | } |
| | |
| | | /** |
| | | * {@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 |
| | |
| | | * 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; |
| | | } |
| | |
| | | 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); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | 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 { |
| | | |
| | |
| | | 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 |
| | |
| | | * @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; |
| | | } |
| | |
| | | /** |
| | | * {@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 |
| | | |
| | | } |
| | |
| | | |
| | | 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. |
| | |
| | | } |
| | | break; |
| | | default: |
| | | String name = jsonAttribute.get(0); |
| | | final String name = jsonAttribute.get(0); |
| | | if (isIncludedAttribute(name)) { |
| | | ldapAttributes.add(name); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | 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)) { |
| | |
| | | |
| | | return false; |
| | | } |
| | | |
| | | public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) { |
| | | // TODO: |
| | | } |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | |
| | | } |
| | | |
| | | 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) { |
| | | |
| | |
| | | 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); |
| | | } |
| | | |
| | |
| | | |
| | | 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) { |
| | | |
| | |
| | | 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); |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
| 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.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; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | 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; |
| | | |
| | | /** |
| | | * |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void getLDAPAttributes(JsonPointer jsonAttribute, Set<String> ldapAttributes) { |
| | | public void getLDAPAttributes(final JsonPointer jsonAttribute, final Set<String> ldapAttributes) { |
| | | // TODO Auto-generated method stub |
| | | |
| | | } |
| | |
| | | /** |
| | | * {@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 |
| | | |
| | | } |
| | |
| | | /** |
| | | * {@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 |
| | | |
| | | } |
| | |
| | | |
| | | 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 |
| | |
| | | * @param attributeName |
| | | * The name of the simple JSON and LDAP attribute. |
| | | */ |
| | | public SimpleAttributeMapper(String attributeName) { |
| | | public SimpleAttributeMapper(final String attributeName) { |
| | | this(attributeName, attributeName); |
| | | } |
| | | |
| | |
| | | * @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()) { |
| | |
| | | } 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); |
| | | } |
| | | |
| | | } |
| 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.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 |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | 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())) { |
| | |
| | | } |
| | | }; |
| | | |
| | | // 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(); |
| | |
| | | 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. |
| | | } |
| | | |
| | | } |
| 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 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"); |
| | | } |
| | | } |
| | | |
| | | } |