Skip to content

Commit 615d3f8

Browse files
committed
Merge pull request #29 from dcrissman/issue17-type-system
Issue #17 type system
2 parents 75fa8e1 + bb5fcb9 commit 615d3f8

File tree

16 files changed

+945
-249
lines changed

16 files changed

+945
-249
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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;
20+
21+
import java.util.ArrayList;
22+
import java.util.Date;
23+
import java.util.List;
24+
25+
import com.fasterxml.jackson.databind.JsonNode;
26+
import com.redhat.lightblue.common.ldap.LdapConstant;
27+
import com.redhat.lightblue.common.ldap.LightblueUtil;
28+
import com.redhat.lightblue.metadata.ArrayElement;
29+
import com.redhat.lightblue.metadata.ArrayField;
30+
import com.redhat.lightblue.metadata.EntityMetadata;
31+
import com.redhat.lightblue.metadata.ObjectField;
32+
import com.redhat.lightblue.metadata.SimpleField;
33+
import com.redhat.lightblue.metadata.Type;
34+
import com.redhat.lightblue.metadata.types.BinaryType;
35+
import com.redhat.lightblue.metadata.types.DateType;
36+
import com.redhat.lightblue.util.JsonDoc;
37+
import com.redhat.lightblue.util.JsonNodeCursor;
38+
import com.redhat.lightblue.util.Path;
39+
import com.unboundid.ldap.sdk.Entry;
40+
import com.unboundid.util.StaticUtils;
41+
42+
/**
43+
* Builds populated instances of {@link Entry} for LDAP interaction.
44+
*
45+
* @author dcrissman
46+
*/
47+
public class EntryBuilder extends TranslatorFromJson<Entry>{
48+
49+
public EntryBuilder(EntityMetadata md){
50+
super(md);
51+
}
52+
53+
public Entry build(String dn, JsonDoc document){
54+
Entry entry = new Entry(dn);
55+
translate(document, entry);
56+
return entry;
57+
}
58+
59+
@Override
60+
protected Object fromJson(Type type, JsonNode node){
61+
if(type instanceof DateType){
62+
return StaticUtils.encodeGeneralizedTime((Date)type.fromJson(node));
63+
}
64+
else if(type instanceof BinaryType){
65+
return type.fromJson(node);
66+
}
67+
else{
68+
return super.fromJson(type, node).toString();
69+
}
70+
}
71+
72+
@Override
73+
protected void translate(SimpleField field, Path path, JsonNode node, Entry target) {
74+
String fieldName = field.getName();
75+
76+
if(LdapConstant.FIELD_DN.equalsIgnoreCase(fieldName)){
77+
throw new IllegalArgumentException(
78+
"'dn' should not be included as it's value will be derived from the metadata.basedn and" +
79+
" the metadata.uniqueattr. Including the 'dn' as an insert attribute is confusing.");
80+
}
81+
else if(LightblueUtil.isFieldObjectType(fieldName)
82+
|| LightblueUtil.isFieldAnArrayCount(fieldName, getEntityMetadata().getFields())){
83+
/*
84+
* Indicates the field is auto-generated for lightblue purposes. These fields
85+
* should not be inserted into LDAP.
86+
*/
87+
return;
88+
}
89+
90+
Type type = field.getType();
91+
Object o = fromJson(type, node);
92+
if(type instanceof BinaryType) {
93+
target.addAttribute(fieldName, (byte[])o);
94+
}
95+
else{
96+
target.addAttribute(fieldName, o.toString());
97+
}
98+
}
99+
100+
@Override
101+
protected void translate(ObjectField field, Path path, JsonNode node, Entry target) {
102+
throw new UnsupportedOperationException("ObjectField type is not currently supported.");
103+
}
104+
105+
@Override
106+
protected void translateSimpleArray(ArrayField field, Path path, List<Object> items, Entry target) {
107+
ArrayElement arrayElement = field.getElement();
108+
Type arrayElementType = arrayElement.getType();
109+
String fieldName = field.getName();
110+
111+
if(arrayElementType instanceof BinaryType){
112+
List<byte[]> bytes = new ArrayList<byte[]>();
113+
for(Object item : items){
114+
bytes.add((byte[])item);
115+
}
116+
target.addAttribute(fieldName, bytes.toArray(new byte[0][]));
117+
}
118+
else{
119+
List<String> values = new ArrayList<String>();
120+
for(Object item : items){
121+
values.add(item.toString());
122+
}
123+
target.addAttribute(fieldName, values);
124+
}
125+
}
126+
127+
@Override
128+
protected void translateObjectArray(ArrayField field, JsonNodeCursor cursor, Entry target) {
129+
throw new UnsupportedOperationException("Object ArrayField type is not currently supported.");
130+
}
131+
132+
}

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

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.ArrayList;
2222
import java.util.HashMap;
2323
import java.util.HashSet;
24-
import java.util.Iterator;
2524
import java.util.List;
2625
import java.util.Map;
2726
import java.util.Map.Entry;
@@ -68,13 +67,13 @@
6867
import com.redhat.lightblue.util.Error;
6968
import com.redhat.lightblue.util.JsonDoc;
7069
import com.redhat.lightblue.util.Path;
71-
import com.unboundid.ldap.sdk.Attribute;
7270
import com.unboundid.ldap.sdk.LDAPConnection;
7371
import com.unboundid.ldap.sdk.LDAPException;
7472
import com.unboundid.ldap.sdk.LDAPResult;
7573
import com.unboundid.ldap.sdk.ResultCode;
7674
import com.unboundid.ldap.sdk.SearchRequest;
7775
import com.unboundid.ldap.sdk.SearchResult;
76+
import com.unboundid.ldap.sdk.SearchResultEntry;
7877
import com.unboundid.ldap.sdk.SearchScope;
7978
import com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl;
8079
import com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl;
@@ -106,19 +105,13 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx,
106105
EntityMetadata md = ctx.getEntityMetadata(ctx.getEntityName());
107106
LdapDataStore store = getLdapDataStore(md);
108107

109-
Map<DocCtx, String> documentToDnMap = new HashMap<DocCtx, String>();
110-
111-
LDAPConnection connection = null;
112-
try {
113-
connection = dbResolver.get(store);
114-
}
115-
catch (LDAPException e) {
116-
//TODO: throw more relevant exception.
117-
throw new RuntimeException("Unable to establish connection to LDAP", e);
118-
}
119-
120108
FieldAccessRoleEvaluator roles = new FieldAccessRoleEvaluator(md, ctx.getCallerRoles());
109+
EntryBuilder entryBuilder = new EntryBuilder(md);
121110

111+
//Create Entry instances for each document.
112+
List<com.unboundid.ldap.sdk.Entry> entries = new ArrayList<com.unboundid.ldap.sdk.Entry>();
113+
Map<DocCtx, String> documentToDnMap = new HashMap<DocCtx, String>();
114+
boolean hasError = false;
122115
for(DocCtx document : documents){
123116
List<Path> paths = roles.getInaccessibleFields_Insert(document);
124117
if((paths != null) && !paths.isEmpty()){
@@ -137,40 +130,21 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx,
137130

138131
String dn = createDN(store, uniqueNode.asText());
139132
documentToDnMap.put(document, dn);
140-
com.unboundid.ldap.sdk.Entry entry = new com.unboundid.ldap.sdk.Entry(dn);
141-
142-
Iterator<Map.Entry<String, JsonNode>> nodeIterator = rootNode.fields();
143-
while(nodeIterator.hasNext()){
144-
Map.Entry<String, JsonNode> node = nodeIterator.next();
145-
if(LdapConstant.FIELD_DN.equalsIgnoreCase(node.getKey())){
146-
throw new IllegalArgumentException(
147-
"'dn' should not be included as it's value will be derived from the metadata.basedn and" +
148-
" the metadata.uniqueattr. Including the 'dn' as an insert attribute is confusing.");
149-
}
150-
151-
JsonNode valueNode = node.getValue();
152-
if(valueNode.isArray()){
153-
List<String> values = new ArrayList<String>();
154-
for(JsonNode string : valueNode){
155-
values.add(string.asText());
156-
}
157-
entry.addAttribute(new Attribute(node.getKey(), values));
158-
}
159-
else{
160-
String fieldName = node.getKey();
161-
if(LightblueUtil.isFieldObjectType(fieldName)
162-
|| LightblueUtil.isFieldAnArrayCount(fieldName, md.getFields())){
163-
/*
164-
* Indicates the field is auto-generated for lightblue purposes. These fields
165-
* should not be inserted into LDAP.
166-
*/
167-
continue;
168-
}
169-
170-
entry.addAttribute(new Attribute(node.getKey(), node.getValue().asText()));
171-
}
133+
try{
134+
entries.add(entryBuilder.build(dn, document));
172135
}
136+
catch(Exception e){
137+
document.addError(Error.get(e));
138+
hasError = true;
139+
}
140+
}
141+
if(hasError){
142+
return response;
143+
}
173144

145+
//Persist each Entry.
146+
LDAPConnection connection = getNewLdapConnection(store);
147+
for(com.unboundid.ldap.sdk.Entry entry : entries){
174148
InsertCommand command = new InsertCommand(connection, entry);
175149

176150
LDAPResult result = command.execute();
@@ -227,9 +201,9 @@ public CRUDFindResponse find(CRUDOperationContext ctx,
227201
CRUDFindResponse response = new CRUDFindResponse();
228202
response.setSize(0);
229203

230-
try {
231-
LDAPConnection connection = dbResolver.get(store);
204+
LDAPConnection connection = getNewLdapConnection(store);
232205

206+
try {
233207
//TODO: Support scopes other than SUB
234208
SearchRequest request = new SearchRequest(
235209
store.getBaseDN(),
@@ -247,7 +221,19 @@ public CRUDFindResponse find(CRUDOperationContext ctx,
247221
SearchResult result = connection.search(request);
248222

249223
response.setSize(result.getEntryCount());
250-
ctx.setDocuments(new ResultTranslator(ctx.getFactory().getNodeFactory()).translate(result, md));
224+
ResultTranslator resultTranslator = new ResultTranslator(ctx.getFactory().getNodeFactory());
225+
List<DocCtx> translatedDocs = new ArrayList<DocCtx>();
226+
for(SearchResultEntry entry : result.getSearchEntries()){
227+
try{
228+
translatedDocs.add(resultTranslator.translate(entry, md));
229+
}
230+
catch(Exception e){
231+
DocCtx erroredDoc = new DocCtx(null);
232+
erroredDoc.addError(Error.get(e));
233+
translatedDocs.add(erroredDoc);
234+
}
235+
}
236+
ctx.setDocuments(translatedDocs);
251237

252238
Projector projector = Projector.getInstance(
253239
Projection.add(
@@ -416,4 +402,22 @@ private void projectChanges(Projection projection, CRUDOperationContext ctx, Map
416402
}
417403
}
418404

405+
/**
406+
* Returns a new connection to ldap.
407+
* @param store - {@link LdapDataStore} to connect too.
408+
* @return a new connection to ldap
409+
* @throws RuntimeException when unable to connect to ldap.
410+
*/
411+
private LDAPConnection getNewLdapConnection(LdapDataStore store) {
412+
LDAPConnection connection = null;
413+
try {
414+
connection = dbResolver.get(store);
415+
}
416+
catch (LDAPException e) {
417+
//TODO: throw more relevant exception.
418+
throw new RuntimeException("Unable to establish connection to LDAP", e);
419+
}
420+
return connection;
421+
}
422+
419423
}

0 commit comments

Comments
 (0)