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