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