1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.ldaptive;
18
19 import java.util.Objects;
20 import java.util.Optional;
21 import lombok.extern.slf4j.Slf4j;
22 import org.bremersee.exception.ServiceException;
23 import org.ldaptive.AddOperation;
24 import org.ldaptive.AddRequest;
25 import org.ldaptive.BindOperation;
26 import org.ldaptive.BindRequest;
27 import org.ldaptive.BindResponse;
28 import org.ldaptive.CompareOperation;
29 import org.ldaptive.CompareRequest;
30 import org.ldaptive.CompareResponse;
31 import org.ldaptive.ConnectionFactory;
32 import org.ldaptive.DeleteOperation;
33 import org.ldaptive.DeleteRequest;
34 import org.ldaptive.LdapAttribute;
35 import org.ldaptive.LdapEntry;
36 import org.ldaptive.LdapException;
37 import org.ldaptive.ModifyDnOperation;
38 import org.ldaptive.ModifyDnRequest;
39 import org.ldaptive.ModifyOperation;
40 import org.ldaptive.ModifyRequest;
41 import org.ldaptive.Operation;
42 import org.ldaptive.Request;
43 import org.ldaptive.Result;
44 import org.ldaptive.ResultCode;
45 import org.ldaptive.SearchOperation;
46 import org.ldaptive.SearchRequest;
47 import org.ldaptive.SearchResponse;
48 import org.ldaptive.extended.ExtendedOperation;
49 import org.ldaptive.extended.ExtendedRequest;
50 import org.ldaptive.extended.ExtendedResponse;
51 import org.ldaptive.handler.ResultPredicate;
52
53
54
55
56
57
58 @Slf4j
59 public class LdaptiveTemplate implements LdaptiveOperations {
60
61 private static final ResultPredicate NOT_COMPARE_RESULT = result -> !result.isSuccess()
62 && result.getResultCode() != ResultCode.COMPARE_TRUE
63 && result.getResultCode() != ResultCode.COMPARE_FALSE;
64
65 private static final ResultPredicate NOT_DELETE_RESULT = result -> !result.isSuccess()
66 && result.getResultCode() != ResultCode.NO_SUCH_OBJECT;
67
68 private static final ResultPredicate NOT_FIND_RESULT = NOT_DELETE_RESULT;
69
70 private final ConnectionFactory connectionFactory;
71
72 private LdaptiveErrorHandler errorHandler = new DefaultLdaptiveErrorHandler();
73
74
75
76
77
78
79 public LdaptiveTemplate(ConnectionFactory connectionFactory) {
80 if (Objects.isNull(connectionFactory)) {
81 throw new IllegalArgumentException("Connection factory must not be present.");
82 }
83 this.connectionFactory = connectionFactory;
84 }
85
86 @Override
87 public ConnectionFactory getConnectionFactory() {
88 return connectionFactory;
89 }
90
91
92
93
94
95
96 public void setErrorHandler(final LdaptiveErrorHandler errorHandler) {
97 if (errorHandler != null) {
98 this.errorHandler = errorHandler;
99 }
100 }
101
102 @Override
103 public LdaptiveTemplate copy() {
104 return copy(null);
105 }
106
107 @Override
108 public LdaptiveTemplate copy(LdaptiveErrorHandler errorHandler) {
109 final LdaptiveTemplate template = new LdaptiveTemplate(connectionFactory);
110 template.setErrorHandler(errorHandler);
111 return template;
112 }
113
114 private <Q extends Request, S extends Result> S execute(Operation<Q, S> operation, Q request) {
115 try {
116 return operation.execute(request);
117
118 } catch (Exception e) {
119 errorHandler.handleError(e);
120 return null;
121 }
122 }
123
124 @Override
125 public void add(AddRequest request) {
126 execute(
127 AddOperation.builder()
128 .factory(getConnectionFactory())
129 .throwIf(ResultPredicate.NOT_SUCCESS)
130 .build(),
131 request);
132 }
133
134 @Override
135 public boolean bind(BindRequest request) {
136 return Optional.ofNullable(execute(new BindOperation(getConnectionFactory()), request))
137 .map(BindResponse::isSuccess)
138 .orElse(false);
139 }
140
141 @Override
142 public boolean compare(CompareRequest request) {
143 return Optional.ofNullable(execute(
144 CompareOperation.builder()
145 .factory(getConnectionFactory())
146 .throwIf(NOT_COMPARE_RESULT)
147 .build(),
148 request))
149 .map(CompareResponse::isTrue)
150 .orElse(false);
151 }
152
153 @Override
154 public void delete(DeleteRequest request) {
155 execute(
156 DeleteOperation.builder()
157 .factory(getConnectionFactory())
158 .throwIf(NOT_DELETE_RESULT)
159 .build(),
160 request);
161 }
162
163 @Override
164 public ExtendedResponse executeExtension(ExtendedRequest request) {
165 return execute(
166 ExtendedOperation.builder()
167 .factory(getConnectionFactory())
168 .throwIf(ResultPredicate.NOT_SUCCESS)
169 .build(),
170 request);
171 }
172
173 @Override
174 public void modify(ModifyRequest request) {
175 if (request.getModifications() != null && request.getModifications().length > 0) {
176 execute(
177 ModifyOperation.builder()
178 .factory(getConnectionFactory())
179 .throwIf(ResultPredicate.NOT_SUCCESS)
180 .build(),
181 request);
182 }
183 }
184
185 @Override
186 public void modifyDn(ModifyDnRequest request) {
187 execute(
188 ModifyDnOperation.builder()
189 .factory(getConnectionFactory())
190 .throwIf(ResultPredicate.NOT_SUCCESS)
191 .build(),
192 request);
193 }
194
195 @Override
196 public SearchResponse search(SearchRequest request) {
197 return execute(
198 SearchOperation.builder()
199 .factory(getConnectionFactory())
200 .throwIf(NOT_FIND_RESULT)
201 .build(),
202 request);
203 }
204
205 @Override
206 public boolean exists(String dn) {
207 try {
208 SearchResponse response = SearchOperation.builder()
209 .factory(getConnectionFactory())
210 .throwIf(NOT_FIND_RESULT)
211 .build()
212 .execute(SearchRequest.objectScopeSearchRequest(dn));
213 return response.isSuccess();
214
215 } catch (LdapException e) {
216 errorHandler.handleError(e);
217 return false;
218 }
219 }
220
221 @Override
222 public <T> T save(T domainObject, LdaptiveEntryMapper<T> entryMapper) {
223
224 String dn = entryMapper.mapDn(domainObject);
225 SearchResponse searchResponse = execute(
226 SearchOperation.builder()
227 .factory(getConnectionFactory())
228 .throwIf(result -> result.getResultCode() != ResultCode.NO_SUCH_OBJECT
229 && result.getResultCode() != ResultCode.SUCCESS)
230 .build(),
231 SearchRequest.objectScopeSearchRequest(dn));
232 return Optional.ofNullable(searchResponse)
233 .map(SearchResponse::getEntry)
234 .map(entry -> entryMapper.mapAndComputeModifyRequest(domainObject, entry)
235 .map(modReq -> {
236 modify(modReq);
237 return entryMapper.map(entry);
238 })
239 .orElse(domainObject))
240 .orElseGet(() -> {
241 String[] objectClasses = entryMapper.getObjectClasses();
242 if (objectClasses == null || objectClasses.length == 0) {
243 final ServiceException se = ServiceException.internalServerError(
244 "Object classes must be specified to save a new ldap entry.",
245 "org.bremersee:ldaptive-integration:d7aa5699-fd2e-45df-a863-97960e8095b8");
246 log.error("Saving domain object failed.", se);
247 throw se;
248 }
249 LdapEntry entry = new LdapEntry();
250 entryMapper.map(domainObject, entry);
251 entry.setDn(dn);
252 entry.addAttributes(new LdapAttribute("objectclass", objectClasses));
253 add(new AddRequest(dn, entry.getAttributes()));
254 return entryMapper.map(entry);
255 });
256 }
257
258 }