diff --git a/lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapErrorCode.java b/lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapErrorCode.java
new file mode 100644
index 0000000..228a73b
--- /dev/null
+++ b/lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapErrorCode.java
@@ -0,0 +1,36 @@
+/*
+ Copyright 2015 Red Hat, Inc. and/or its affiliates.
+
+ This file is part of lightblue.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+package com.redhat.lightblue.common.ldap;
+
+/**
+ * Error codes specific to LDAP
+ *
+ * @author dcrissman
+ */
+public final class LdapErrorCode {
+
+ /** An unsupported feature was used. */
+ public static final String ERR_UNSUPPORTED_FEATURE = "ldap:UnsupportedFeature:";
+
+ /** Lightblue-Ldap does not currently support object arrays. This error indicates that such a field was used. */
+ public static final String ERR_UNSUPPORTED_FEATURE_OBJECT_ARRAY = ERR_UNSUPPORTED_FEATURE + "ObjectArray";
+
+ private LdapErrorCode(){}
+
+}
diff --git a/lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapFieldNameTranslator.java b/lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapFieldNameTranslator.java
index d65a723..2a30a48 100644
--- a/lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapFieldNameTranslator.java
+++ b/lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapFieldNameTranslator.java
@@ -18,6 +18,8 @@
*/
package com.redhat.lightblue.common.ldap;
+import com.redhat.lightblue.util.Path;
+
/**
* Represents a class that can translate back and forth between a fieldName and an LDAP attributeName.
*
@@ -30,13 +32,13 @@ public interface LdapFieldNameTranslator {
* @param fieldName - metadata field name
* @return ldap attributeName or the fieldName back at you if no mapping is present.
*/
- public String translateFieldName(String fieldName);
+ public String translateFieldName(Path path);
/**
* Returns the fieldName with the given attributeName.
* @param attributeName - ldap attribute name
* @return metadata fieldName or the attributeName back at you if no mapping is present.
*/
- public String translateAttributeName(String attributeName);
+ public Path translateAttributeName(String attributeName);
}
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/EntryBuilder.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/EntryBuilder.java
index ad81fff..db9c35d 100644
--- a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/EntryBuilder.java
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/EntryBuilder.java
@@ -24,19 +24,20 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.redhat.lightblue.common.ldap.LdapConstant;
+import com.redhat.lightblue.common.ldap.LdapErrorCode;
import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
import com.redhat.lightblue.common.ldap.LightblueUtil;
import com.redhat.lightblue.metadata.ArrayElement;
import com.redhat.lightblue.metadata.ArrayField;
import com.redhat.lightblue.metadata.EntityMetadata;
-import com.redhat.lightblue.metadata.ObjectField;
+import com.redhat.lightblue.metadata.MetadataConstants;
import com.redhat.lightblue.metadata.SimpleField;
import com.redhat.lightblue.metadata.Type;
import com.redhat.lightblue.metadata.types.BinaryType;
import com.redhat.lightblue.metadata.types.DateType;
+import com.redhat.lightblue.util.Error;
import com.redhat.lightblue.util.JsonDoc;
import com.redhat.lightblue.util.JsonNodeCursor;
-import com.redhat.lightblue.util.Path;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.util.StaticUtils;
@@ -55,9 +56,17 @@ public EntryBuilder(EntityMetadata md, LdapFieldNameTranslator fieldNameTranslat
}
public Entry build(String dn, JsonDoc document){
- Entry entry = new Entry(dn);
- translate(document, entry);
- return entry;
+ Error.push("build entry");
+ Error.push(LdapConstant.ATTRIBUTE_DN + "=" + dn);
+ try{
+ Entry entry = new Entry(dn);
+ translate(document, entry);
+ return entry;
+ }
+ finally{
+ Error.pop();
+ Error.pop();
+ }
}
@Override
@@ -74,13 +83,12 @@ else if(type instanceof BinaryType){
}
@Override
- protected void translate(SimpleField field, Path path, JsonNode node, Entry target) {
- String attributeName = fieldNameTranslator.translateFieldName(field.getName());
+ protected void translate(SimpleField field, JsonNode node, Entry target) {
+ String attributeName = fieldNameTranslator.translateFieldName(field.getFullPath());
if(LdapConstant.ATTRIBUTE_DN.equalsIgnoreCase(attributeName)){
- throw new IllegalArgumentException(
- "'dn' should not be included as it's value will be derived from the metadata.basedn and" +
- " the metadata.uniqueattr. Including the 'dn' as an insert attribute is confusing.");
+ //DN is derived using metadata.uniqueattr, providing it is confusing.
+ throw Error.get(MetadataConstants.ERR_INVALID_FIELD_REFERENCE, LdapConstant.ATTRIBUTE_DN);
}
else if(LightblueUtil.isFieldObjectType(attributeName)
|| LightblueUtil.isFieldAnArrayCount(attributeName, getEntityMetadata().getFields())){
@@ -102,15 +110,10 @@ else if(LightblueUtil.isFieldObjectType(attributeName)
}
@Override
- protected void translate(ObjectField field, Path path, JsonNode node, Entry target) {
- throw new UnsupportedOperationException("ObjectField type is not currently supported.");
- }
-
- @Override
- protected void translateSimpleArray(ArrayField field, Path path, List items, Entry target) {
+ protected void translateSimpleArray(ArrayField field, List items, Entry target) {
ArrayElement arrayElement = field.getElement();
Type arrayElementType = arrayElement.getType();
- String attributeName = fieldNameTranslator.translateFieldName(field.getName());
+ String attributeName = fieldNameTranslator.translateFieldName(field.getFullPath());
if(arrayElementType instanceof BinaryType){
List bytes = new ArrayList();
@@ -130,7 +133,7 @@ protected void translateSimpleArray(ArrayField field, Path path, List it
@Override
protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Entry target) {
- throw new UnsupportedOperationException("Object ArrayField type is not currently supported.");
+ throw Error.get(LdapErrorCode.ERR_UNSUPPORTED_FEATURE_OBJECT_ARRAY, field.getFullPath().toString());
}
}
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCRUDController.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCRUDController.java
index fff1427..3048e6a 100644
--- a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCRUDController.java
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCRUDController.java
@@ -29,7 +29,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import com.redhat.lightblue.common.ldap.DBResolver;
import com.redhat.lightblue.common.ldap.LdapConstant;
import com.redhat.lightblue.common.ldap.LdapDataStore;
@@ -44,24 +43,17 @@
import com.redhat.lightblue.crud.CRUDUpdateResponse;
import com.redhat.lightblue.crud.CrudConstants;
import com.redhat.lightblue.crud.DocCtx;
-import com.redhat.lightblue.crud.ldap.model.TrivialLdapFieldNameTranslator;
import com.redhat.lightblue.crud.ldap.translator.FilterTranslator;
import com.redhat.lightblue.crud.ldap.translator.ResultTranslator;
import com.redhat.lightblue.crud.ldap.translator.SortTranslator;
import com.redhat.lightblue.eval.FieldAccessRoleEvaluator;
import com.redhat.lightblue.eval.Projector;
import com.redhat.lightblue.hystrix.ldap.InsertCommand;
-import com.redhat.lightblue.metadata.ArrayField;
import com.redhat.lightblue.metadata.DataStore;
-import com.redhat.lightblue.metadata.EntityInfo;
import com.redhat.lightblue.metadata.EntityMetadata;
import com.redhat.lightblue.metadata.FieldCursor;
-import com.redhat.lightblue.metadata.Fields;
-import com.redhat.lightblue.metadata.Metadata;
+import com.redhat.lightblue.metadata.MetadataConstants;
import com.redhat.lightblue.metadata.MetadataListener;
-import com.redhat.lightblue.metadata.SimpleArrayElement;
-import com.redhat.lightblue.metadata.SimpleField;
-import com.redhat.lightblue.metadata.types.IntegerType;
import com.redhat.lightblue.metadata.types.StringType;
import com.redhat.lightblue.query.Projection;
import com.redhat.lightblue.query.QueryExpression;
@@ -107,10 +99,10 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx,
EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName());
LdapDataStore store = getLdapDataStore(md);
- LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
+ LdapFieldNameTranslator fieldNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md);
FieldAccessRoleEvaluator roles = new FieldAccessRoleEvaluator(md, ctx.getCallerRoles());
- EntryBuilder entryBuilder = new EntryBuilder(md, property);
+ EntryBuilder entryBuilder = new EntryBuilder(md, fieldNameTranslator);
//Create Entry instances for each document.
List entries = new ArrayList();
@@ -125,12 +117,10 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx,
}
}
- JsonNode rootNode = document.getRoot();
-
- String uniqueFieldName = property.translateAttributeName(store.getUniqueAttribute());
- JsonNode uniqueNode = rootNode.get(uniqueFieldName);
+ Path uniqueFieldPath = fieldNameTranslator.translateAttributeName(store.getUniqueAttribute());
+ JsonNode uniqueNode = document.get(uniqueFieldPath);
if(uniqueNode == null){
- throw new IllegalArgumentException(uniqueFieldName + " is a required field");
+ throw Error.get(MetadataConstants.ERR_PARSE_MISSING_ELEMENT, store.getUniqueAttribute());
}
String dn = createDN(store, uniqueNode.asText());
@@ -208,17 +198,17 @@ public CRUDFindResponse find(CRUDOperationContext ctx,
LDAPConnection connection = getNewLdapConnection(store);
- LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
+ LdapFieldNameTranslator fieldNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md);
try {
//TODO: Support scopes other than SUB
SearchRequest request = new SearchRequest(
store.getBaseDN(),
SearchScope.SUB,
- new FilterTranslator(property).translate(query),
- translateFieldNames(property, gatherRequiredFields(md, projection, query, sort)).toArray(new String[0]));
+ new FilterTranslator(fieldNameTranslator).translate(query),
+ translateFieldNames(fieldNameTranslator, gatherRequiredFields(md, projection, query, sort)).toArray(new String[0]));
if(sort != null){
- request.addControl(new ServerSideSortRequestControl(false, new SortTranslator(property).translate(sort)));
+ request.addControl(new ServerSideSortRequestControl(false, new SortTranslator(fieldNameTranslator).translate(sort)));
}
if((from != null) && (from > 0)){
int endPos = to.intValue() - from.intValue();
@@ -228,16 +218,14 @@ public CRUDFindResponse find(CRUDOperationContext ctx,
SearchResult result = connection.search(request);
response.setSize(result.getEntryCount());
- ResultTranslator resultTranslator = new ResultTranslator(ctx.getFactory().getNodeFactory(), md, property);
+ ResultTranslator resultTranslator = new ResultTranslator(ctx.getFactory().getNodeFactory(), md, fieldNameTranslator);
List translatedDocs = new ArrayList();
for(SearchResultEntry entry : result.getSearchEntries()){
try{
translatedDocs.add(resultTranslator.translate(entry));
}
catch(Exception e){
- DocCtx erroredDoc = new DocCtx(null);
- erroredDoc.addError(Error.get(e));
- translatedDocs.add(erroredDoc);
+ ctx.addError(Error.get(e));
}
}
ctx.setDocuments(translatedDocs);
@@ -250,7 +238,7 @@ public CRUDFindResponse find(CRUDOperationContext ctx,
ctx.getCallerRoles()).getExcludedFields(FieldAccessRoleEvaluator.Operation.find)
),
md);
- for (DocCtx document : ctx.getDocuments()) {
+ for (DocCtx document : ctx.getDocumentsWithoutErrors()) {
document.setOutputDocument(projector.project(document, ctx.getFactory().getNodeFactory()));
}
}
@@ -269,43 +257,7 @@ public void updatePredefinedFields(CRUDOperationContext ctx, JsonDoc doc) {
@Override
public MetadataListener getMetadataListener() {
- return new MetadataListener() {
-
- @Override
- public void beforeUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity) {
- //Do Nothing!!
- }
-
- /**
- * Ensure that dn and objectClass are on the entity.
- */
- @Override
- public void beforeCreateNewSchema(Metadata m, EntityMetadata md) {
- LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
-
- Fields fields = md.getEntitySchema().getFields();
- String dnFieldName = property.translateAttributeName(LdapConstant.ATTRIBUTE_DN);
- if(!fields.has(dnFieldName)){
- fields.addNew(new SimpleField(dnFieldName, StringType.TYPE));
- }
-
- String objectClassFieldName = property.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS);
- if(!fields.has(objectClassFieldName)){
- fields.addNew(new ArrayField(objectClassFieldName, new SimpleArrayElement(StringType.TYPE)));
- fields.addNew(new SimpleField(LightblueUtil.createArrayCountFieldName(objectClassFieldName), IntegerType.TYPE));
- }
- }
-
- @Override
- public void afterUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity) {
- //Do Nothing!!
- }
-
- @Override
- public void afterCreateNewSchema(Metadata m, EntityMetadata md) {
- //Do Nothing!!
- }
- };
+ return new LdapMetadataListener();
}
/**
@@ -324,26 +276,6 @@ private LdapDataStore getLdapDataStore(EntityMetadata md){
return (LdapDataStore) store;
}
- /**
- * Shortcut method to get and return the {@link LdapFieldNameTranslator} on the passed
- * in {@link EntityMetadata}.
- * @param md - {@link EntityMetadata}.
- * @return {@link LdapFieldNameTranslator}
- * @throws IllegalArgumentException if an invalid object is found.
- */
- private LdapFieldNameTranslator getLdapFieldNameTranslator(EntityMetadata md){
- Object o = md.getEntityInfo().getProperties().get(LdapConstant.BACKEND);
-
- if(o == null){
- return new TrivialLdapFieldNameTranslator();
- }
-
- if(!(o instanceof LdapFieldNameTranslator)){
- throw new IllegalArgumentException("Object of type " + o.getClass() + " is not supported.");
- }
- return (LdapFieldNameTranslator) o;
- }
-
/**
* Creates and returns a unique DN.
* @param store - {@link LdapDataStore} to use as the BaseDN and field that
@@ -364,9 +296,9 @@ private String createDN(LdapDataStore store, String uniqueValue){
* @param sort - (optional) {@link Sort}.
* @return list of field names.
*/
- private Set gatherRequiredFields(EntityMetadata md,
+ private Set gatherRequiredFields(EntityMetadata md,
Projection projection, QueryExpression query, Sort sort){
- Set fields = new HashSet();
+ Set paths = new HashSet();
FieldCursor cursor = md.getFieldCursor();
while(cursor.next()) {
@@ -381,15 +313,15 @@ private Set gatherRequiredFields(EntityMetadata md,
* Handles the case of an array count field, which will not actually exist in
* the ldap entity.
*/
- fields.add(LightblueUtil.createArrayFieldNameFromCountField(fieldName));
+ paths.add(node.mutableCopy().setLast(LightblueUtil.createArrayFieldNameFromCountField(fieldName)).immutableCopy());
}
else{
- fields.add(fieldName);
+ paths.add(node);
}
}
}
- return fields;
+ return paths;
}
/**
@@ -399,10 +331,10 @@ private Set gatherRequiredFields(EntityMetadata md,
* @param fieldNames - Collection
of fieldNames to translated
* @return Set
of translated attributeNames.
*/
- private Set translateFieldNames(LdapFieldNameTranslator property, Collection fieldNames){
+ private Set translateFieldNames(LdapFieldNameTranslator property, Collection fieldNames){
Set attributes = new HashSet();
- for(String fieldName : fieldNames){
- attributes.add(property.translateFieldName(fieldName));
+ for(Path path : fieldNames){
+ attributes.add(property.translateFieldName(path));
}
return attributes;
@@ -422,9 +354,9 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map
EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName());
JsonNodeFactory factory = ctx.getFactory().getNodeFactory();
- LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
+ LdapFieldNameTranslator fieldNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md);
- Set requiredAttributeNames = translateFieldNames(property, gatherRequiredFields(md, projection, null, null));
+ Set requiredAttributeNames = translateFieldNames(fieldNameTranslator, gatherRequiredFields(md, projection, null, null));
Projector projector = Projector.getInstance(
Projection.add(
projection,
@@ -434,7 +366,7 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map
),
md);
- String dnFieldName = property.translateAttributeName(LdapConstant.ATTRIBUTE_DN);
+ Path dnFieldPath = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN);
for(Entry insertedDn : documentToDnMap.entrySet()){
DocCtx document = insertedDn.getKey();
@@ -443,9 +375,9 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map
// If only dn is in the projection, then no need to query LDAP.
if((requiredAttributeNames.size() == 1) && requiredAttributeNames.contains(LdapConstant.ATTRIBUTE_DN)){
- ObjectNode node = factory.objectNode();
- node.set(dnFieldName, StringType.TYPE.toJson(factory, dn));
- projectionResponseJson = new DocCtx(new JsonDoc(node));
+ JsonDoc jdoc = new JsonDoc(factory.objectNode());
+ jdoc.modify(dnFieldPath, StringType.TYPE.toJson(factory, dn), true);
+ projectionResponseJson = new DocCtx(jdoc);
}
//TODO: else fetch entity from LDAP and project results.
//TODO: Probably want to batch fetch as opposed to individual fetches.
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCrudUtil.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCrudUtil.java
new file mode 100644
index 0000000..4a2cd5e
--- /dev/null
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCrudUtil.java
@@ -0,0 +1,55 @@
+/*
+ Copyright 2015 Red Hat, Inc. and/or its affiliates.
+
+ This file is part of lightblue.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+package com.redhat.lightblue.crud.ldap;
+
+import com.redhat.lightblue.common.ldap.LdapConstant;
+import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
+import com.redhat.lightblue.crud.ldap.model.TrivialLdapFieldNameTranslator;
+import com.redhat.lightblue.metadata.EntityMetadata;
+
+/**
+ * Utility methods for LDAP CRUD operations.
+ *
+ * @author dcrissman
+ */
+public final class LdapCrudUtil {
+
+ /**
+ * Shortcut method to get and return the {@link LdapFieldNameTranslator} on the passed
+ * in {@link EntityMetadata}.
+ * @param md - {@link EntityMetadata}.
+ * @return {@link LdapFieldNameTranslator}
+ * @throws IllegalArgumentException if an invalid object is found.
+ */
+ public static LdapFieldNameTranslator getLdapFieldNameTranslator(EntityMetadata md){
+ Object o = md.getEntityInfo().getProperties().get(LdapConstant.BACKEND);
+
+ if(o == null){
+ return new TrivialLdapFieldNameTranslator();
+ }
+
+ if(!(o instanceof LdapFieldNameTranslator)){
+ throw new IllegalArgumentException("Object of type " + o.getClass() + " is not supported.");
+ }
+ return (LdapFieldNameTranslator) o;
+ }
+
+ private LdapCrudUtil(){}
+
+}
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapMetadataListener.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapMetadataListener.java
new file mode 100644
index 0000000..b71eda0
--- /dev/null
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapMetadataListener.java
@@ -0,0 +1,148 @@
+/*
+ Copyright 2015 Red Hat, Inc. and/or its affiliates.
+
+ This file is part of lightblue.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+package com.redhat.lightblue.crud.ldap;
+
+import com.redhat.lightblue.common.ldap.LdapConstant;
+import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
+import com.redhat.lightblue.metadata.ArrayField;
+import com.redhat.lightblue.metadata.EntityInfo;
+import com.redhat.lightblue.metadata.EntityMetadata;
+import com.redhat.lightblue.metadata.Field;
+import com.redhat.lightblue.metadata.FieldTreeNode;
+import com.redhat.lightblue.metadata.Fields;
+import com.redhat.lightblue.metadata.Metadata;
+import com.redhat.lightblue.metadata.MetadataConstants;
+import com.redhat.lightblue.metadata.MetadataListener;
+import com.redhat.lightblue.metadata.ObjectArrayElement;
+import com.redhat.lightblue.metadata.ObjectField;
+import com.redhat.lightblue.metadata.PredefinedFields;
+import com.redhat.lightblue.metadata.SimpleArrayElement;
+import com.redhat.lightblue.metadata.SimpleField;
+import com.redhat.lightblue.metadata.types.StringType;
+import com.redhat.lightblue.util.Error;
+import com.redhat.lightblue.util.Path;
+
+/**
+ * Implementation of {@link MetadataListener} for LDAP.
+ *
+ * @author dcrissman
+ */
+public class LdapMetadataListener implements MetadataListener{
+
+ @Override
+ public void beforeUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity) {
+ //Do Nothing!!
+ }
+
+ @Override
+ public void afterUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity) {
+ //Do Nothing!!
+ }
+
+ @Override
+ public void afterCreateNewSchema(Metadata m, EntityMetadata md) {
+ //Do Nothing!!
+ }
+
+ /**
+ * Ensure that dn and objectClass are on the entity.
+ */
+ @Override
+ public void beforeCreateNewSchema(Metadata m, EntityMetadata md) {
+ LdapFieldNameTranslator ldapNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md);
+ //TODO: check for array index or Path.any
+
+ ensureDnField(md, ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN));
+
+ ensureObjectClassField(md,
+ ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS));
+
+ PredefinedFields.ensurePredefinedFields(md);
+ }
+
+ /**
+ * Ensures the objectClass field is present on the entity. If not, then it will added. If so, but
+ * is defined incorrectly, then an {@link Error} will be thrown.
+ */
+ private void ensureObjectClassField(EntityMetadata md, Path objectClassFieldPath) {
+ FieldTreeNode objectClassNode;
+ try{
+ objectClassNode = md.resolve(objectClassFieldPath);
+ }
+ catch(Error e){
+ addFieldToParent(md, objectClassFieldPath,
+ (Field) (objectClassNode = new ArrayField(objectClassFieldPath.getLast(), new SimpleArrayElement(StringType.TYPE))));
+ }
+ if(!(objectClassNode instanceof ArrayField)){
+ throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassNode.getFullPath().toString());
+ }
+ ArrayField objectClassField = (ArrayField) objectClassNode;
+ if(!(objectClassField.getElement().getType() instanceof StringType)){
+ throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassField.getFullPath().toString());
+ }
+ }
+
+ /**
+ * Ensures the dn field is present on the entity. If not, then it will added. If so, but
+ * is defined incorrectly, then an {@link Error} will be thrown.
+ */
+ private void ensureDnField(EntityMetadata md, Path dnFieldPath) {
+ FieldTreeNode dnNode;
+ try{
+ dnNode = md.resolve(dnFieldPath);
+ }
+ catch(Error e){
+ addFieldToParent(md, dnFieldPath,
+ (Field)(dnNode = new SimpleField(dnFieldPath.getLast(), StringType.TYPE)));
+ }
+ if(!(dnNode.getType() instanceof StringType)){
+ throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, dnNode.getFullPath().toString());
+ }
+ }
+
+ /**
+ * Adds the newField to the newFieldPath
.
+ * @param md - {@link EntityMetadata}
+ * @param newFieldPath - {@link Path} to add
+ * @param newField - {@link Field} to add at the newFieldPath
+ */
+ private void addFieldToParent(EntityMetadata md, Path newFieldPath, Field newField){
+ Fields fields;
+
+ if(newFieldPath.numSegments() == 1){
+ fields = md.getFields();
+ }
+ else{
+ Path parentPath = newFieldPath.prefix(-1);
+ FieldTreeNode parent = md.resolve(parentPath);
+
+ if(parent instanceof ObjectField){
+ fields = ((ObjectField) parent).getFields();
+ }
+ else if (parent instanceof ObjectArrayElement){
+ fields = ((ObjectArrayElement) parent).getFields();
+ }
+ else {
+ throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, parentPath.toString());
+ }
+ }
+ fields.addNew(newField);
+ }
+
+}
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/TranslatorFromJson.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/TranslatorFromJson.java
index d5fc04d..d6f02b5 100644
--- a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/TranslatorFromJson.java
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/TranslatorFromJson.java
@@ -23,19 +23,21 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NullNode;
+import com.redhat.lightblue.common.ldap.LdapErrorCode;
import com.redhat.lightblue.metadata.ArrayElement;
import com.redhat.lightblue.metadata.ArrayField;
import com.redhat.lightblue.metadata.EntityMetadata;
import com.redhat.lightblue.metadata.FieldTreeNode;
+import com.redhat.lightblue.metadata.MetadataConstants;
import com.redhat.lightblue.metadata.ObjectArrayElement;
import com.redhat.lightblue.metadata.ObjectField;
import com.redhat.lightblue.metadata.ReferenceField;
import com.redhat.lightblue.metadata.SimpleArrayElement;
import com.redhat.lightblue.metadata.SimpleField;
import com.redhat.lightblue.metadata.Type;
+import com.redhat.lightblue.util.Error;
import com.redhat.lightblue.util.JsonDoc;
import com.redhat.lightblue.util.JsonNodeCursor;
-import com.redhat.lightblue.util.Path;
/**
* Defines a class that translates lightblue json nodes into
@@ -45,6 +47,8 @@
*
* @param - A entity that the specific datastore knows how
* to interact with.
+ *
+ * @see #translate(JsonDoc, Object)
*/
public abstract class TranslatorFromJson {
@@ -54,7 +58,7 @@ public TranslatorFromJson(EntityMetadata md){
this.md = md;
}
- protected EntityMetadata getEntityMetadata(){
+ public EntityMetadata getEntityMetadata(){
return md;
}
@@ -67,7 +71,12 @@ protected Object fromJson(Type type, JsonNode node){
}
}
- protected void translate(JsonDoc document, T target){
+ /**
+ * Translates an entire {@link JsonDoc} to T.
+ * @param document - {@link JsonDoc}
+ * @param target - T
+ */
+ public void translate(JsonDoc document, T target){
JsonNodeCursor cursor = document.cursor();
if (!cursor.firstChild()) {
//TODO throw exception?
@@ -79,36 +88,44 @@ protected void translate(JsonDoc document, T target){
} while (cursor.nextSibling());
}
- private void translate(JsonNodeCursor cursor, T target){
- Path path = cursor.getCurrentPath();
+ /**
+ * Uses the current position of the cursor to translate the current node and any children it may have.
+ * This is ultimately the driver behind this class and may be called recursively by implementing classes to process child nodes.
+ * NOTE: Calling method is responsible for moving the cursor to where it needs to be.
+ * @param cursor - {@link JsonNodeCursor}
+ * @param target - T
+ */
+ protected void translate(JsonNodeCursor cursor, T target){
JsonNode node = cursor.getCurrentNode();
- FieldTreeNode fieldNode = md.resolve(path);
-
- if (fieldNode == null) {
- throw new NullPointerException("No Metadata field found for: " + path.toString());
- }
-
- if (fieldNode instanceof SimpleField) {
- translate((SimpleField) fieldNode, path, node, target);
- }
- else if (fieldNode instanceof ObjectField) {
- translate((ObjectField) fieldNode, path, node, target);
+ FieldTreeNode fieldNode = md.resolve(cursor.getCurrentPath());
+
+ Error.push(fieldNode.getFullPath().getLast());
+
+ try{
+ if (fieldNode instanceof SimpleField) {
+ translate((SimpleField) fieldNode, node, target);
+ }
+ else if (fieldNode instanceof ObjectField) {
+ translate((ObjectField) fieldNode, cursor, target);
+ }
+ else if (fieldNode instanceof ArrayField) {
+ translate((ArrayField) fieldNode, cursor, target);
+ }
+ else if (fieldNode instanceof ReferenceField) {
+ translate((ReferenceField) fieldNode, node, target);
+ }
+ else{
+ throw Error.get(LdapErrorCode.ERR_UNSUPPORTED_FEATURE + fieldNode.getClass().getName(), fieldNode.getFullPath().toString());
+ }
}
- else if (fieldNode instanceof ArrayField) {
- translate((ArrayField) fieldNode, cursor, path, target);
- }
- else if (fieldNode instanceof ReferenceField) {
- translate((ReferenceField) fieldNode, path, node, target);
- }
- else{
- throw new UnsupportedOperationException("Field type is not supported: " + fieldNode.getClass().getName());
+ finally{
+ Error.pop();
}
}
- private void translate(ArrayField field, JsonNodeCursor cursor, Path path, T target){
+ private void translate(ArrayField field, JsonNodeCursor cursor, T target){
if(!cursor.firstChild()){
- //TODO: throw exception?
- return;
+ throw Error.get(MetadataConstants.ERR_ILL_FORMED_METADATA, cursor.getCurrentPath().toString());
}
ArrayElement arrayElement = field.getElement();
@@ -118,25 +135,36 @@ private void translate(ArrayField field, JsonNodeCursor cursor, Path path, T tar
do {
items.add(fromJson(arrayElement.getType(), cursor.getCurrentNode()));
} while (cursor.nextSibling());
- translateSimpleArray(field, path, items, target);
+ translateSimpleArray(field, items, target);
}
else if(arrayElement instanceof ObjectArrayElement){
translateObjectArray(field, cursor, target);
}
else{
- throw new UnsupportedOperationException("ArrayElement type is not supported: " + arrayElement.getClass().getName());
+ throw Error.get(LdapErrorCode.ERR_UNSUPPORTED_FEATURE + arrayElement.getClass().getName(), field.getFullPath().toString());
}
cursor.parent();
}
- protected void translate(ReferenceField field, Path path, JsonNode node, T target){
+ protected void translate(ObjectField field, JsonNodeCursor cursor, T target){
+ if(!cursor.firstChild()){
+ throw Error.get(MetadataConstants.ERR_ILL_FORMED_METADATA, cursor.getCurrentPath().toString());
+ }
+
+ do {
+ translate(cursor, target);
+ } while (cursor.nextSibling());
+
+ cursor.parent();
+ }
+
+ protected void translate(ReferenceField field, JsonNode node, T target){
//Do nothing by default!
}
- protected abstract void translate(SimpleField field, Path path, JsonNode node, T target);
- protected abstract void translate(ObjectField field, Path path, JsonNode node, T target);
- protected abstract void translateSimpleArray(ArrayField field, Path path, List items, T target);
+ protected abstract void translate(SimpleField field, JsonNode node, T target);
+ protected abstract void translateSimpleArray(ArrayField field, List items, T target);
protected abstract void translateObjectArray(ArrayField field, JsonNodeCursor cursor, T target);
}
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslator.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslator.java
index 3ac4008..577e36c 100644
--- a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslator.java
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslator.java
@@ -19,6 +19,7 @@
package com.redhat.lightblue.crud.ldap.model;
import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
+import com.redhat.lightblue.util.Path;
/**
* An implementation of {@link LdapFieldNameTranslator} used by crud when
@@ -29,13 +30,13 @@
public class TrivialLdapFieldNameTranslator implements LdapFieldNameTranslator{
@Override
- public String translateFieldName(String fieldName) {
- return fieldName;
+ public String translateFieldName(Path path) {
+ return path.getLast();
}
@Override
- public String translateAttributeName(String attributeName) {
- return attributeName;
+ public Path translateAttributeName(String attributeName) {
+ return new Path(attributeName);
}
}
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/FilterTranslator.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/FilterTranslator.java
index 58c922b..e027be2 100644
--- a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/FilterTranslator.java
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/FilterTranslator.java
@@ -86,7 +86,7 @@ else if (query instanceof ValueComparisonExpression){
}
private Filter translate(ArrayContainsExpression query){
- String attributeName = fieldNameTranslator.translateFieldName(query.getArray().toString());
+ String attributeName = fieldNameTranslator.translateFieldName(query.getArray());
List filters = new ArrayList();
for(Value value : query.getValues()){
@@ -131,7 +131,7 @@ private Filter translate(NaryLogicalExpression query){
}
private Filter translate(NaryRelationalExpression query){
- String attributeName = fieldNameTranslator.translateFieldName(query.getField().toString());
+ String attributeName = fieldNameTranslator.translateFieldName(query.getField());
List filters = new ArrayList();
for(Value value : query.getValues()){
filters.add(Filter.createEqualityFilter(attributeName, value.getValue().toString()));
@@ -162,7 +162,7 @@ private Filter translate(UnaryLogicalExpression query){
}
private Filter translate(ValueComparisonExpression query){
- String attributeName = fieldNameTranslator.translateFieldName(query.getField().toString());
+ String attributeName = fieldNameTranslator.translateFieldName(query.getField());
String rValue = query.getRvalue().getValue().toString();
switch(query.getOp()){
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslator.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslator.java
index 797a831..c6dd5b1 100644
--- a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslator.java
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslator.java
@@ -26,11 +26,13 @@
import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
import com.redhat.lightblue.common.ldap.LightblueUtil;
import com.redhat.lightblue.crud.DocCtx;
+import com.redhat.lightblue.metadata.ArrayElement;
import com.redhat.lightblue.metadata.ArrayField;
import com.redhat.lightblue.metadata.EntityMetadata;
import com.redhat.lightblue.metadata.FieldCursor;
import com.redhat.lightblue.metadata.FieldTreeNode;
import com.redhat.lightblue.metadata.Fields;
+import com.redhat.lightblue.metadata.ObjectArrayElement;
import com.redhat.lightblue.metadata.ObjectField;
import com.redhat.lightblue.metadata.ReferenceField;
import com.redhat.lightblue.metadata.SimpleArrayElement;
@@ -41,6 +43,7 @@
import com.redhat.lightblue.metadata.types.IntegerType;
import com.redhat.lightblue.metadata.types.StringType;
import com.redhat.lightblue.util.JsonDoc;
+import com.redhat.lightblue.util.Path;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.SearchResultEntry;
@@ -54,79 +57,93 @@ public class ResultTranslator {
private final JsonNodeFactory factory;
private final EntityMetadata md;
private final LdapFieldNameTranslator fieldNameTranslator;
+ private final Path dnPath;
public ResultTranslator(JsonNodeFactory factory, EntityMetadata md, LdapFieldNameTranslator fieldNameTranslator){
this.factory = factory;
this.md = md;
this.fieldNameTranslator = fieldNameTranslator;
+ dnPath = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN);
}
public DocCtx translate(SearchResultEntry entry){
FieldCursor cursor = md.getFieldCursor();
- String entityName = md.getEntityInfo().getName();
Fields fields = md.getFields();
+
if (cursor.firstChild()) {
- return new DocCtx(new JsonDoc(toJson(entry, cursor, entityName, fields)));
+ JsonDoc jdoc = new JsonDoc(toJson(entry, cursor, fields));
+ jdoc.modify(dnPath, StringType.TYPE.toJson(factory, entry.getDN()), true);
+ return new DocCtx(jdoc);
}
//TODO: What to do in case of a null value here?
return null;
}
- private JsonNode toJson(SearchResultEntry entry, FieldCursor fieldCursor, String entityName, Fields fields){
+ private ObjectNode toJson(SearchResultEntry entry, FieldCursor fieldCursor, Fields fields){
ObjectNode node = factory.objectNode();
- String dnFieldName = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN);
+ String entityName = md.getEntityInfo().getName();
do {
- FieldTreeNode field = fieldCursor.getCurrentNode();
- String fieldName = field.getName();
- if(LightblueUtil.isFieldAnArrayCount(fieldName, fields)){
- /*
- * This case will be handled by the array itself, allowing this to
- * process runs the risk of nulling out the correct value.
- */
- continue;
- }
- else if(dnFieldName.equalsIgnoreCase(fieldName)){
+ Path fieldPath = fieldCursor.getCurrentPath();
+
+ if(dnPath.equals(fieldPath)){
//DN is not handled as a normal attribute, can be skipped.
continue;
}
-
- String attributeName = fieldNameTranslator.translateFieldName(fieldName);
- Attribute attr = entry.getAttribute(attributeName);
-
- JsonNode value = null;
- if(attr != null){
- if (field instanceof SimpleField) {
- value = toJson((SimpleField)field, attr);
- }
- else if (field instanceof ObjectField) {
- value = toJson((ObjectField)field, attr);
- }
- else if (field instanceof ArrayField){
- value = toJson((ArrayField)field, attr, fieldCursor);
- node.set(
- LightblueUtil.createArrayCountFieldName(fieldName),
- IntegerType.TYPE.toJson(factory, attr.getValues().length));
- }
- else if (field instanceof ReferenceField) {
- value = toJson((ReferenceField)field, attr);
- }
- else{
- throw new UnsupportedOperationException("Unknown Field type: " + field.getClass().getName());
- }
+ else if(LightblueUtil.isFieldObjectType(fieldPath.toString())){
+ node.set(fieldPath.toString(), StringType.TYPE.toJson(factory, entityName));
}
- else if(LightblueUtil.isFieldObjectType(fieldName)){
- value = StringType.TYPE.toJson(factory, entityName);
+ else{
+ appendToJsonNode(entry, fieldCursor, node, fields);
}
- node.set(fieldName, value);
} while(fieldCursor.nextSibling());
- node.set(dnFieldName, StringType.TYPE.toJson(factory, entry.getDN()));
return node;
}
+ private void appendToJsonNode(SearchResultEntry entry, FieldCursor fieldCursor, ObjectNode targetNode, Fields fields){
+ FieldTreeNode field = fieldCursor.getCurrentNode();
+ String fieldName = field.getName();
+ Path path = fieldCursor.getCurrentPath();
+
+ String attributeName = fieldNameTranslator.translateFieldName(path);
+ Attribute attr = entry.getAttribute(attributeName);
+
+ JsonNode value = null;
+
+ if(LightblueUtil.isFieldAnArrayCount(fieldName, fields)){
+ /*
+ * This case will be handled by the array itself, allowing this to
+ * process runs the risk of nulling out the correct value.
+ */
+ return;
+ }
+ else if (field instanceof ObjectField) {
+ value = toJson((ObjectField)field, fieldCursor, entry);
+ }
+ else if(attr != null){
+ if (field instanceof SimpleField) {
+ value = toJson((SimpleField)field, attr);
+ }
+ else if (field instanceof ArrayField){
+ value = toJson((ArrayField)field, attr, fieldCursor);
+ targetNode.set(
+ LightblueUtil.createArrayCountFieldName(fieldName),
+ IntegerType.TYPE.toJson(factory, attr.getValues().length));
+ }
+ else if (field instanceof ReferenceField) {
+ value = toJson((ReferenceField)field, attr);
+ }
+ else{
+ throw new UnsupportedOperationException("Unknown Field type: " + field.getClass().getName());
+ }
+ }
+
+ targetNode.set(fieldName, value);
+ }
+
private JsonNode toJson(SimpleField field, Attribute attr){
Type type = field.getType();
@@ -148,28 +165,41 @@ else if(type instanceof BinaryType){
return field.getType().toJson(factory, value);
}
- private JsonNode toJson(ObjectField field, Attribute attr){
- throw new UnsupportedOperationException("ObjectField type not currently supported.");
+ private JsonNode toJson(ObjectField field, FieldCursor fieldCursor, SearchResultEntry entry){
+ if(!fieldCursor.firstChild()){
+ //TODO: Should an exception be thrown here?
+ return null;
+ }
+
+ JsonNode node = toJson(entry, fieldCursor, field.getFields());
+
+ fieldCursor.parent();
+
+ return node;
}
private JsonNode toJson(ArrayField field, Attribute attr, FieldCursor fieldCursor){
if(!fieldCursor.firstChild()){
+ //TODO: Should an exception be thrown here?
return null;
}
- String[] values = attr.getValues();
FieldTreeNode node = fieldCursor.getCurrentNode();
- if(!(node instanceof SimpleArrayElement)){
- throw new UnsupportedOperationException("ArrayElement type is not supported: " + node.getClass().getName());
- }
-
- //TODO: Determine if LDAP would support an ObjectArrayElement
-
+ ArrayElement arrayElement = field.getElement();
ArrayNode valueNode = factory.arrayNode();
- for(String value : values){
- valueNode.add(node.getType().toJson(factory, value));
+ if (arrayElement instanceof SimpleArrayElement) {
+ String[] values = attr.getValues();
+ for(String value : values){
+ valueNode.add(node.getType().toJson(factory, value));
+ }
+ }
+ else if(arrayElement instanceof ObjectArrayElement){
+ throw new UnsupportedOperationException("Object ArrayField type is not currently supported.");
+ }
+ else{
+ throw new UnsupportedOperationException("ArrayElement type is not supported: " + node.getClass().getName());
}
fieldCursor.parent();
diff --git a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/SortTranslator.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/SortTranslator.java
index ecf2745..b4d5993 100644
--- a/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/SortTranslator.java
+++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/SortTranslator.java
@@ -58,7 +58,7 @@ private void doTranslate(Sort sort, List data() {
});
}
+ @After
+ public void after(){
+ Error.reset();
+ }
+
private final String fieldName = "testfield";
private final String metadataType;
private final String crudValue;
diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapCrudUtilTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapCrudUtilTest.java
new file mode 100644
index 0000000..78435fb
--- /dev/null
+++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapCrudUtilTest.java
@@ -0,0 +1,88 @@
+/*
+ Copyright 2015 Red Hat, Inc. and/or its affiliates.
+
+ This file is part of lightblue.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+package com.redhat.lightblue.crud.ldap;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.redhat.lightblue.common.ldap.LdapConstant;
+import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
+import com.redhat.lightblue.crud.ldap.model.TrivialLdapFieldNameTranslator;
+import com.redhat.lightblue.metadata.EntityMetadata;
+import com.redhat.lightblue.util.Path;
+
+public class LdapCrudUtilTest {
+
+ public static EntityMetadata createTestEntityMetadataWithLdapProperty(Object property){
+ EntityMetadata md = new EntityMetadata("fake");
+ md.getEntityInfo().getProperties().put(LdapConstant.BACKEND, property);
+
+ return md;
+ }
+
+ /**
+ * Should return an instance of {@link TrivialLdapFieldNameTranslator}
+ * because the "ldap" property does not exist, ergo no translations.
+ */
+ @Test
+ public void testGetLdapFieldNameTranslator_NoProperties(){
+ EntityMetadata md = new EntityMetadata("fake");
+
+ LdapFieldNameTranslator translator = LdapCrudUtil.getLdapFieldNameTranslator(md);
+ assertNotNull(translator);
+ assertTrue(translator instanceof TrivialLdapFieldNameTranslator);
+ }
+
+ /**
+ * An "ldap" property does exist, but the specific implementation is not visible here.
+ */
+ @Test
+ public void testGetLdapFieldNameTranslator(){
+ EntityMetadata md = createTestEntityMetadataWithLdapProperty(new FakeLdapFieldNameTranslator());
+
+ LdapFieldNameTranslator translator = LdapCrudUtil.getLdapFieldNameTranslator(md);
+ assertNotNull(translator);
+ assertTrue(LdapCrudUtil.getLdapFieldNameTranslator(md) instanceof FakeLdapFieldNameTranslator);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetLdapFieldNameTranslator_NotInstanceofLdapFieldNameTranslator(){
+ EntityMetadata md = createTestEntityMetadataWithLdapProperty(new Object());
+
+ LdapCrudUtil.getLdapFieldNameTranslator(md);
+ }
+
+ /** Fake implementation of {@link LdapFieldNameTranslator} for testing purposes. */
+ private static final class FakeLdapFieldNameTranslator implements LdapFieldNameTranslator{
+
+ @Override
+ public String translateFieldName(Path path) {
+ throw new UnsupportedOperationException("method does nothing.");
+ }
+
+ @Override
+ public Path translateAttributeName(String attributeName) {
+ throw new UnsupportedOperationException("method does nothing.");
+ }
+
+ }
+
+}
diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapMetadataListenerTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapMetadataListenerTest.java
new file mode 100644
index 0000000..351ab05
--- /dev/null
+++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapMetadataListenerTest.java
@@ -0,0 +1,232 @@
+/*
+ Copyright 2015 Red Hat, Inc. and/or its affiliates.
+
+ This file is part of lightblue.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+package com.redhat.lightblue.crud.ldap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.redhat.lightblue.common.ldap.LdapConstant;
+import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
+import com.redhat.lightblue.metadata.ArrayField;
+import com.redhat.lightblue.metadata.EntityMetadata;
+import com.redhat.lightblue.metadata.Fields;
+import com.redhat.lightblue.metadata.ObjectArrayElement;
+import com.redhat.lightblue.metadata.ObjectField;
+import com.redhat.lightblue.metadata.SimpleArrayElement;
+import com.redhat.lightblue.metadata.SimpleField;
+import com.redhat.lightblue.metadata.types.IntegerType;
+import com.redhat.lightblue.metadata.types.StringType;
+import com.redhat.lightblue.util.Error;
+import com.redhat.lightblue.util.Path;
+
+public class LdapMetadataListenerTest {
+
+ /**
+ * No fields are defined, so ensure the fields are automatically created.
+ */
+ @Test
+ public void testBeforeCreateNewSchema(){
+ EntityMetadata md = new EntityMetadata("fake");
+
+ LdapMetadataListener listener = new LdapMetadataListener();
+ listener.beforeCreateNewSchema(null, md);
+
+ assertTrue(md.getFields().has(LdapConstant.ATTRIBUTE_DN));
+ assertTrue(md.getFields().has(LdapConstant.ATTRIBUTE_OBJECT_CLASS));
+ assertTrue(md.getFields().has(LdapConstant.ATTRIBUTE_OBJECT_CLASS + "#"));
+ }
+
+ /**
+ * The fields that were defined should remain.
+ */
+ @Test
+ public void testBeforeCreateNewSchema_alreadyHasDefinedDnAndObjectClass(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ SimpleField dnField = new SimpleField(LdapConstant.ATTRIBUTE_DN, StringType.TYPE);
+ fields.addNew(dnField);
+ ArrayField objectClassField = new ArrayField(LdapConstant.ATTRIBUTE_OBJECT_CLASS, new SimpleArrayElement(StringType.TYPE));
+ fields.addNew(objectClassField);
+ SimpleField objectClassCountField = new SimpleField(LdapConstant.ATTRIBUTE_OBJECT_CLASS + "#", IntegerType.TYPE);
+ fields.addNew(objectClassCountField);
+
+ LdapMetadataListener listener = new LdapMetadataListener();
+ listener.beforeCreateNewSchema(null, md);
+
+ assertTrue(md.getFields().has(LdapConstant.ATTRIBUTE_DN));
+ assertTrue(md.getFields().has(LdapConstant.ATTRIBUTE_OBJECT_CLASS));
+ assertTrue(md.getFields().has(LdapConstant.ATTRIBUTE_OBJECT_CLASS + "#"));
+
+ assertEquals(dnField, md.getFields().getField(LdapConstant.ATTRIBUTE_DN));
+ assertEquals(objectClassField, md.getFields().getField(LdapConstant.ATTRIBUTE_OBJECT_CLASS));
+ assertEquals(objectClassCountField, md.getFields().getField(LdapConstant.ATTRIBUTE_OBJECT_CLASS + "#"));
+ }
+
+ /**
+ * This ensures that if the DN is defined within an object in the metadata that the method
+ * continues to work as expected.
+ */
+ @Test
+ public void testBeforeCreateNewSchema_DnInObject(){
+ String fieldName = "someobject." + LdapConstant.ATTRIBUTE_DN;
+
+ EntityMetadata md = LdapCrudUtilTest.createTestEntityMetadataWithLdapProperty(
+ new FakeLdapFieldNameTranslator(fieldName, LdapConstant.ATTRIBUTE_DN));
+ md.getFields().addNew(new ObjectField("someobject"));
+
+ LdapMetadataListener listener = new LdapMetadataListener();
+ listener.beforeCreateNewSchema(null, md);
+
+ assertNotNull(md.resolve(new Path(fieldName)));
+ }
+
+ /**
+ * This ensures that if the DN is defined within an object in the metadata that the method
+ * continues to work as expected.
+ */
+ @Test
+ public void testBeforeCreateNewSchema_ObjectClassAndCountInObject(){
+ String fieldName = "someobject." + LdapConstant.ATTRIBUTE_OBJECT_CLASS;
+
+ EntityMetadata md = LdapCrudUtilTest.createTestEntityMetadataWithLdapProperty(
+ new FakeLdapFieldNameTranslator(fieldName, LdapConstant.ATTRIBUTE_OBJECT_CLASS));
+ md.getFields().addNew(new ObjectField("someobject"));
+
+ LdapMetadataListener listener = new LdapMetadataListener();
+ listener.beforeCreateNewSchema(null, md);
+
+ assertNotNull(md.resolve(new Path(fieldName)));
+ assertNotNull(md.resolve(new Path(fieldName + "# ")));
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedDn_butAsWrongType(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ fields.addNew(new SimpleField(LdapConstant.ATTRIBUTE_DN, IntegerType.TYPE));
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedDn_butAsWrongField(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ fields.addNew(new ArrayField(LdapConstant.ATTRIBUTE_DN));
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedObjectClass_butAsWrongType(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ fields.addNew(new SimpleField(LdapConstant.ATTRIBUTE_OBJECT_CLASS, StringType.TYPE));
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedObjectClass_butAsWrongField(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ fields.addNew(new SimpleField(LdapConstant.ATTRIBUTE_OBJECT_CLASS));
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedObjectClass_butWithWrongElementType(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ fields.addNew(new ArrayField(LdapConstant.ATTRIBUTE_OBJECT_CLASS, new SimpleArrayElement(IntegerType.TYPE)));
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedObjectClass_butWithWrongElementField(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ ArrayField field = new ArrayField(LdapConstant.ATTRIBUTE_OBJECT_CLASS, new ObjectArrayElement());
+ fields.addNew(field);
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedObjectClassCount_butAsWrongType(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ fields.addNew(new SimpleField(LdapConstant.ATTRIBUTE_OBJECT_CLASS + "#", StringType.TYPE));
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ @Test(expected = Error.class)
+ public void testBeforeCreateNewSchema_alreadyHasDefinedObjectClassCount_butAsWrongField(){
+ EntityMetadata md = new EntityMetadata("fake");
+ Fields fields = md.getEntitySchema().getFields();
+
+ fields.addNew(new ArrayField(LdapConstant.ATTRIBUTE_OBJECT_CLASS + "#"));
+
+ new LdapMetadataListener().beforeCreateNewSchema(null, md);
+ }
+
+ /** Fake implementation of {@link LdapFieldNameTranslator} for testing purposes. */
+ private static final class FakeLdapFieldNameTranslator implements LdapFieldNameTranslator{
+
+ private final String fieldName;
+ private final String attributeName;
+
+ public FakeLdapFieldNameTranslator(String fieldName, String attributeName){
+ this.fieldName = fieldName;
+ this.attributeName = attributeName;
+ }
+
+ @Override
+ public String translateFieldName(Path path) {
+ if(fieldName.equals(path.toString())){
+ return attributeName;
+ }
+ return path.toString();
+ }
+
+ @Override
+ public Path translateAttributeName(String attributeName) {
+ if(this.attributeName.equals(attributeName)) {
+ return new Path(fieldName);
+ }
+ return new Path(attributeName);
+ }
+
+ }
+
+}
diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslatorTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslatorTest.java
index 34f96b9..397d2c5 100644
--- a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslatorTest.java
+++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/model/TrivialLdapFieldNameTranslatorTest.java
@@ -22,18 +22,20 @@
import org.junit.Test;
+import com.redhat.lightblue.util.Path;
+
public class TrivialLdapFieldNameTranslatorTest {
@Test
public void testTranslateFieldName(){
String fieldName = "fakeFieldName";
- assertEquals(fieldName, new TrivialLdapFieldNameTranslator().translateFieldName(fieldName));
+ assertEquals(fieldName, new TrivialLdapFieldNameTranslator().translateFieldName(new Path(fieldName)));
}
@Test
public void testTranslateAttributeName(){
String attributeName = "fakeAttributeName";
- assertEquals(attributeName, new TrivialLdapFieldNameTranslator().translateAttributeName(attributeName));
+ assertEquals(attributeName, new TrivialLdapFieldNameTranslator().translateAttributeName(attributeName).toString());
}
}
diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslatorTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslatorTest.java
index 4fe3c1a..7c5f2b0 100644
--- a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslatorTest.java
+++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslatorTest.java
@@ -378,15 +378,23 @@ public FieldTreeNode resolve(Path p, int level) {
new ResultTranslator(factory, md, new TrivialLdapFieldNameTranslator()).translate(result);
}
- @Test(expected = UnsupportedOperationException.class)
+ @Test
public void testTranslate_ObjectField() throws JSONException{
- SearchResultEntry result = new SearchResultEntry(-1, "uid=john.doe,dc=example,dc=com", new Attribute[]{new Attribute("fake")});
+ SearchResultEntry result = new SearchResultEntry(-1, "uid=john.doe,dc=example,dc=com", new Attribute[]{new Attribute("key", "value")});
- EntityMetadata md = fakeEntityMetadata("fakeMetadata",
- new ObjectField("fake")
- );
+ ObjectField objectField = new ObjectField("fakeObject");
+ objectField.getFields().addNew(new SimpleField("key", StringType.TYPE));
- new ResultTranslator(factory, md, new TrivialLdapFieldNameTranslator()).translate(result);
+ EntityMetadata md = fakeEntityMetadata("fakeMetadata", objectField);
+
+ DocCtx document = new ResultTranslator(factory, md, new TrivialLdapFieldNameTranslator()).translate(result);
+
+ assertNotNull(document);
+
+ JSONAssert.assertEquals(
+ "{\"dn\":\"uid=john.doe,dc=example,dc=com\",\"fakeObject\":{\"key\":\"value\"}}",
+ document.getOutputDocument().toString(),
+ true);
}
@Test(expected = UnsupportedOperationException.class)
diff --git a/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/AbstractLdapCRUDController.java b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/AbstractLdapCRUDController.java
index 4297863..564b988 100644
--- a/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/AbstractLdapCRUDController.java
+++ b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/AbstractLdapCRUDController.java
@@ -22,10 +22,11 @@
import static com.redhat.lightblue.util.test.AbstractJsonNodeTest.loadJsonNode;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.rules.ErrorCollector;
+import org.junit.runners.model.MultipleFailureException;
import com.fasterxml.jackson.databind.JsonNode;
import com.redhat.lightblue.DataError;
@@ -41,22 +42,29 @@ public abstract class AbstractLdapCRUDController extends AbstractCRUDController{
@ClassRule
public static LdapServerExternalResource ldapServer = LdapServerExternalResource.createDefaultInstance();
- @Rule
- public ErrorCollector errorCollector = new ErrorCollector();
-
- protected void assertNoErrors(Response response){
+ protected void assertNoErrors(Response response) throws MultipleFailureException{
+ List errors = new ArrayList();
for(Error error : response.getErrors()){
Exception e = new Exception(error.getMessage(), error);
e.printStackTrace();
- errorCollector.addError(e);
+ errors.add(e);
+ }
+
+ if(!errors.isEmpty()){
+ throw new MultipleFailureException(errors);
}
}
- protected void assertNoDataErrors(Response response){
+ protected void assertNoDataErrors(Response response) throws MultipleFailureException{
+ List errors = new ArrayList();
for(DataError error : response.getDataErrors()){
Exception e = new Exception("DataError: " + error.toJson().toString());
e.printStackTrace();
- errorCollector.addError(e);
+ errors.add(e);
+ }
+
+ if(!errors.isEmpty()){
+ throw new MultipleFailureException(errors);
}
}
diff --git a/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDControllerTest.java b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDControllerTest.java
index dcd41d8..cd47dba 100644
--- a/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDControllerTest.java
+++ b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDControllerTest.java
@@ -55,11 +55,11 @@ public class ITCaseLdapCRUDControllerTest extends AbstractLdapCRUDController{
@BeforeClass
public static void beforeClass() throws Exception {
- ldapServer.add("ou=Users,dc=example,dc=com", new Attribute[]{
+ ldapServer.add(BASEDB_USERS, new Attribute[]{
new Attribute("objectClass", "top"),
new Attribute("objectClass", "organizationalUnit"),
new Attribute("ou", "Users")});
- ldapServer.add("ou=Departments,dc=example,dc=com", new Attribute[]{
+ ldapServer.add(BASEDB_DEPARTMENTS, new Attribute[]{
new Attribute("objectClass", "top"),
new Attribute("objectClass", "organizationalUnit"),
new Attribute("ou", "Departments")});
diff --git a/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_Objects_Test.java b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_Objects_Test.java
new file mode 100644
index 0000000..a1c4653
--- /dev/null
+++ b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_Objects_Test.java
@@ -0,0 +1,96 @@
+/*
+ Copyright 2015 Red Hat, Inc. and/or its affiliates.
+
+ This file is part of lightblue.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+package com.redhat.lightblue.crud.ldap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.redhat.lightblue.Response;
+import com.redhat.lightblue.crud.FindRequest;
+import com.redhat.lightblue.crud.InsertionRequest;
+import com.redhat.lightblue.ldap.test.LdapServerExternalResource;
+import com.redhat.lightblue.mongo.test.MongoServerExternalResource;
+import com.unboundid.ldap.sdk.Attribute;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ITCaseLdapCRUDController_Objects_Test extends AbstractLdapCRUDController{
+
+ private static final String BASEDB_USERS = "ou=Users,dc=example,dc=com";
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ ldapServer.add(BASEDB_USERS, new Attribute[]{
+ new Attribute("objectClass", "top"),
+ new Attribute("objectClass", "organizationalUnit"),
+ new Attribute("ou", "Users")});
+
+ System.setProperty("ldap.host", "localhost");
+ System.setProperty("ldap.port", String.valueOf(LdapServerExternalResource.DEFAULT_PORT));
+ System.setProperty("ldap.database", "test");
+ System.setProperty("ldap.personWithAddress.basedn", BASEDB_USERS);
+
+ System.setProperty("mongo.host", "localhost");
+ System.setProperty("mongo.port", String.valueOf(MongoServerExternalResource.DEFAULT_PORT));
+ System.setProperty("mongo.database", "lightblue");
+
+ initLightblueFactory("./datasources.json", "./metadata/person-with-address-metadata.json");
+ }
+
+ @Test
+ public void test1PersonWithAddress_Insert() throws Exception{
+ Response response = lightblueFactory.getMediator().insert(
+ createRequest_FromResource(InsertionRequest.class, "./crud/insert/person-with-address-insert-single.json"));
+
+ assertNotNull(response);
+ assertNoErrors(response);
+ assertNoDataErrors(response);
+ assertEquals(1, response.getModifiedCount());
+
+ JsonNode entityData = response.getEntityData();
+ assertNotNull(entityData);
+ JSONAssert.assertEquals(
+ "[{\"dn\":\"uid=john.doe," + BASEDB_USERS + "\"}]",
+ entityData.toString(), false);
+ }
+
+ @Test
+ public void test2PersonWithAddress_Find() throws Exception{
+ Response response = lightblueFactory.getMediator().find(
+ createRequest_FromResource(FindRequest.class, "./crud/find/person-with-address-find-single.json"));
+
+ assertNotNull(response);
+ assertNoErrors(response);
+ assertNoDataErrors(response);
+ assertEquals(1, response.getMatchCount());
+
+ JsonNode entityData = response.getEntityData();
+ assertNotNull(entityData);
+ JSONAssert.assertEquals(
+ "[{\"dn\":\"uid=john.doe," + BASEDB_USERS + "\",\"address\":{\"street\":\"123 Some St.\",\"postalCode\":12345,\"state\":\"NC\"}}]",
+ entityData.toString(), true);
+ }
+
+}
diff --git a/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_WithProperties_Test.java b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_WithProperties_Test.java
index 8f27c99..b0786de 100644
--- a/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_WithProperties_Test.java
+++ b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_WithProperties_Test.java
@@ -47,7 +47,7 @@ public class ITCaseLdapCRUDController_WithProperties_Test extends AbstractLdapCR
@BeforeClass
public static void beforeClass() throws Exception {
- ldapServer.add("ou=Customers,dc=example,dc=com", new Attribute[]{
+ ldapServer.add(BASEDB_CUSTOMERS, new Attribute[]{
new Attribute("objectClass", "top"),
new Attribute("objectClass", "organizationalUnit"),
new Attribute("ou", "Customers")});
diff --git a/lightblue-ldap-integration-test/src/test/resources/crud/find/person-with-address-find-single.json b/lightblue-ldap-integration-test/src/test/resources/crud/find/person-with-address-find-single.json
new file mode 100644
index 0000000..5c4c987
--- /dev/null
+++ b/lightblue-ldap-integration-test/src/test/resources/crud/find/person-with-address-find-single.json
@@ -0,0 +1,13 @@
+{
+ "entity": "personWithAddress",
+ "entityVersion": "1.0.0",
+ "projection": [
+ {"field": "dn"},
+ {"field": "address.*"}
+ ],
+ "query": {
+ "field": "uid",
+ "op": "$eq",
+ "rvalue": "john.doe"
+ }
+}
diff --git a/lightblue-ldap-integration-test/src/test/resources/crud/insert/person-with-address-insert-single.json b/lightblue-ldap-integration-test/src/test/resources/crud/insert/person-with-address-insert-single.json
new file mode 100644
index 0000000..3124e2a
--- /dev/null
+++ b/lightblue-ldap-integration-test/src/test/resources/crud/insert/person-with-address-insert-single.json
@@ -0,0 +1,19 @@
+{
+ "entity": "personWithAddress",
+ "entityVersion": "1.0.0",
+ "projection": {
+ "field": "dn"
+ },
+ "data": {
+ "objectClass": ["top", "person", "organizationalPerson", "inetOrgPerson"],
+ "uid": "john.doe",
+ "givenName": "John",
+ "sn": "Doe",
+ "cn": "John Doe",
+ "address": {
+ "street": "123 Some St.",
+ "postalCode": 12345,
+ "state": "NC"
+ }
+ }
+}
\ No newline at end of file
diff --git a/lightblue-ldap-integration-test/src/test/resources/metadata/person-with-address-metadata.json b/lightblue-ldap-integration-test/src/test/resources/metadata/person-with-address-metadata.json
new file mode 100644
index 0000000..78f16f0
--- /dev/null
+++ b/lightblue-ldap-integration-test/src/test/resources/metadata/person-with-address-metadata.json
@@ -0,0 +1,49 @@
+{
+ "entityInfo": {
+ "name": "personWithAddress",
+ "datastore": {
+ "backend":"ldap",
+ "database": "${ldap.database}",
+ "basedn": "${ldap.personWithAddress.basedn}",
+ "uniqueattr": "uid"
+ },
+ "ldap": {
+ "fieldsToAttributes": [
+ {
+ "field": "address.state",
+ "attribute": "st"
+ }
+ ]
+ }
+ },
+ "schema": {
+ "name": "personWithAddress",
+ "version": {
+ "value": "1.0.0",
+ "changelog": "blahblah"
+ },
+ "status": {
+ "value": "active"
+ },
+ "access" : {
+ "insert": ["anyone"],
+ "update": ["anyone"],
+ "delete": ["anyone"],
+ "find": ["anyone"]
+ },
+ "fields": {
+ "uid": {"type": "string"},
+ "givenName": {"type": "string"},
+ "sn": {"type": "string"},
+ "cn": {"type": "string"},
+ "address": {
+ "type": "object",
+ "fields": {
+ "street": {"type": "string"},
+ "postalCode": {"type": "integer"},
+ "state": {"type": "string"}
+ }
+ }
+ }
+ }
+}
diff --git a/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadata.java b/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadata.java
index 7f5fe9b..f5fc0f6 100644
--- a/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadata.java
+++ b/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadata.java
@@ -20,9 +20,11 @@
import java.util.HashMap;
import java.util.Map;
-import java.util.Map.Entry;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
+import com.redhat.lightblue.util.Path;
/**
* Container for special ldap properties parsed from the metadata.json file.
@@ -33,42 +35,49 @@
*/
public class LdapMetadata implements LdapFieldNameTranslator{
- private final Map fieldsToAttributes = new HashMap();
+ private final BiMap fieldsToAttributes = HashBiMap.create();
/**
* Returns an immutable copy of the internal collection of {@link FieldAttributeMapping}s.
* @return a collection of {@link FieldAttributeMapping}s.
*/
- public Map getFieldsToAttributes(){
- return new HashMap(fieldsToAttributes);
+ public Map getFieldsToAttributes(){
+ return new HashMap(fieldsToAttributes);
}
@Override
- public String translateFieldName(String fieldName){
- String attributeName = fieldsToAttributes.get(fieldName);
- if(attributeName == null){
- return fieldName;
+ public String translateFieldName(Path path){
+ String attributeName = fieldsToAttributes.get(path);
+ if(attributeName != null){
+ return attributeName;
}
- return attributeName;
+ Path last = path.suffix(1);
+ attributeName = fieldsToAttributes.get(last);
+ if(attributeName != null){
+ return attributeName;
+ }
+
+ return last.toString();
}
@Override
- public String translateAttributeName(String attributeName){
- for(Entry f2a : fieldsToAttributes.entrySet()){
- if(f2a.getValue().equalsIgnoreCase(attributeName)){
- return f2a.getKey();
- }
+ public Path translateAttributeName(String attributeName){
+ Path fieldPath = fieldsToAttributes.inverse().get(attributeName);
+
+ if(fieldPath == null){
+ return new Path(attributeName);
}
- return attributeName;
+
+ return fieldPath;
}
/**
* Adds a {@link FieldAttributeMapping} to this {@link LdapMetadata}.
* @param fieldAttributeMapping - {@link FieldAttributeMapping}
*/
- public void addFieldToAttribute(String fieldName, String attributeName){
- fieldsToAttributes.put(fieldName, attributeName);
+ public void addFieldToAttribute(Path fieldPath, String attributeName){
+ fieldsToAttributes.put(fieldPath, attributeName);
}
}
diff --git a/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParser.java b/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParser.java
index 5ff8124..382fee4 100644
--- a/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParser.java
+++ b/lightblue-ldap-metadata/src/main/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParser.java
@@ -27,6 +27,7 @@
import com.redhat.lightblue.metadata.parser.MetadataParser;
import com.redhat.lightblue.metadata.parser.PropertyParser;
import com.redhat.lightblue.util.Error;
+import com.redhat.lightblue.util.Path;
/**
* {@link PropertyParser} implementation for LDAP.
@@ -51,7 +52,7 @@ public com.redhat.lightblue.metadata.ldap.model.LdapMetadata parse(String name,
if(fieldsToAttributesNode != null){
for(T fieldToAttributeNode : fieldsToAttributesNode){
ldapMetadata.addFieldToAttribute(
- p.getRequiredStringProperty(fieldToAttributeNode, FIELD),
+ new Path(p.getRequiredStringProperty(fieldToAttributeNode, FIELD)),
p.getRequiredStringProperty(fieldToAttributeNode, ATTRIBUTE));
}
}
@@ -70,9 +71,9 @@ public void convert(MetadataParser p, T emptyNode, Object object) {
if(!ldapMetadata.getFieldsToAttributes().isEmpty()){
Object fieldsToAttributesNode = p.newArrayField(emptyNode, FIELDS_TO_ATTRIBUTES);
- for(Entry entry : ldapMetadata.getFieldsToAttributes().entrySet()){
+ for(Entry entry : ldapMetadata.getFieldsToAttributes().entrySet()){
T fieldToAttributeNode = p.newNode();
- p.putString(fieldToAttributeNode, FIELD, entry.getKey());
+ p.putString(fieldToAttributeNode, FIELD, entry.getKey().toString());
p.putString(fieldToAttributeNode, ATTRIBUTE, entry.getValue());
p.addObjectToArray(fieldsToAttributesNode, fieldToAttributeNode);
diff --git a/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadataTest.java b/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadataTest.java
index 9ee1f1b..29bc71a 100644
--- a/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadataTest.java
+++ b/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/model/LdapMetadataTest.java
@@ -27,55 +27,92 @@
import org.junit.Test;
+import com.redhat.lightblue.util.Path;
+
public class LdapMetadataTest {
@Test
public void testTranslateFieldName(){
- String fieldName = "fakeFieldName";
+ Path fieldName = new Path("fakeFieldName");
String attributeName = "fakeAttributeName";
- LdapMetadata property = new LdapMetadata();
- property.addFieldToAttribute(fieldName, attributeName);
- property.addFieldToAttribute("anotherField", "anotherAttribute");
+ LdapMetadata metadata = new LdapMetadata();
+ metadata.addFieldToAttribute(fieldName, attributeName);
+ metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute");
- assertEquals(attributeName, property.translateFieldName(fieldName));
+ assertEquals(attributeName, metadata.translateFieldName(new Path(fieldName)));
+ }
+
+ @Test
+ public void testTranslateFieldName_WithPath(){
+ Path fieldName = new Path("fakePath.fakeFieldName");
+ String attributeName = "fakeAttributeName";
+
+ LdapMetadata metadata = new LdapMetadata();
+ metadata.addFieldToAttribute(fieldName, attributeName);
+
+ assertEquals(attributeName, metadata.translateFieldName(new Path(fieldName)));
+ }
+
+ @Test
+ public void testTranslateFieldName_WithPath_MatchesOnTail(){
+ Path fieldName = new Path("fakeFieldName");
+ String pathedFieldName = "fakePath." + fieldName;
+ String attributeName = "fakeAttributeName";
+
+ LdapMetadata metadata = new LdapMetadata();
+ metadata.addFieldToAttribute(fieldName, attributeName);
+
+ assertEquals(attributeName, metadata.translateFieldName(new Path(pathedFieldName)));
}
@Test
public void testTranslateFieldName_ValueNotPresent(){
String fieldName = "fakeFieldName";
- assertEquals(fieldName, new LdapMetadata().translateFieldName(fieldName));
+ assertEquals(fieldName, new LdapMetadata().translateFieldName(new Path(fieldName)));
}
@Test
public void testTranslateAttributeName(){
- String fieldName = "fakeFieldName";
+ Path fieldName = new Path("fakeFieldName");
+ String attributeName = "fakeAttributeName";
+
+ LdapMetadata metadata = new LdapMetadata();
+ metadata.addFieldToAttribute(fieldName, attributeName);
+ metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute");
+
+ assertEquals(fieldName, metadata.translateAttributeName(attributeName));
+ }
+
+ @Test
+ public void testTranslateAttributeName_WithPath(){
+ Path fieldName = new Path("somePath.fakeFieldName");
String attributeName = "fakeAttributeName";
- LdapMetadata property = new LdapMetadata();
- property.addFieldToAttribute(fieldName, attributeName);
- property.addFieldToAttribute("anotherField", "anotherAttribute");
+ LdapMetadata metadata = new LdapMetadata();
+ metadata.addFieldToAttribute(fieldName, attributeName);
+ metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute");
- assertEquals(fieldName, property.translateAttributeName(attributeName));
+ assertEquals(fieldName, metadata.translateAttributeName(attributeName));
}
@Test
public void testTranslateAttributeName_ValueNotPresent(){
String attributeName = "fakeAttributeName";
- assertEquals(attributeName, new LdapMetadata().translateAttributeName(attributeName));
+ assertEquals(attributeName, new LdapMetadata().translateAttributeName(attributeName).toString());
}
@Test
public void testGetFieldsToAttributes_AssertImmutable(){
- LdapMetadata property = new LdapMetadata();
- property.addFieldToAttribute("anotherField", "anotherAttribute");
+ LdapMetadata metadata = new LdapMetadata();
+ metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute");
- Map fieldsToAttributes = property.getFieldsToAttributes();
+ Map fieldsToAttributes = metadata.getFieldsToAttributes();
assertNotNull(fieldsToAttributes);
- assertMapEquivalent(fieldsToAttributes, property.getFieldsToAttributes());
- assertNotSame(fieldsToAttributes, property.getFieldsToAttributes());
+ assertMapEquivalent(fieldsToAttributes, metadata.getFieldsToAttributes());
+ assertNotSame(fieldsToAttributes, metadata.getFieldsToAttributes());
}
}
diff --git a/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParserTest.java b/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParserTest.java
index 34b46ee..9a947ab 100644
--- a/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParserTest.java
+++ b/lightblue-ldap-metadata/src/test/java/com/redhat/lightblue/metadata/ldap/parser/LdapPropertyParserTest.java
@@ -39,6 +39,7 @@
import com.redhat.lightblue.common.ldap.LdapConstant;
import com.redhat.lightblue.metadata.ldap.model.LdapMetadata;
import com.redhat.lightblue.test.MetadataUtil;
+import com.redhat.lightblue.util.Path;
public class LdapPropertyParserTest {
@@ -54,13 +55,13 @@ public void testParse() throws IOException{
assertNotNull(ldapMetadata);
- Map fieldsToAttributes = ldapMetadata.getFieldsToAttributes();
+ Map fieldsToAttributes = ldapMetadata.getFieldsToAttributes();
assertNotNull(fieldsToAttributes);
assertEquals(2, fieldsToAttributes.size());
- Map expected = new HashMap();
- expected.put("firstName", "givenName");
- expected.put("lastName", "sn");
+ Map expected = new HashMap();
+ expected.put(new Path("firstName"), "givenName");
+ expected.put(new Path("lastName"), "sn");
assertMapEquivalent(expected, fieldsToAttributes);
}
@@ -87,8 +88,8 @@ public void testParse_IncorrectBackend(){
@Test
public void testConvert() throws IOException, JSONException{
LdapMetadata ldapMetadata = new LdapMetadata();
- ldapMetadata.addFieldToAttribute("firstName", "givenName");
- ldapMetadata.addFieldToAttribute("lastName", "sn");
+ ldapMetadata.addFieldToAttribute(new Path("firstName"), "givenName");
+ ldapMetadata.addFieldToAttribute(new Path("lastName"), "sn");
JsonNode node = json("{}");