Skip to content

Commit 7cc17a1

Browse files
committed
Merge pull request #39 from dcrissman/issue31-field-to-attribute-mapping
Issue31 field to attribute mapping
2 parents 490de5a + 75e5c93 commit 7cc17a1

File tree

32 files changed

+1145
-100
lines changed

32 files changed

+1145
-100
lines changed

lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapConstant.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
public final class LdapConstant {
2727

2828
public static final String BACKEND = "ldap";
29-
public static final String FIELD_DN = "dn";
30-
public static final String FIELD_OBJECT_CLASS = "objectClass";
29+
public static final String ATTRIBUTE_DN = "dn";
30+
public static final String ATTRIBUTE_OBJECT_CLASS = "objectClass";
3131

3232
private LdapConstant(){}
3333

lightblue-ldap-common/src/main/java/com/redhat/lightblue/common/ldap/LdapDataStore.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ public void setBaseDN(String baseDN) {
5353
this.baseDN = baseDN;
5454
}
5555

56-
public String getUniqueField() {
56+
public String getUniqueAttribute() {
5757
return uniqueField;
5858
}
5959

60-
public void setUniqueField(String uniqueField) {
60+
public void setUniqueAttribute(String uniqueField) {
6161
this.uniqueField = uniqueField;
6262
}
6363

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright 2015 Red Hat, Inc. and/or its affiliates.
3+
4+
This file is part of lightblue.
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
package com.redhat.lightblue.common.ldap;
20+
21+
/**
22+
* Represents a class that can translate back and forth between a fieldName and an LDAP attributeName.
23+
*
24+
* @author dcrissman
25+
*/
26+
public interface LdapFieldNameTranslator {
27+
28+
/**
29+
* Returns the attributeName with the given fieldName.
30+
* @param fieldName - metadata field name
31+
* @return ldap attributeName or the fieldName back at you if no mapping is present.
32+
*/
33+
public String translateFieldName(String fieldName);
34+
35+
/**
36+
* Returns the fieldName with the given attributeName.
37+
* @param attributeName - ldap attribute name
38+
* @return metadata fieldName or the attributeName back at you if no mapping is present.
39+
*/
40+
public String translateAttributeName(String attributeName);
41+
42+
}

lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/EntryBuilder.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import com.fasterxml.jackson.databind.JsonNode;
2626
import com.redhat.lightblue.common.ldap.LdapConstant;
27+
import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
2728
import com.redhat.lightblue.common.ldap.LightblueUtil;
2829
import com.redhat.lightblue.metadata.ArrayElement;
2930
import com.redhat.lightblue.metadata.ArrayField;
@@ -46,8 +47,11 @@
4647
*/
4748
public class EntryBuilder extends TranslatorFromJson<Entry>{
4849

49-
public EntryBuilder(EntityMetadata md){
50+
private final LdapFieldNameTranslator fieldNameTranslator;
51+
52+
public EntryBuilder(EntityMetadata md, LdapFieldNameTranslator fieldNameTranslator){
5053
super(md);
54+
this.fieldNameTranslator = fieldNameTranslator;
5155
}
5256

5357
public Entry build(String dn, JsonDoc document){
@@ -71,15 +75,15 @@ else if(type instanceof BinaryType){
7175

7276
@Override
7377
protected void translate(SimpleField field, Path path, JsonNode node, Entry target) {
74-
String fieldName = field.getName();
78+
String attributeName = fieldNameTranslator.translateFieldName(field.getName());
7579

76-
if(LdapConstant.FIELD_DN.equalsIgnoreCase(fieldName)){
80+
if(LdapConstant.ATTRIBUTE_DN.equalsIgnoreCase(attributeName)){
7781
throw new IllegalArgumentException(
7882
"'dn' should not be included as it's value will be derived from the metadata.basedn and" +
7983
" the metadata.uniqueattr. Including the 'dn' as an insert attribute is confusing.");
8084
}
81-
else if(LightblueUtil.isFieldObjectType(fieldName)
82-
|| LightblueUtil.isFieldAnArrayCount(fieldName, getEntityMetadata().getFields())){
85+
else if(LightblueUtil.isFieldObjectType(attributeName)
86+
|| LightblueUtil.isFieldAnArrayCount(attributeName, getEntityMetadata().getFields())){
8387
/*
8488
* Indicates the field is auto-generated for lightblue purposes. These fields
8589
* should not be inserted into LDAP.
@@ -90,10 +94,10 @@ else if(LightblueUtil.isFieldObjectType(fieldName)
9094
Type type = field.getType();
9195
Object o = fromJson(type, node);
9296
if(type instanceof BinaryType) {
93-
target.addAttribute(fieldName, (byte[])o);
97+
target.addAttribute(attributeName, (byte[])o);
9498
}
9599
else{
96-
target.addAttribute(fieldName, o.toString());
100+
target.addAttribute(attributeName, o.toString());
97101
}
98102
}
99103

@@ -106,21 +110,21 @@ protected void translate(ObjectField field, Path path, JsonNode node, Entry targ
106110
protected void translateSimpleArray(ArrayField field, Path path, List<Object> items, Entry target) {
107111
ArrayElement arrayElement = field.getElement();
108112
Type arrayElementType = arrayElement.getType();
109-
String fieldName = field.getName();
113+
String attributeName = fieldNameTranslator.translateFieldName(field.getName());
110114

111115
if(arrayElementType instanceof BinaryType){
112116
List<byte[]> bytes = new ArrayList<byte[]>();
113117
for(Object item : items){
114118
bytes.add((byte[])item);
115119
}
116-
target.addAttribute(fieldName, bytes.toArray(new byte[0][]));
120+
target.addAttribute(attributeName, bytes.toArray(new byte[0][]));
117121
}
118122
else{
119123
List<String> values = new ArrayList<String>();
120124
for(Object item : items){
121125
values.add(item.toString());
122126
}
123-
target.addAttribute(fieldName, values);
127+
target.addAttribute(attributeName, values);
124128
}
125129
}
126130

lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCRUDController.java

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package com.redhat.lightblue.crud.ldap;
2020

2121
import java.util.ArrayList;
22+
import java.util.Collection;
2223
import java.util.HashMap;
2324
import java.util.HashSet;
2425
import java.util.List;
@@ -32,6 +33,7 @@
3233
import com.redhat.lightblue.common.ldap.DBResolver;
3334
import com.redhat.lightblue.common.ldap.LdapConstant;
3435
import com.redhat.lightblue.common.ldap.LdapDataStore;
36+
import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
3537
import com.redhat.lightblue.common.ldap.LightblueUtil;
3638
import com.redhat.lightblue.crud.CRUDController;
3739
import com.redhat.lightblue.crud.CRUDDeleteResponse;
@@ -42,6 +44,7 @@
4244
import com.redhat.lightblue.crud.CRUDUpdateResponse;
4345
import com.redhat.lightblue.crud.CrudConstants;
4446
import com.redhat.lightblue.crud.DocCtx;
47+
import com.redhat.lightblue.crud.ldap.model.TrivialLdapFieldNameTranslator;
4548
import com.redhat.lightblue.crud.ldap.translator.FilterTranslator;
4649
import com.redhat.lightblue.crud.ldap.translator.ResultTranslator;
4750
import com.redhat.lightblue.crud.ldap.translator.SortTranslator;
@@ -104,9 +107,10 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx,
104107

105108
EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName());
106109
LdapDataStore store = getLdapDataStore(md);
110+
LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
107111

108112
FieldAccessRoleEvaluator roles = new FieldAccessRoleEvaluator(md, ctx.getCallerRoles());
109-
EntryBuilder entryBuilder = new EntryBuilder(md);
113+
EntryBuilder entryBuilder = new EntryBuilder(md, property);
110114

111115
//Create Entry instances for each document.
112116
List<com.unboundid.ldap.sdk.Entry> entries = new ArrayList<com.unboundid.ldap.sdk.Entry>();
@@ -123,9 +127,10 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx,
123127

124128
JsonNode rootNode = document.getRoot();
125129

126-
JsonNode uniqueNode = rootNode.get(store.getUniqueField());
130+
String uniqueFieldName = property.translateAttributeName(store.getUniqueAttribute());
131+
JsonNode uniqueNode = rootNode.get(uniqueFieldName);
127132
if(uniqueNode == null){
128-
throw new IllegalArgumentException(store.getUniqueField() + " is a required field");
133+
throw new IllegalArgumentException(uniqueFieldName + " is a required field");
129134
}
130135

131136
String dn = createDN(store, uniqueNode.asText());
@@ -203,15 +208,17 @@ public CRUDFindResponse find(CRUDOperationContext ctx,
203208

204209
LDAPConnection connection = getNewLdapConnection(store);
205210

211+
LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
212+
206213
try {
207214
//TODO: Support scopes other than SUB
208215
SearchRequest request = new SearchRequest(
209216
store.getBaseDN(),
210217
SearchScope.SUB,
211-
new FilterTranslator().translate(query),
212-
collectRequiredFields(md, projection, query, sort).toArray(new String[0]));
218+
new FilterTranslator(property).translate(query),
219+
translateFieldNames(property, gatherRequiredFields(md, projection, query, sort)).toArray(new String[0]));
213220
if(sort != null){
214-
request.addControl(new ServerSideSortRequestControl(false, new SortTranslator().translate(sort)));
221+
request.addControl(new ServerSideSortRequestControl(false, new SortTranslator(property).translate(sort)));
215222
}
216223
if((from != null) && (from > 0)){
217224
int endPos = to.intValue() - from.intValue();
@@ -221,11 +228,11 @@ public CRUDFindResponse find(CRUDOperationContext ctx,
221228
SearchResult result = connection.search(request);
222229

223230
response.setSize(result.getEntryCount());
224-
ResultTranslator resultTranslator = new ResultTranslator(ctx.getFactory().getNodeFactory());
231+
ResultTranslator resultTranslator = new ResultTranslator(ctx.getFactory().getNodeFactory(), md, property);
225232
List<DocCtx> translatedDocs = new ArrayList<DocCtx>();
226233
for(SearchResultEntry entry : result.getSearchEntries()){
227234
try{
228-
translatedDocs.add(resultTranslator.translate(entry, md));
235+
translatedDocs.add(resultTranslator.translate(entry));
229236
}
230237
catch(Exception e){
231238
DocCtx erroredDoc = new DocCtx(null);
@@ -274,13 +281,18 @@ public void beforeUpdateEntityInfo(Metadata m, EntityInfo ei, boolean newEntity)
274281
*/
275282
@Override
276283
public void beforeCreateNewSchema(Metadata m, EntityMetadata md) {
284+
LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
285+
277286
Fields fields = md.getEntitySchema().getFields();
278-
if(!fields.has(LdapConstant.FIELD_DN)){
279-
fields.addNew(new SimpleField(LdapConstant.FIELD_DN, StringType.TYPE));
287+
String dnFieldName = property.translateAttributeName(LdapConstant.ATTRIBUTE_DN);
288+
if(!fields.has(dnFieldName)){
289+
fields.addNew(new SimpleField(dnFieldName, StringType.TYPE));
280290
}
281-
if(!fields.has(LdapConstant.FIELD_OBJECT_CLASS)){
282-
fields.addNew(new ArrayField(LdapConstant.FIELD_OBJECT_CLASS, new SimpleArrayElement(StringType.TYPE)));
283-
fields.addNew(new SimpleField(LightblueUtil.createArrayCountFieldName(LdapConstant.FIELD_OBJECT_CLASS), IntegerType.TYPE));
291+
292+
String objectClassFieldName = property.translateAttributeName(LdapConstant.ATTRIBUTE_OBJECT_CLASS);
293+
if(!fields.has(objectClassFieldName)){
294+
fields.addNew(new ArrayField(objectClassFieldName, new SimpleArrayElement(StringType.TYPE)));
295+
fields.addNew(new SimpleField(LightblueUtil.createArrayCountFieldName(objectClassFieldName), IntegerType.TYPE));
284296
}
285297
}
286298

@@ -312,6 +324,26 @@ private LdapDataStore getLdapDataStore(EntityMetadata md){
312324
return (LdapDataStore) store;
313325
}
314326

327+
/**
328+
* Shortcut method to get and return the {@link LdapFieldNameTranslator} on the passed
329+
* in {@link EntityMetadata}.
330+
* @param md - {@link EntityMetadata}.
331+
* @return {@link LdapFieldNameTranslator}
332+
* @throws IllegalArgumentException if an invalid object is found.
333+
*/
334+
private LdapFieldNameTranslator getLdapFieldNameTranslator(EntityMetadata md){
335+
Object o = md.getEntityInfo().getProperties().get(LdapConstant.BACKEND);
336+
337+
if(o == null){
338+
return new TrivialLdapFieldNameTranslator();
339+
}
340+
341+
if(!(o instanceof LdapFieldNameTranslator)){
342+
throw new IllegalArgumentException("Object of type " + o.getClass() + " is not supported.");
343+
}
344+
return (LdapFieldNameTranslator) o;
345+
}
346+
315347
/**
316348
* Creates and returns a unique DN.
317349
* @param store - {@link LdapDataStore} to use as the BaseDN and field that
@@ -320,7 +352,7 @@ private LdapDataStore getLdapDataStore(EntityMetadata md){
320352
* @return a string representation of the DN.
321353
*/
322354
private String createDN(LdapDataStore store, String uniqueValue){
323-
return store.getUniqueField() + "=" + uniqueValue + "," + store.getBaseDN();
355+
return store.getUniqueAttribute() + "=" + uniqueValue + "," + store.getBaseDN();
324356
}
325357

326358
/**
@@ -332,7 +364,7 @@ private String createDN(LdapDataStore store, String uniqueValue){
332364
* @param sort - (optional) {@link Sort}.
333365
* @return list of field names.
334366
*/
335-
private Set<String> collectRequiredFields(EntityMetadata md,
367+
private Set<String> gatherRequiredFields(EntityMetadata md,
336368
Projection projection, QueryExpression query, Sort sort){
337369
Set<String> fields = new HashSet<String>();
338370

@@ -360,6 +392,22 @@ private Set<String> collectRequiredFields(EntityMetadata md,
360392
return fields;
361393
}
362394

395+
/**
396+
* Translates a <code>Collection</code> of fieldNames into a <code>Set</code> of
397+
* attributeNames
398+
* @param property - {@link LdapFieldNameTranslator}.
399+
* @param fieldNames - <code>Collection</code> of fieldNames to translated
400+
* @return <code>Set</code> of translated attributeNames.
401+
*/
402+
private Set<String> translateFieldNames(LdapFieldNameTranslator property, Collection<String> fieldNames){
403+
Set<String> attributes = new HashSet<String>();
404+
for(String fieldName : fieldNames){
405+
attributes.add(property.translateFieldName(fieldName));
406+
}
407+
408+
return attributes;
409+
}
410+
363411
/**
364412
* For Insert and Save (and possibly Update), this method will project the results back
365413
* onto the documents.
@@ -374,7 +422,9 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map
374422

375423
EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName());
376424
JsonNodeFactory factory = ctx.getFactory().getNodeFactory();
377-
Set<String> requiredFields = collectRequiredFields(md, projection, null, null);
425+
LdapFieldNameTranslator property = getLdapFieldNameTranslator(md);
426+
427+
Set<String> requiredAttributeNames = translateFieldNames(property, gatherRequiredFields(md, projection, null, null));
378428
Projector projector = Projector.getInstance(
379429
Projection.add(
380430
projection,
@@ -384,15 +434,17 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map
384434
),
385435
md);
386436

437+
String dnFieldName = property.translateAttributeName(LdapConstant.ATTRIBUTE_DN);
438+
387439
for(Entry<DocCtx, String> insertedDn : documentToDnMap.entrySet()){
388440
DocCtx document = insertedDn.getKey();
389441
String dn = insertedDn.getValue();
390442
DocCtx projectionResponseJson = null;
391443

392444
// If only dn is in the projection, then no need to query LDAP.
393-
if((requiredFields.size() == 1) && requiredFields.contains(LdapConstant.FIELD_DN)){
445+
if((requiredAttributeNames.size() == 1) && requiredAttributeNames.contains(LdapConstant.ATTRIBUTE_DN)){
394446
ObjectNode node = factory.objectNode();
395-
node.set(LdapConstant.FIELD_DN, StringType.TYPE.toJson(factory, dn));
447+
node.set(dnFieldName, StringType.TYPE.toJson(factory, dn));
396448
projectionResponseJson = new DocCtx(new JsonDoc(node));
397449
}
398450
//TODO: else fetch entity from LDAP and project results.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright 2015 Red Hat, Inc. and/or its affiliates.
3+
4+
This file is part of lightblue.
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
package com.redhat.lightblue.crud.ldap.model;
20+
21+
import com.redhat.lightblue.common.ldap.LdapFieldNameTranslator;
22+
23+
/**
24+
* An implementation of {@link LdapFieldNameTranslator} used by crud when
25+
* no other implementation can be found.
26+
*
27+
* @author dcrissman
28+
*/
29+
public class TrivialLdapFieldNameTranslator implements LdapFieldNameTranslator{
30+
31+
@Override
32+
public String translateFieldName(String fieldName) {
33+
return fieldName;
34+
}
35+
36+
@Override
37+
public String translateAttributeName(String attributeName) {
38+
return attributeName;
39+
}
40+
41+
}

0 commit comments

Comments
 (0)