From 7c5d5986db5741602f1c63e5ddd9f3911b95ab68 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Mon, 26 Jan 2015 13:28:30 -0500 Subject: [PATCH 01/13] couple small changes to unit tests --- .../lightblue/crud/ldap/ITCaseLdapCRUDControllerTest.java | 4 ++-- .../ldap/ITCaseLdapCRUDController_WithProperties_Test.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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_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")}); From 334cde5d661166e96e8dac25b902ea44965b7dec Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Mon, 26 Jan 2015 16:22:10 -0500 Subject: [PATCH 02/13] fixes #30 and #42 - support object fields and use Paths over fieldName fix crud errors so that they actually are sent to the client --- .../common/ldap/LdapFieldNameTranslator.java | 4 +- .../lightblue/crud/ldap/EntryBuilder.java | 12 +- .../crud/ldap/LdapCRUDController.java | 43 +++--- .../crud/ldap/TranslatorFromJson.java | 39 ++++- .../model/TrivialLdapFieldNameTranslator.java | 5 +- .../ldap/translator/FilterTranslator.java | 6 +- .../ldap/translator/ResultTranslator.java | 133 +++++++++++------- .../crud/ldap/translator/SortTranslator.java | 2 +- .../TrivialLdapFieldNameTranslatorTest.java | 4 +- .../ldap/translator/ResultTranslatorTest.java | 20 ++- .../crud/ldap/AbstractLdapCRUDController.java | 26 ++-- ...ITCaseLdapCRUDController_Objects_Test.java | 78 ++++++++++ .../find/person-with-address-find-single.json | 13 ++ .../person-with-address-insert-single.json | 19 +++ .../person-with-address-metadata.json | 49 +++++++ .../metadata/ldap/model/LdapMetadata.java | 17 ++- .../metadata/ldap/model/LdapMetadataTest.java | 29 +++- 17 files changed, 381 insertions(+), 118 deletions(-) create mode 100644 lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_Objects_Test.java create mode 100644 lightblue-ldap-integration-test/src/test/resources/crud/find/person-with-address-find-single.json create mode 100644 lightblue-ldap-integration-test/src/test/resources/crud/insert/person-with-address-insert-single.json create mode 100644 lightblue-ldap-integration-test/src/test/resources/metadata/person-with-address-metadata.json 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..a944ded 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,7 +32,7 @@ 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. 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..f09094d 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 @@ -29,7 +29,6 @@ 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.SimpleField; import com.redhat.lightblue.metadata.Type; import com.redhat.lightblue.metadata.types.BinaryType; @@ -75,7 +74,7 @@ else if(type instanceof BinaryType){ @Override protected void translate(SimpleField field, Path path, JsonNode node, Entry target) { - String attributeName = fieldNameTranslator.translateFieldName(field.getName()); + String attributeName = fieldNameTranslator.translateFieldName(path); if(LdapConstant.ATTRIBUTE_DN.equalsIgnoreCase(attributeName)){ throw new IllegalArgumentException( @@ -101,16 +100,11 @@ 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) { ArrayElement arrayElement = field.getElement(); Type arrayElementType = arrayElement.getType(); - String attributeName = fieldNameTranslator.translateFieldName(field.getName()); + String attributeName = fieldNameTranslator.translateFieldName(path); if(arrayElementType instanceof BinaryType){ List bytes = new ArrayList(); @@ -129,7 +123,7 @@ protected void translateSimpleArray(ArrayField field, Path path, List it } @Override - protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Entry target) { + protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Path path, Entry target) { throw new UnsupportedOperationException("Object ArrayField type is not currently supported."); } 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..af5f0f4 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 @@ -107,10 +107,10 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx, EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName()); LdapDataStore store = getLdapDataStore(md); - LdapFieldNameTranslator property = getLdapFieldNameTranslator(md); + LdapFieldNameTranslator fieldNameTranslator = 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(); @@ -127,7 +127,7 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx, JsonNode rootNode = document.getRoot(); - String uniqueFieldName = property.translateAttributeName(store.getUniqueAttribute()); + String uniqueFieldName = fieldNameTranslator.translateAttributeName(store.getUniqueAttribute()); JsonNode uniqueNode = rootNode.get(uniqueFieldName); if(uniqueNode == null){ throw new IllegalArgumentException(uniqueFieldName + " is a required field"); @@ -208,17 +208,17 @@ public CRUDFindResponse find(CRUDOperationContext ctx, LDAPConnection connection = getNewLdapConnection(store); - LdapFieldNameTranslator property = getLdapFieldNameTranslator(md); + LdapFieldNameTranslator fieldNameTranslator = 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,14 +228,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); + DocCtx erroredDoc = new DocCtx(new JsonDoc(null)); erroredDoc.addError(Error.get(e)); translatedDocs.add(erroredDoc); } @@ -250,7 +250,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())); } } @@ -364,9 +364,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 +381,16 @@ 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(new Path(node.toString().replace(fieldName, "") + LightblueUtil.createArrayFieldNameFromCountField(fieldName))); } else{ - fields.add(fieldName); + paths.add(node); } } } - return fields; + return paths; } /** @@ -399,10 +400,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 +423,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 = 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 +435,7 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map ), md); - String dnFieldName = property.translateAttributeName(LdapConstant.ATTRIBUTE_DN); + String dnFieldName = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); for(Entry insertedDn : documentToDnMap.entrySet()){ DocCtx document = insertedDn.getKey(); 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..8739421 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 @@ -45,6 +45,8 @@ * * @param - A entity that the specific datastore knows how * to interact with. + * + * @see #translate(JsonDoc, Object) */ public abstract class TranslatorFromJson { @@ -54,7 +56,7 @@ public TranslatorFromJson(EntityMetadata md){ this.md = md; } - protected EntityMetadata getEntityMetadata(){ + public EntityMetadata getEntityMetadata(){ return md; } @@ -67,7 +69,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,7 +86,14 @@ protected void translate(JsonDoc document, T target){ } while (cursor.nextSibling()); } - private void translate(JsonNodeCursor cursor, T target){ + /** + * 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){ Path path = cursor.getCurrentPath(); JsonNode node = cursor.getCurrentNode(); FieldTreeNode fieldNode = md.resolve(path); @@ -92,7 +106,7 @@ private void translate(JsonNodeCursor cursor, T target){ translate((SimpleField) fieldNode, path, node, target); } else if (fieldNode instanceof ObjectField) { - translate((ObjectField) fieldNode, path, node, target); + translate((ObjectField) fieldNode, cursor, path, target); } else if (fieldNode instanceof ArrayField) { translate((ArrayField) fieldNode, cursor, path, target); @@ -121,7 +135,7 @@ private void translate(ArrayField field, JsonNodeCursor cursor, Path path, T tar translateSimpleArray(field, path, items, target); } else if(arrayElement instanceof ObjectArrayElement){ - translateObjectArray(field, cursor, target); + translateObjectArray(field, cursor, path, target); } else{ throw new UnsupportedOperationException("ArrayElement type is not supported: " + arrayElement.getClass().getName()); @@ -130,13 +144,24 @@ else if(arrayElement instanceof ObjectArrayElement){ cursor.parent(); } + protected void translate(ObjectField field, JsonNodeCursor cursor, Path path, T target){ + if(!cursor.firstChild()){ + //TODO: throw exception? + return; + } + do { + translate(cursor, target); + } while (cursor.nextSibling()); + + cursor.parent(); + } + protected void translate(ReferenceField field, Path path, 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 translateObjectArray(ArrayField field, JsonNodeCursor cursor, T target); + protected abstract void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Path path, 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..80c539d 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,8 +30,8 @@ public class TrivialLdapFieldNameTranslator implements LdapFieldNameTranslator{ @Override - public String translateFieldName(String fieldName) { - return fieldName; + public String translateFieldName(Path path) { + return path.getLast(); } @Override 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..59953db 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,94 @@ public class ResultTranslator { private final JsonNodeFactory factory; private final EntityMetadata md; private final LdapFieldNameTranslator fieldNameTranslator; + private final String fieldNameDN; public ResultTranslator(JsonNodeFactory factory, EntityMetadata md, LdapFieldNameTranslator fieldNameTranslator){ this.factory = factory; this.md = md; this.fieldNameTranslator = fieldNameTranslator; + fieldNameDN = 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))); + ObjectNode node = toJson(entry, cursor, fields); + node.set(fieldNameDN, StringType.TYPE.toJson(factory, entry.getDN())); + return new DocCtx(new JsonDoc(node)); } //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)){ + + if(fieldNameDN.equalsIgnoreCase(fieldName)){ //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(fieldName)){ - value = StringType.TYPE.toJson(factory, entityName); + node.set(fieldName, 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 +166,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 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/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..2fc2c5e --- /dev/null +++ b/lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDController_Objects_Test.java @@ -0,0 +1,78 @@ +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/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..ef47b76 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 @@ -23,6 +23,7 @@ import java.util.Map.Entry; import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator; +import com.redhat.lightblue.util.Path; /** * Container for special ldap properties parsed from the metadata.json file. @@ -44,13 +45,19 @@ public Map getFieldsToAttributes(){ } @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.toString()); + if(attributeName != null){ + return attributeName; } - return attributeName; + String last = path.getLast(); + attributeName = fieldsToAttributes.get(last); + if(attributeName != null){ + return attributeName; + } + + return last; } @Override 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..e58d243 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,6 +27,8 @@ import org.junit.Test; +import com.redhat.lightblue.util.Path; + public class LdapMetadataTest { @Test @@ -38,14 +40,37 @@ public void testTranslateFieldName(){ property.addFieldToAttribute(fieldName, attributeName); property.addFieldToAttribute("anotherField", "anotherAttribute"); - assertEquals(attributeName, property.translateFieldName(fieldName)); + assertEquals(attributeName, property.translateFieldName(new Path(fieldName))); + } + + @Test + public void testTranslateFieldName_WithPath(){ + String fieldName = "fakePath.fakeFieldName"; + String attributeName = "fakeAttributeName"; + + LdapMetadata property = new LdapMetadata(); + property.addFieldToAttribute(fieldName, attributeName); + + assertEquals(attributeName, property.translateFieldName(new Path(fieldName))); + } + + @Test + public void testTranslateFieldName_WithPath_MatchesOnTail(){ + String fieldName = "fakeFieldName"; + String pathedFieldName = "fakePath." + fieldName; + String attributeName = "fakeAttributeName"; + + LdapMetadata property = new LdapMetadata(); + property.addFieldToAttribute(fieldName, attributeName); + + assertEquals(attributeName, property.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 From 459ff20128ad7380c4a44024572be75efd945824 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Wed, 28 Jan 2015 08:31:20 -0500 Subject: [PATCH 03/13] LdapFieldNameTranslator#translateAttributeName now returns a Path --- .../common/ldap/LdapFieldNameTranslator.java | 2 +- .../crud/ldap/LdapCRUDController.java | 28 +++++----- .../model/TrivialLdapFieldNameTranslator.java | 4 +- .../ldap/translator/ResultTranslator.java | 15 +++--- .../TrivialLdapFieldNameTranslatorTest.java | 2 +- .../metadata/ldap/model/LdapMetadata.java | 6 +-- .../metadata/ldap/model/LdapMetadataTest.java | 52 ++++++++++++------- 7 files changed, 59 insertions(+), 50 deletions(-) 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 a944ded..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 @@ -39,6 +39,6 @@ public interface LdapFieldNameTranslator { * @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/LdapCRUDController.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCRUDController.java index af5f0f4..b7af21d 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 @@ -125,12 +125,10 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx, } } - JsonNode rootNode = document.getRoot(); - - String uniqueFieldName = fieldNameTranslator.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 new IllegalArgumentException(store.getUniqueAttribute() + " is a required field"); } String dn = createDN(store, uniqueNode.asText()); @@ -281,18 +279,18 @@ public void beforeUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity) */ @Override public void beforeCreateNewSchema(Metadata m, EntityMetadata md) { - LdapFieldNameTranslator property = getLdapFieldNameTranslator(md); + LdapFieldNameTranslator ldapNameTranslator = 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)); + Path dnFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); + if(!fields.has(dnFieldPath.toString())){ + fields.addNew(new SimpleField(dnFieldPath.toString(), 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)); + Path objectClassFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS); + if(!fields.has(objectClassFieldPath.toString())){ + fields.addNew(new ArrayField(objectClassFieldPath.toString(), new SimpleArrayElement(StringType.TYPE))); + fields.addNew(new SimpleField(LightblueUtil.createArrayCountFieldName(objectClassFieldPath.toString()), IntegerType.TYPE)); } } @@ -435,7 +433,7 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map ), md); - String dnFieldName = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); + Path dnFieldPath = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); for(Entry insertedDn : documentToDnMap.entrySet()){ DocCtx document = insertedDn.getKey(); @@ -445,7 +443,7 @@ 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)); + node.set(dnFieldPath.toString(), StringType.TYPE.toJson(factory, dn)); projectionResponseJson = new DocCtx(new JsonDoc(node)); } //TODO: else fetch entity from LDAP and project results. 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 80c539d..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 @@ -35,8 +35,8 @@ public String translateFieldName(Path path) { } @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/ResultTranslator.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/translator/ResultTranslator.java index 59953db..2a367f7 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 @@ -57,13 +57,13 @@ public class ResultTranslator { private final JsonNodeFactory factory; private final EntityMetadata md; private final LdapFieldNameTranslator fieldNameTranslator; - private final String fieldNameDN; + private final Path dnPath; public ResultTranslator(JsonNodeFactory factory, EntityMetadata md, LdapFieldNameTranslator fieldNameTranslator){ this.factory = factory; this.md = md; this.fieldNameTranslator = fieldNameTranslator; - fieldNameDN = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); + dnPath = fieldNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); } public DocCtx translate(SearchResultEntry entry){ @@ -72,7 +72,7 @@ public DocCtx translate(SearchResultEntry entry){ if (cursor.firstChild()) { ObjectNode node = toJson(entry, cursor, fields); - node.set(fieldNameDN, StringType.TYPE.toJson(factory, entry.getDN())); + node.set(dnPath.toString(), StringType.TYPE.toJson(factory, entry.getDN())); return new DocCtx(new JsonDoc(node)); } @@ -85,15 +85,14 @@ private ObjectNode toJson(SearchResultEntry entry, FieldCursor fieldCursor, Fiel String entityName = md.getEntityInfo().getName(); do { - FieldTreeNode field = fieldCursor.getCurrentNode(); - String fieldName = field.getName(); + Path fieldPath = fieldCursor.getCurrentPath(); - if(fieldNameDN.equalsIgnoreCase(fieldName)){ + if(dnPath.matches(fieldPath)){ //DN is not handled as a normal attribute, can be skipped. continue; } - else if(LightblueUtil.isFieldObjectType(fieldName)){ - node.set(fieldName, StringType.TYPE.toJson(factory, entityName)); + else if(LightblueUtil.isFieldObjectType(fieldPath.toString())){ + node.set(fieldPath.toString(), StringType.TYPE.toJson(factory, entityName)); } else{ appendToJsonNode(entry, fieldCursor, node, fields); 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 2edccd2..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 @@ -35,7 +35,7 @@ public void testTranslateFieldName(){ @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-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 ef47b76..c3d4b4e 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 @@ -61,13 +61,13 @@ public String translateFieldName(Path path){ } @Override - public String translateAttributeName(String attributeName){ + public Path translateAttributeName(String attributeName){ for(Entry f2a : fieldsToAttributes.entrySet()){ if(f2a.getValue().equalsIgnoreCase(attributeName)){ - return f2a.getKey(); + return new Path(f2a.getKey()); } } - return attributeName; + return new Path(attributeName); } /** 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 e58d243..9c5e1c4 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 @@ -36,11 +36,11 @@ public void testTranslateFieldName(){ String fieldName = "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("anotherField", "anotherAttribute"); - assertEquals(attributeName, property.translateFieldName(new Path(fieldName))); + assertEquals(attributeName, metadata.translateFieldName(new Path(fieldName))); } @Test @@ -48,10 +48,10 @@ public void testTranslateFieldName_WithPath(){ String fieldName = "fakePath.fakeFieldName"; String attributeName = "fakeAttributeName"; - LdapMetadata property = new LdapMetadata(); - property.addFieldToAttribute(fieldName, attributeName); + LdapMetadata metadata = new LdapMetadata(); + metadata.addFieldToAttribute(fieldName, attributeName); - assertEquals(attributeName, property.translateFieldName(new Path(fieldName))); + assertEquals(attributeName, metadata.translateFieldName(new Path(fieldName))); } @Test @@ -60,10 +60,10 @@ public void testTranslateFieldName_WithPath_MatchesOnTail(){ String pathedFieldName = "fakePath." + fieldName; String attributeName = "fakeAttributeName"; - LdapMetadata property = new LdapMetadata(); - property.addFieldToAttribute(fieldName, attributeName); + LdapMetadata metadata = new LdapMetadata(); + metadata.addFieldToAttribute(fieldName, attributeName); - assertEquals(attributeName, property.translateFieldName(new Path(pathedFieldName))); + assertEquals(attributeName, metadata.translateFieldName(new Path(pathedFieldName))); } @Test @@ -78,29 +78,41 @@ public void testTranslateAttributeName(){ String fieldName = "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("anotherField", "anotherAttribute"); - assertEquals(fieldName, property.translateAttributeName(attributeName)); + assertEquals(fieldName, metadata.translateAttributeName(attributeName).toString()); + } + + @Test + public void testTranslateAttributeName_WithPath(){ + String fieldName = "somePath.fakeFieldName"; + String attributeName = "fakeAttributeName"; + + LdapMetadata metadata = new LdapMetadata(); + metadata.addFieldToAttribute(fieldName, attributeName); + metadata.addFieldToAttribute("anotherField", "anotherAttribute"); + + assertEquals(fieldName, metadata.translateAttributeName(attributeName).toString()); } @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("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()); } } From e837644f1aa13b598cee1ad7d04844e20d213879 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Wed, 28 Jan 2015 13:15:19 -0500 Subject: [PATCH 04/13] use ctx error over document error --- .../com/redhat/lightblue/crud/ldap/LdapCRUDController.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 b7af21d..c484683 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 @@ -233,9 +233,7 @@ public CRUDFindResponse find(CRUDOperationContext ctx, translatedDocs.add(resultTranslator.translate(entry)); } catch(Exception e){ - DocCtx erroredDoc = new DocCtx(new JsonDoc(null)); - erroredDoc.addError(Error.get(e)); - translatedDocs.add(erroredDoc); + ctx.addError(Error.get(e)); } } ctx.setDocuments(translatedDocs); From ce8b284766c2aad8f0deb6e4d31574219ced1f70 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Wed, 28 Jan 2015 13:20:02 -0500 Subject: [PATCH 05/13] simplify EntryBuilder method signatures --- .../lightblue/crud/ldap/EntryBuilder.java | 11 ++++----- .../crud/ldap/TranslatorFromJson.java | 24 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) 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 f09094d..53a436d 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 @@ -35,7 +35,6 @@ import com.redhat.lightblue.metadata.types.DateType; 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; @@ -73,8 +72,8 @@ else if(type instanceof BinaryType){ } @Override - protected void translate(SimpleField field, Path path, JsonNode node, Entry target) { - String attributeName = fieldNameTranslator.translateFieldName(path); + protected void translate(SimpleField field, JsonNode node, Entry target) { + String attributeName = fieldNameTranslator.translateFieldName(field.getFullPath()); if(LdapConstant.ATTRIBUTE_DN.equalsIgnoreCase(attributeName)){ throw new IllegalArgumentException( @@ -101,10 +100,10 @@ else if(LightblueUtil.isFieldObjectType(attributeName) } @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(path); + String attributeName = fieldNameTranslator.translateFieldName(field.getFullPath()); if(arrayElementType instanceof BinaryType){ List bytes = new ArrayList(); @@ -123,7 +122,7 @@ protected void translateSimpleArray(ArrayField field, Path path, List it } @Override - protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Path path, Entry target) { + protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Entry target) { throw new UnsupportedOperationException("Object ArrayField type is not currently supported."); } 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 8739421..57c2965 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 @@ -103,23 +103,23 @@ protected void translate(JsonNodeCursor cursor, T target){ } if (fieldNode instanceof SimpleField) { - translate((SimpleField) fieldNode, path, node, target); + translate((SimpleField) fieldNode, node, target); } else if (fieldNode instanceof ObjectField) { - translate((ObjectField) fieldNode, cursor, path, target); + translate((ObjectField) fieldNode, cursor, target); } else if (fieldNode instanceof ArrayField) { - translate((ArrayField) fieldNode, cursor, path, target); + translate((ArrayField) fieldNode, cursor, target); } else if (fieldNode instanceof ReferenceField) { - translate((ReferenceField) fieldNode, path, node, target); + translate((ReferenceField) fieldNode, node, target); } else{ throw new UnsupportedOperationException("Field type is not supported: " + fieldNode.getClass().getName()); } } - 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; @@ -132,10 +132,10 @@ 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, path, target); + translateObjectArray(field, cursor, target); } else{ throw new UnsupportedOperationException("ArrayElement type is not supported: " + arrayElement.getClass().getName()); @@ -144,7 +144,7 @@ else if(arrayElement instanceof ObjectArrayElement){ cursor.parent(); } - protected void translate(ObjectField field, JsonNodeCursor cursor, Path path, T target){ + protected void translate(ObjectField field, JsonNodeCursor cursor, T target){ if(!cursor.firstChild()){ //TODO: throw exception? return; @@ -156,12 +156,12 @@ protected void translate(ObjectField field, JsonNodeCursor cursor, Path path, T cursor.parent(); } - protected void translate(ReferenceField field, Path path, JsonNode node, T target){ + 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 translateSimpleArray(ArrayField field, Path path, List items, T target); - protected abstract void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Path path, 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); } From 5beb0c5c2b40fa3109b5d21e00190448ea4ec278 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Wed, 28 Jan 2015 14:01:31 -0500 Subject: [PATCH 06/13] add unit test for unsupported objectarrays --- .../lightblue/crud/ldap/EntryBuilderTest.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java index 64e00c6..57ec763 100644 --- a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java +++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java @@ -89,8 +89,8 @@ public void testFieldIsObjectType() throws Exception{ * it requires two fields. */ @Test - public void testFieldIsArrayField() throws Exception{ - String arrayFieldName = "someArray"; + public void testFieldIsSimpleArrayField() throws Exception{ + String arrayFieldName = "someSimpleArray"; String arrayCountFieldName = LightblueUtil.createArrayCountFieldName(arrayFieldName); Entry entry = buildEntry( arrayCountFieldName, @@ -110,6 +110,24 @@ public void testFieldIsArrayFieldWithoutMatchArray() throws Exception{ assertNotNull(entry.getAttribute(arrayCountFieldName)); } + /** + * This test is kind of hacky as it requires json injection in order to make it work because + * it requires two fields. + * ObjectFields are not currently supported in LDAP, an exception should be thrown indicating as such. + */ + @Test(expected = UnsupportedOperationException.class) + public void testObjectArrayField_ThrowsException() throws Exception{ + String arrayFieldName = "someObjectArray"; + String arrayCountFieldName = LightblueUtil.createArrayCountFieldName(arrayFieldName); + Entry entry = buildEntry( + arrayCountFieldName, + "{\"type\": \"integer\"}, " + quote(arrayFieldName) + ": {\"type\": \"array\", \"items\": {\"type\": \"object\",\"fields\": {\"someField\": {\"type\": \"string\"}}}}", + "1," + quote(arrayFieldName) + ":[{\"someField\":\"hello\"}]"); + + assertNotNull(entry); + assertNull(entry.getAttribute(arrayFieldName)); + } + @Test(expected = IllegalArgumentException.class) public void testFieldIsDN() throws Exception{ buildEntry(LdapConstant.ATTRIBUTE_DN, "{\"type\": \"string\"}", quote("uid=someuid,dc=example,dc=com")); From 1c755531a4df574ebc2a287cd443b6b1b7b9f881 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Wed, 28 Jan 2015 14:10:50 -0500 Subject: [PATCH 07/13] use Path copy utilities --- .../com/redhat/lightblue/crud/ldap/LdapCRUDController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 c484683..38fd781 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 @@ -377,8 +377,7 @@ private Set gatherRequiredFields(EntityMetadata md, * Handles the case of an array count field, which will not actually exist in * the ldap entity. */ - - paths.add(new Path(node.toString().replace(fieldName, "") + LightblueUtil.createArrayFieldNameFromCountField(fieldName))); + paths.add(node.mutableCopy().setLast(LightblueUtil.createArrayFieldNameFromCountField(fieldName)).immutableCopy()); } else{ paths.add(node); From 2570e4d846551e8045dccbf3c5e656f36764b63b Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Wed, 28 Jan 2015 14:54:05 -0500 Subject: [PATCH 08/13] Add error push/pop to TranslatorFromJson --- .../redhat/lightblue/crud/ldap/EntryBuilder.java | 5 ++++- .../lightblue/crud/ldap/TranslatorFromJson.java | 6 ++++++ .../lightblue/crud/ldap/EntryBuilderTest.java | 16 +++++++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) 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 53a436d..1755ced 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 @@ -33,6 +33,7 @@ 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.unboundid.ldap.sdk.Entry; @@ -53,8 +54,10 @@ public EntryBuilder(EntityMetadata md, LdapFieldNameTranslator fieldNameTranslat } public Entry build(String dn, JsonDoc document){ + Error.push(LdapConstant.ATTRIBUTE_DN + "=" + dn); Entry entry = new Entry(dn); translate(document, entry); + Error.pop(); return entry; } @@ -123,7 +126,7 @@ protected void translateSimpleArray(ArrayField field, List items, Entry @Override protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Entry target) { - throw new UnsupportedOperationException("Object ArrayField type is not currently supported."); + throw Error.get("Unsupported Feature: object array", field.getFullPath().toString()); } } 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 57c2965..60caa45 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 @@ -33,6 +33,7 @@ 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; @@ -102,6 +103,8 @@ protected void translate(JsonNodeCursor cursor, T target){ throw new NullPointerException("No Metadata field found for: " + path.toString()); } + Error.push(fieldNode.getFullPath().getLast()); + if (fieldNode instanceof SimpleField) { translate((SimpleField) fieldNode, node, target); } @@ -117,6 +120,8 @@ else if (fieldNode instanceof ReferenceField) { else{ throw new UnsupportedOperationException("Field type is not supported: " + fieldNode.getClass().getName()); } + + Error.pop(); } private void translate(ArrayField field, JsonNodeCursor cursor, T target){ @@ -149,6 +154,7 @@ protected void translate(ObjectField field, JsonNodeCursor cursor, T target){ //TODO: throw exception? return; } + do { translate(cursor, target); } while (cursor.nextSibling()); diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java index 57ec763..c4b7b00 100644 --- a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java +++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java @@ -32,7 +32,9 @@ import javax.xml.bind.DatatypeConverter; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @@ -76,6 +78,9 @@ protected static String quote(String text){ public static class SpecializedTests { + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + @Test public void testFieldIsObjectType() throws Exception{ Entry entry = buildEntry(LightblueUtil.FIELD_OBJECT_TYPE, "{\"type\": \"string\"}", quote("someEntity")); @@ -115,17 +120,18 @@ public void testFieldIsArrayFieldWithoutMatchArray() throws Exception{ * it requires two fields. * ObjectFields are not currently supported in LDAP, an exception should be thrown indicating as such. */ - @Test(expected = UnsupportedOperationException.class) + @Test public void testObjectArrayField_ThrowsException() throws Exception{ String arrayFieldName = "someObjectArray"; String arrayCountFieldName = LightblueUtil.createArrayCountFieldName(arrayFieldName); - Entry entry = buildEntry( + + expectedEx.expect(com.redhat.lightblue.util.Error.class); + expectedEx.expectMessage("{\"objectType\":\"error\",\"context\":\"dn=uid=someuid,dc=example,dc=com/" + arrayFieldName + "\",\"errorCode\":\"Unsupported Feature: object array\",\"msg\":\"" + arrayFieldName + "\"}"); + + buildEntry( arrayCountFieldName, "{\"type\": \"integer\"}, " + quote(arrayFieldName) + ": {\"type\": \"array\", \"items\": {\"type\": \"object\",\"fields\": {\"someField\": {\"type\": \"string\"}}}}", "1," + quote(arrayFieldName) + ":[{\"someField\":\"hello\"}]"); - - assertNotNull(entry); - assertNull(entry.getAttribute(arrayFieldName)); } @Test(expected = IllegalArgumentException.class) From 4097c7e387479c927061c2dff3b885927e4c9c33 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Wed, 28 Jan 2015 16:10:27 -0500 Subject: [PATCH 09/13] use Error push/pop and throw Errors over Exceptions --- .../lightblue/crud/ldap/EntryBuilder.java | 7 ++++--- .../crud/ldap/LdapCRUDController.java | 2 +- .../crud/ldap/TranslatorFromJson.java | 10 ++++------ .../lightblue/crud/ldap/EntryBuilderTest.java | 20 ++++++++++++++++++- 4 files changed, 28 insertions(+), 11 deletions(-) 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 1755ced..b7ea705 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 @@ -79,9 +79,10 @@ 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."); + throw Error.get("Invalid Field Definition", "'" + LdapConstant.ATTRIBUTE_DN + "' should not be included as its value will be" + + " derived from the metadata.basedn and" + + " the metadata.uniqueattr. Including the '" + LdapConstant.ATTRIBUTE_DN + + "' as an insert attribute is confusing."); } else if(LightblueUtil.isFieldObjectType(attributeName) || LightblueUtil.isFieldAnArrayCount(attributeName, getEntityMetadata().getFields())){ 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 38fd781..6301df8 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 @@ -128,7 +128,7 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx, Path uniqueFieldPath = fieldNameTranslator.translateAttributeName(store.getUniqueAttribute()); JsonNode uniqueNode = document.get(uniqueFieldPath); if(uniqueNode == null){ - throw new IllegalArgumentException(store.getUniqueAttribute() + " is a required field"); + throw Error.get("Required Field", store.getUniqueAttribute()); } String dn = createDN(store, uniqueNode.asText()); 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 60caa45..3269ded 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 @@ -36,7 +36,6 @@ 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 @@ -95,12 +94,11 @@ public void translate(JsonDoc document, T target){ * @param target - T */ protected void translate(JsonNodeCursor cursor, T target){ - Path path = cursor.getCurrentPath(); JsonNode node = cursor.getCurrentNode(); - FieldTreeNode fieldNode = md.resolve(path); + FieldTreeNode fieldNode = md.resolve(cursor.getCurrentPath()); if (fieldNode == null) { - throw new NullPointerException("No Metadata field found for: " + path.toString()); + throw Error.get("Metadata Not Found", cursor.getCurrentPath().toString()); } Error.push(fieldNode.getFullPath().getLast()); @@ -118,7 +116,7 @@ else if (fieldNode instanceof ReferenceField) { translate((ReferenceField) fieldNode, node, target); } else{ - throw new UnsupportedOperationException("Field type is not supported: " + fieldNode.getClass().getName()); + throw Error.get("Unsupported Feature: " + fieldNode.getClass().getName(), fieldNode.getFullPath().toString()); } Error.pop(); @@ -143,7 +141,7 @@ else if(arrayElement instanceof ObjectArrayElement){ translateObjectArray(field, cursor, target); } else{ - throw new UnsupportedOperationException("ArrayElement type is not supported: " + arrayElement.getClass().getName()); + throw Error.get("Unsupported Feature: " + arrayElement.getClass().getName(), field.getFullPath().toString()); } cursor.parent(); diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java index c4b7b00..c163218 100644 --- a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java +++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java @@ -32,6 +32,7 @@ import javax.xml.bind.DatatypeConverter; +import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -49,6 +50,7 @@ import com.redhat.lightblue.metadata.EntityMetadata; import com.redhat.lightblue.metadata.types.DateType; import com.redhat.lightblue.test.MetadataUtil; +import com.redhat.lightblue.util.Error; import com.redhat.lightblue.util.JsonDoc; import com.unboundid.ldap.sdk.Entry; import com.unboundid.util.StaticUtils; @@ -81,6 +83,11 @@ public static class SpecializedTests { @Rule public ExpectedException expectedEx = ExpectedException.none(); + @After + public void after(){ + Error.reset(); + } + @Test public void testFieldIsObjectType() throws Exception{ Entry entry = buildEntry(LightblueUtil.FIELD_OBJECT_TYPE, "{\"type\": \"string\"}", quote("someEntity")); @@ -134,8 +141,14 @@ public void testObjectArrayField_ThrowsException() throws Exception{ "1," + quote(arrayFieldName) + ":[{\"someField\":\"hello\"}]"); } - @Test(expected = IllegalArgumentException.class) + /** + * DN fields should never be defined as they are technically not attributes. + */ + @Test public void testFieldIsDN() throws Exception{ + expectedEx.expect(com.redhat.lightblue.util.Error.class); + expectedEx.expectMessage("{\"objectType\":\"error\",\"context\":\"dn=uid=someuid,dc=example,dc=com/dn\",\"errorCode\":\"Invalid Field Definition\",\"msg\":\"'dn' should not be included as its value will be derived from the metadata.basedn and the metadata.uniqueattr. Including the 'dn' as an insert attribute is confusing.\"}"); + buildEntry(LdapConstant.ATTRIBUTE_DN, "{\"type\": \"string\"}", quote("uid=someuid,dc=example,dc=com")); } @@ -167,6 +180,11 @@ public static Collection data() { }); } + @After + public void after(){ + Error.reset(); + } + private final String fieldName = "testfield"; private final String metadataType; private final String crudValue; From 6d1fefdcb951e733df504a77a9ce3e559fa6d7e3 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Fri, 30 Jan 2015 16:38:33 -0500 Subject: [PATCH 10/13] changes based on feedback --- .../lightblue/common/ldap/LdapErrorCode.java | 36 +++ .../lightblue/crud/ldap/EntryBuilder.java | 24 +- .../crud/ldap/LdapCRUDController.java | 75 +----- .../lightblue/crud/ldap/LdapCrudUtil.java | 55 +++++ .../crud/ldap/LdapMetadataListener.java | 150 +++++++++++ .../crud/ldap/TranslatorFromJson.java | 47 ++-- .../ldap/translator/ResultTranslator.java | 2 +- .../lightblue/crud/ldap/EntryBuilderTest.java | 6 +- .../lightblue/crud/ldap/LdapCrudUtilTest.java | 88 +++++++ .../crud/ldap/LdapMetadataListenerTest.java | 232 ++++++++++++++++++ ...ITCaseLdapCRUDController_Objects_Test.java | 18 ++ .../metadata/ldap/model/LdapMetadata.java | 20 +- .../ldap/parser/LdapPropertyParser.java | 7 +- .../metadata/ldap/model/LdapMetadataTest.java | 24 +- .../ldap/parser/LdapPropertyParserTest.java | 13 +- 15 files changed, 660 insertions(+), 137 deletions(-) create mode 100644 lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapErrorCode.java create mode 100644 lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCrudUtil.java create mode 100644 lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapMetadataListener.java create mode 100644 lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapCrudUtilTest.java create mode 100644 lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/LdapMetadataListenerTest.java 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-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 b7ea705..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,11 +24,13 @@ 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.MetadataConstants; import com.redhat.lightblue.metadata.SimpleField; import com.redhat.lightblue.metadata.Type; import com.redhat.lightblue.metadata.types.BinaryType; @@ -54,11 +56,17 @@ public EntryBuilder(EntityMetadata md, LdapFieldNameTranslator fieldNameTranslat } public Entry build(String dn, JsonDoc document){ + Error.push("build entry"); Error.push(LdapConstant.ATTRIBUTE_DN + "=" + dn); - Entry entry = new Entry(dn); - translate(document, entry); - Error.pop(); - return entry; + try{ + Entry entry = new Entry(dn); + translate(document, entry); + return entry; + } + finally{ + Error.pop(); + Error.pop(); + } } @Override @@ -79,10 +87,8 @@ protected void translate(SimpleField field, JsonNode node, Entry target) { String attributeName = fieldNameTranslator.translateFieldName(field.getFullPath()); if(LdapConstant.ATTRIBUTE_DN.equalsIgnoreCase(attributeName)){ - throw Error.get("Invalid Field Definition", "'" + LdapConstant.ATTRIBUTE_DN + "' should not be included as its value will be" - + " derived from the metadata.basedn and" - + " the metadata.uniqueattr. Including the '" + LdapConstant.ATTRIBUTE_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())){ @@ -127,7 +133,7 @@ protected void translateSimpleArray(ArrayField field, List items, Entry @Override protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Entry target) { - throw Error.get("Unsupported Feature: object array", field.getFullPath().toString()); + 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 6301df8..92b2eb9 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 @@ -44,24 +44,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,7 +100,7 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx, EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName()); LdapDataStore store = getLdapDataStore(md); - LdapFieldNameTranslator fieldNameTranslator = getLdapFieldNameTranslator(md); + LdapFieldNameTranslator fieldNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md); FieldAccessRoleEvaluator roles = new FieldAccessRoleEvaluator(md, ctx.getCallerRoles()); EntryBuilder entryBuilder = new EntryBuilder(md, fieldNameTranslator); @@ -128,7 +121,7 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx, Path uniqueFieldPath = fieldNameTranslator.translateAttributeName(store.getUniqueAttribute()); JsonNode uniqueNode = document.get(uniqueFieldPath); if(uniqueNode == null){ - throw Error.get("Required Field", store.getUniqueAttribute()); + throw Error.get(MetadataConstants.ERR_PARSE_MISSING_ELEMENT, store.getUniqueAttribute()); } String dn = createDN(store, uniqueNode.asText()); @@ -206,7 +199,7 @@ public CRUDFindResponse find(CRUDOperationContext ctx, LDAPConnection connection = getNewLdapConnection(store); - LdapFieldNameTranslator fieldNameTranslator = getLdapFieldNameTranslator(md); + LdapFieldNameTranslator fieldNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md); try { //TODO: Support scopes other than SUB @@ -265,43 +258,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 ldapNameTranslator = getLdapFieldNameTranslator(md); - - Fields fields = md.getEntitySchema().getFields(); - Path dnFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); - if(!fields.has(dnFieldPath.toString())){ - fields.addNew(new SimpleField(dnFieldPath.toString(), StringType.TYPE)); - } - - Path objectClassFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS); - if(!fields.has(objectClassFieldPath.toString())){ - fields.addNew(new ArrayField(objectClassFieldPath.toString(), new SimpleArrayElement(StringType.TYPE))); - fields.addNew(new SimpleField(LightblueUtil.createArrayCountFieldName(objectClassFieldPath.toString()), 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(); } /** @@ -320,26 +277,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 @@ -418,7 +355,7 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName()); JsonNodeFactory factory = ctx.getFactory().getNodeFactory(); - LdapFieldNameTranslator fieldNameTranslator = getLdapFieldNameTranslator(md); + LdapFieldNameTranslator fieldNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md); Set requiredAttributeNames = translateFieldNames(fieldNameTranslator, gatherRequiredFields(md, projection, null, null)); Projector projector = Projector.getInstance( 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..91d2b36 --- /dev/null +++ b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapMetadataListener.java @@ -0,0 +1,150 @@ +/* + 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.common.ldap.LightblueUtil; +import com.redhat.lightblue.metadata.ArrayElement; +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.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; + +/** + * 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!! + } + + /** + * 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 + + Path dnFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); + try{ + FieldTreeNode dnNode = md.resolve(dnFieldPath); + if((!(dnNode instanceof SimpleField)) || (!(dnNode.getType() instanceof StringType))){ + throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, dnNode.getFullPath().toString()); + } + } + catch(Error e){ + if(e.getErrorCode().equals(MetadataConstants.ERR_FIELD_WRONG_TYPE)){ + throw e; + } + addFieldToParent(md, dnFieldPath, new SimpleField(dnFieldPath.getLast(), StringType.TYPE)); + } + + Path objectClassFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS); + try{ + FieldTreeNode objectClassNode = md.resolve(objectClassFieldPath); + if(!(objectClassNode instanceof ArrayField)){ + throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassNode.getFullPath().toString()); + } + ArrayField objectClassField = (ArrayField) objectClassNode; + ArrayElement arrayElement = objectClassField.getElement(); + if((!(arrayElement instanceof SimpleArrayElement)) || (!(arrayElement.getType() instanceof StringType))){ + throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassField.getFullPath().toString()); + } + } + catch(Error e){ + if(e.getErrorCode().equals(MetadataConstants.ERR_FIELD_WRONG_TYPE)){ + throw e; + } + addFieldToParent(md, objectClassFieldPath, new ArrayField(objectClassFieldPath.getLast(), new SimpleArrayElement(StringType.TYPE))); + } + + Path objectClassCountFieldPath = objectClassFieldPath.mutableCopy().pop().push(LightblueUtil.createArrayCountFieldName(objectClassFieldPath.getLast())); + try{ + FieldTreeNode objectClassCountNode = md.resolve(objectClassCountFieldPath); + if((!(objectClassCountNode instanceof SimpleField)) || (!(objectClassCountNode.getType() instanceof IntegerType))){ + throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassCountNode.getFullPath().toString()); + } + } + catch(Error e){ + if(e.getErrorCode().equals(MetadataConstants.ERR_FIELD_WRONG_TYPE)){ + throw e; + } + addFieldToParent(md, objectClassCountFieldPath, new SimpleField(objectClassCountFieldPath.getLast(), IntegerType.TYPE)); + } + } + + /** + * 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); + } + + @Override + public void afterUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity) { + //Do Nothing!! + } + + @Override + public void afterCreateNewSchema(Metadata m, EntityMetadata md) { + //Do Nothing!! + } + +} 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 3269ded..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,10 +23,12 @@ 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; @@ -97,35 +99,33 @@ protected void translate(JsonNodeCursor cursor, T target){ JsonNode node = cursor.getCurrentNode(); FieldTreeNode fieldNode = md.resolve(cursor.getCurrentPath()); - if (fieldNode == null) { - throw Error.get("Metadata Not Found", cursor.getCurrentPath().toString()); - } - Error.push(fieldNode.getFullPath().getLast()); - if (fieldNode instanceof SimpleField) { - translate((SimpleField) fieldNode, node, target); - } - else if (fieldNode instanceof ObjectField) { - translate((ObjectField) fieldNode, cursor, target); + 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, target); + finally{ + Error.pop(); } - else if (fieldNode instanceof ReferenceField) { - translate((ReferenceField) fieldNode, node, target); - } - else{ - throw Error.get("Unsupported Feature: " + fieldNode.getClass().getName(), fieldNode.getFullPath().toString()); - } - - Error.pop(); } 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(); @@ -141,7 +141,7 @@ else if(arrayElement instanceof ObjectArrayElement){ translateObjectArray(field, cursor, target); } else{ - throw Error.get("Unsupported Feature: " + arrayElement.getClass().getName(), field.getFullPath().toString()); + throw Error.get(LdapErrorCode.ERR_UNSUPPORTED_FEATURE + arrayElement.getClass().getName(), field.getFullPath().toString()); } cursor.parent(); @@ -149,8 +149,7 @@ else if(arrayElement instanceof ObjectArrayElement){ protected void translate(ObjectField field, JsonNodeCursor cursor, T target){ if(!cursor.firstChild()){ - //TODO: throw exception? - return; + throw Error.get(MetadataConstants.ERR_ILL_FORMED_METADATA, cursor.getCurrentPath().toString()); } do { 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 2a367f7..b6a1fa1 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 @@ -87,7 +87,7 @@ private ObjectNode toJson(SearchResultEntry entry, FieldCursor fieldCursor, Fiel do { Path fieldPath = fieldCursor.getCurrentPath(); - if(dnPath.matches(fieldPath)){ + if(dnPath.equals(fieldPath)){ //DN is not handled as a normal attribute, can be skipped. continue; } diff --git a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java index c163218..d6ab029 100644 --- a/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java +++ b/lightblue-ldap-crud/src/test/java/com/redhat/lightblue/crud/ldap/EntryBuilderTest.java @@ -43,6 +43,7 @@ import org.junit.runners.Suite.SuiteClasses; import com.redhat.lightblue.common.ldap.LdapConstant; +import com.redhat.lightblue.common.ldap.LdapErrorCode; import com.redhat.lightblue.common.ldap.LightblueUtil; import com.redhat.lightblue.crud.ldap.EntryBuilderTest.ParameterizedTests; import com.redhat.lightblue.crud.ldap.EntryBuilderTest.SpecializedTests; @@ -133,7 +134,7 @@ public void testObjectArrayField_ThrowsException() throws Exception{ String arrayCountFieldName = LightblueUtil.createArrayCountFieldName(arrayFieldName); expectedEx.expect(com.redhat.lightblue.util.Error.class); - expectedEx.expectMessage("{\"objectType\":\"error\",\"context\":\"dn=uid=someuid,dc=example,dc=com/" + arrayFieldName + "\",\"errorCode\":\"Unsupported Feature: object array\",\"msg\":\"" + arrayFieldName + "\"}"); + expectedEx.expectMessage("{\"objectType\":\"error\",\"context\":\"build entry/dn=uid=someuid,dc=example,dc=com/" + arrayFieldName + "\",\"errorCode\":\"" + LdapErrorCode.ERR_UNSUPPORTED_FEATURE_OBJECT_ARRAY + "\",\"msg\":\"" + arrayFieldName + "\"}"); buildEntry( arrayCountFieldName, @@ -147,8 +148,7 @@ public void testObjectArrayField_ThrowsException() throws Exception{ @Test public void testFieldIsDN() throws Exception{ expectedEx.expect(com.redhat.lightblue.util.Error.class); - expectedEx.expectMessage("{\"objectType\":\"error\",\"context\":\"dn=uid=someuid,dc=example,dc=com/dn\",\"errorCode\":\"Invalid Field Definition\",\"msg\":\"'dn' should not be included as its value will be derived from the metadata.basedn and the metadata.uniqueattr. Including the 'dn' as an insert attribute is confusing.\"}"); - + expectedEx.expectMessage("{\"objectType\":\"error\",\"context\":\"build entry/dn=uid=someuid,dc=example,dc=com/dn\",\"errorCode\":\"metadata:InvalidFieldReference\",\"msg\":\"dn\"}"); buildEntry(LdapConstant.ATTRIBUTE_DN, "{\"type\": \"string\"}", quote("uid=someuid,dc=example,dc=com")); } 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-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 index 2fc2c5e..a1c4653 100644 --- 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 @@ -1,3 +1,21 @@ +/* + 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; 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 c3d4b4e..a36da56 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 @@ -34,37 +34,37 @@ */ public class LdapMetadata implements LdapFieldNameTranslator{ - private final Map fieldsToAttributes = new HashMap(); + private final Map fieldsToAttributes = new HashMap(); /** * 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(Path path){ - String attributeName = fieldsToAttributes.get(path.toString()); + String attributeName = fieldsToAttributes.get(path); if(attributeName != null){ return attributeName; } - String last = path.getLast(); + Path last = path.suffix(1); attributeName = fieldsToAttributes.get(last); if(attributeName != null){ return attributeName; } - return last; + return last.toString(); } @Override public Path translateAttributeName(String attributeName){ - for(Entry f2a : fieldsToAttributes.entrySet()){ + for(Entry f2a : fieldsToAttributes.entrySet()){ if(f2a.getValue().equalsIgnoreCase(attributeName)){ - return new Path(f2a.getKey()); + return f2a.getKey(); } } return new Path(attributeName); @@ -74,8 +74,8 @@ public Path translateAttributeName(String attributeName){ * 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 9c5e1c4..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 @@ -33,19 +33,19 @@ public class LdapMetadataTest { @Test public void testTranslateFieldName(){ - String fieldName = "fakeFieldName"; + Path fieldName = new Path("fakeFieldName"); String attributeName = "fakeAttributeName"; LdapMetadata metadata = new LdapMetadata(); metadata.addFieldToAttribute(fieldName, attributeName); - metadata.addFieldToAttribute("anotherField", "anotherAttribute"); + metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute"); assertEquals(attributeName, metadata.translateFieldName(new Path(fieldName))); } @Test public void testTranslateFieldName_WithPath(){ - String fieldName = "fakePath.fakeFieldName"; + Path fieldName = new Path("fakePath.fakeFieldName"); String attributeName = "fakeAttributeName"; LdapMetadata metadata = new LdapMetadata(); @@ -56,7 +56,7 @@ public void testTranslateFieldName_WithPath(){ @Test public void testTranslateFieldName_WithPath_MatchesOnTail(){ - String fieldName = "fakeFieldName"; + Path fieldName = new Path("fakeFieldName"); String pathedFieldName = "fakePath." + fieldName; String attributeName = "fakeAttributeName"; @@ -75,26 +75,26 @@ public void testTranslateFieldName_ValueNotPresent(){ @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("anotherField", "anotherAttribute"); + metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute"); - assertEquals(fieldName, metadata.translateAttributeName(attributeName).toString()); + assertEquals(fieldName, metadata.translateAttributeName(attributeName)); } @Test public void testTranslateAttributeName_WithPath(){ - String fieldName = "somePath.fakeFieldName"; + Path fieldName = new Path("somePath.fakeFieldName"); String attributeName = "fakeAttributeName"; LdapMetadata metadata = new LdapMetadata(); metadata.addFieldToAttribute(fieldName, attributeName); - metadata.addFieldToAttribute("anotherField", "anotherAttribute"); + metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute"); - assertEquals(fieldName, metadata.translateAttributeName(attributeName).toString()); + assertEquals(fieldName, metadata.translateAttributeName(attributeName)); } @Test @@ -107,9 +107,9 @@ public void testTranslateAttributeName_ValueNotPresent(){ @Test public void testGetFieldsToAttributes_AssertImmutable(){ LdapMetadata metadata = new LdapMetadata(); - metadata.addFieldToAttribute("anotherField", "anotherAttribute"); + metadata.addFieldToAttribute(new Path("anotherField"), "anotherAttribute"); - Map fieldsToAttributes = metadata.getFieldsToAttributes(); + Map fieldsToAttributes = metadata.getFieldsToAttributes(); assertNotNull(fieldsToAttributes); 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("{}"); From 8ebf356e402a8f586101f5ea38f92e3761df8bb4 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Mon, 2 Feb 2015 09:46:06 -0500 Subject: [PATCH 11/13] use BiMap over iterating of Map values to find key --- .../metadata/ldap/model/LdapMetadata.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 a36da56..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,8 +20,9 @@ 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; @@ -34,7 +35,7 @@ */ 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. @@ -62,12 +63,13 @@ public String translateFieldName(Path path){ @Override public Path translateAttributeName(String attributeName){ - for(Entry f2a : fieldsToAttributes.entrySet()){ - if(f2a.getValue().equalsIgnoreCase(attributeName)){ - return f2a.getKey(); - } + Path fieldPath = fieldsToAttributes.inverse().get(attributeName); + + if(fieldPath == null){ + return new Path(attributeName); } - return new Path(attributeName); + + return fieldPath; } /** From da8d967ae6e663647467147f4dbe2d90d7d6b069 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Mon, 2 Feb 2015 11:03:08 -0500 Subject: [PATCH 12/13] cleanup LdapMetadataListener --- .../crud/ldap/LdapMetadataListener.java | 105 +++++++++++------- 1 file changed, 63 insertions(+), 42 deletions(-) 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 index 91d2b36..7079033 100644 --- 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 @@ -52,6 +52,16 @@ 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. */ @@ -60,51 +70,72 @@ public void beforeCreateNewSchema(Metadata m, EntityMetadata md) { LdapFieldNameTranslator ldapNameTranslator = LdapCrudUtil.getLdapFieldNameTranslator(md); //TODO: check for array index or Path.any - Path dnFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN); + ensureDnField(md, ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN)); + + Path objectClassFieldPath = ensureObjectClassField(md, + ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS)); + + ensureObjectClassCountField(md, + objectClassFieldPath.mutableCopy().pop().push(LightblueUtil.createArrayCountFieldName(objectClassFieldPath.getLast()))); + } + + /** + * Ensures the objectClass count 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 ensureObjectClassCountField(EntityMetadata md, Path objectClassCountFieldPath) { + FieldTreeNode objectClassCountNode; try{ - FieldTreeNode dnNode = md.resolve(dnFieldPath); - if((!(dnNode instanceof SimpleField)) || (!(dnNode.getType() instanceof StringType))){ - throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, dnNode.getFullPath().toString()); - } + objectClassCountNode = md.resolve(objectClassCountFieldPath); } catch(Error e){ - if(e.getErrorCode().equals(MetadataConstants.ERR_FIELD_WRONG_TYPE)){ - throw e; - } - addFieldToParent(md, dnFieldPath, new SimpleField(dnFieldPath.getLast(), StringType.TYPE)); + addFieldToParent(md, objectClassCountFieldPath, + (Field)(objectClassCountNode = new SimpleField(objectClassCountFieldPath.getLast(), IntegerType.TYPE))); + } + if((!(objectClassCountNode instanceof SimpleField)) || (!(objectClassCountNode.getType() instanceof IntegerType))){ + throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassCountNode.getFullPath().toString()); } + } - Path objectClassFieldPath = ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS); + /** + * 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 Path ensureObjectClassField(EntityMetadata md, Path objectClassFieldPath) { + FieldTreeNode objectClassNode; try{ - FieldTreeNode objectClassNode = md.resolve(objectClassFieldPath); - if(!(objectClassNode instanceof ArrayField)){ - throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassNode.getFullPath().toString()); - } - ArrayField objectClassField = (ArrayField) objectClassNode; - ArrayElement arrayElement = objectClassField.getElement(); - if((!(arrayElement instanceof SimpleArrayElement)) || (!(arrayElement.getType() instanceof StringType))){ - throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassField.getFullPath().toString()); - } + objectClassNode = md.resolve(objectClassFieldPath); } catch(Error e){ - if(e.getErrorCode().equals(MetadataConstants.ERR_FIELD_WRONG_TYPE)){ - throw e; - } - addFieldToParent(md, objectClassFieldPath, new ArrayField(objectClassFieldPath.getLast(), new SimpleArrayElement(StringType.TYPE))); + 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; + ArrayElement arrayElement = objectClassField.getElement(); + if((!(arrayElement instanceof SimpleArrayElement)) || (!(arrayElement.getType() instanceof StringType))){ + throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassField.getFullPath().toString()); + } + return objectClassFieldPath; + } - Path objectClassCountFieldPath = objectClassFieldPath.mutableCopy().pop().push(LightblueUtil.createArrayCountFieldName(objectClassFieldPath.getLast())); + /** + * 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{ - FieldTreeNode objectClassCountNode = md.resolve(objectClassCountFieldPath); - if((!(objectClassCountNode instanceof SimpleField)) || (!(objectClassCountNode.getType() instanceof IntegerType))){ - throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassCountNode.getFullPath().toString()); - } + dnNode = md.resolve(dnFieldPath); } catch(Error e){ - if(e.getErrorCode().equals(MetadataConstants.ERR_FIELD_WRONG_TYPE)){ - throw e; - } - addFieldToParent(md, objectClassCountFieldPath, new SimpleField(objectClassCountFieldPath.getLast(), IntegerType.TYPE)); + addFieldToParent(md, dnFieldPath, + (Field)(dnNode = new SimpleField(dnFieldPath.getLast(), StringType.TYPE))); + } + if((!(dnNode instanceof SimpleField)) || (!(dnNode.getType() instanceof StringType))){ + throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, dnNode.getFullPath().toString()); } } @@ -137,14 +168,4 @@ else if (parent instanceof ObjectArrayElement){ fields.addNew(newField); } - @Override - public void afterUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity) { - //Do Nothing!! - } - - @Override - public void afterCreateNewSchema(Metadata m, EntityMetadata md) { - //Do Nothing!! - } - } From dfd0c0db203ed0bad403ee0e7fe34f8755231623 Mon Sep 17 00:00:00 2001 From: Dennis Crissman Date: Mon, 2 Feb 2015 14:41:11 -0500 Subject: [PATCH 13/13] adjustments to better utilize the tools provided by core --- .../crud/ldap/LdapCRUDController.java | 7 ++-- .../crud/ldap/LdapMetadataListener.java | 35 ++++--------------- .../ldap/translator/ResultTranslator.java | 6 ++-- 3 files changed, 12 insertions(+), 36 deletions(-) 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 92b2eb9..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; @@ -376,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(dnFieldPath.toString(), 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/LdapMetadataListener.java b/lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapMetadataListener.java index 7079033..b71eda0 100644 --- 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 @@ -20,8 +20,6 @@ import com.redhat.lightblue.common.ldap.LdapConstant; 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.EntityInfo; import com.redhat.lightblue.metadata.EntityMetadata; @@ -33,9 +31,9 @@ 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.IntegerType; import com.redhat.lightblue.metadata.types.StringType; import com.redhat.lightblue.util.Error; import com.redhat.lightblue.util.Path; @@ -72,36 +70,17 @@ public void beforeCreateNewSchema(Metadata m, EntityMetadata md) { ensureDnField(md, ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_DN)); - Path objectClassFieldPath = ensureObjectClassField(md, + ensureObjectClassField(md, ldapNameTranslator.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS)); - ensureObjectClassCountField(md, - objectClassFieldPath.mutableCopy().pop().push(LightblueUtil.createArrayCountFieldName(objectClassFieldPath.getLast()))); - } - - /** - * Ensures the objectClass count 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 ensureObjectClassCountField(EntityMetadata md, Path objectClassCountFieldPath) { - FieldTreeNode objectClassCountNode; - try{ - objectClassCountNode = md.resolve(objectClassCountFieldPath); - } - catch(Error e){ - addFieldToParent(md, objectClassCountFieldPath, - (Field)(objectClassCountNode = new SimpleField(objectClassCountFieldPath.getLast(), IntegerType.TYPE))); - } - if((!(objectClassCountNode instanceof SimpleField)) || (!(objectClassCountNode.getType() instanceof IntegerType))){ - throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassCountNode.getFullPath().toString()); - } + 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 Path ensureObjectClassField(EntityMetadata md, Path objectClassFieldPath) { + private void ensureObjectClassField(EntityMetadata md, Path objectClassFieldPath) { FieldTreeNode objectClassNode; try{ objectClassNode = md.resolve(objectClassFieldPath); @@ -114,11 +93,9 @@ private Path ensureObjectClassField(EntityMetadata md, Path objectClassFieldPath throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassNode.getFullPath().toString()); } ArrayField objectClassField = (ArrayField) objectClassNode; - ArrayElement arrayElement = objectClassField.getElement(); - if((!(arrayElement instanceof SimpleArrayElement)) || (!(arrayElement.getType() instanceof StringType))){ + if(!(objectClassField.getElement().getType() instanceof StringType)){ throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, objectClassField.getFullPath().toString()); } - return objectClassFieldPath; } /** @@ -134,7 +111,7 @@ private void ensureDnField(EntityMetadata md, Path dnFieldPath) { addFieldToParent(md, dnFieldPath, (Field)(dnNode = new SimpleField(dnFieldPath.getLast(), StringType.TYPE))); } - if((!(dnNode instanceof SimpleField)) || (!(dnNode.getType() instanceof StringType))){ + if(!(dnNode.getType() instanceof StringType)){ throw Error.get(MetadataConstants.ERR_FIELD_WRONG_TYPE, dnNode.getFullPath().toString()); } } 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 b6a1fa1..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 @@ -71,9 +71,9 @@ public DocCtx translate(SearchResultEntry entry){ Fields fields = md.getFields(); if (cursor.firstChild()) { - ObjectNode node = toJson(entry, cursor, fields); - node.set(dnPath.toString(), StringType.TYPE.toJson(factory, entry.getDN())); - return new DocCtx(new JsonDoc(node)); + 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?