org.bremersee.data.ldaptive.LdaptiveTemplate Maven / Gradle / Ivy
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bremersee.data.ldaptive;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import javax.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.bremersee.exception.ServiceException;
import org.ldaptive.AddOperation;
import org.ldaptive.AddRequest;
import org.ldaptive.AttributeModification;
import org.ldaptive.Connection;
import org.ldaptive.ConnectionFactory;
import org.ldaptive.DeleteOperation;
import org.ldaptive.DeleteRequest;
import org.ldaptive.LdapAttribute;
import org.ldaptive.LdapEntry;
import org.ldaptive.LdapException;
import org.ldaptive.ModifyOperation;
import org.ldaptive.ModifyRequest;
import org.ldaptive.ResultCode;
import org.ldaptive.SearchOperation;
import org.ldaptive.SearchRequest;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
/**
* The template for executing ldap operations.
*
* @author Christian Bremer
*/
@Slf4j
@SuppressWarnings("WeakerAccess")
public class LdaptiveTemplate implements LdaptiveOperations {
private final ConnectionFactory connectionFactory;
/**
* Instantiates a new ldap template.
*
* @param connectionFactory the connection factory
*/
public LdaptiveTemplate(final ConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory, "Connection factory must not be null.");
this.connectionFactory = connectionFactory;
}
private Connection getConnection() throws LdapException {
final Connection connection = this.connectionFactory.getConnection();
if (!connection.isOpen()) {
connection.open();
}
return connection;
}
/**
* Close the given context and ignore any thrown exception. This is useful for typical finally
* blocks in manual ldap statements.
*
* @param connection the ldap connection to close
*/
private void closeConnection(final Connection connection) {
if (connection != null && connection.isOpen()) {
try {
connection.close();
} catch (final Exception ex) {
log.warn("Closing ldap connection failed.", ex);
}
}
}
@Override
public T execute(final LdaptiveConnectionCallback callback) {
Connection connection = null;
try {
connection = getConnection();
return callback.doWithConnection(connection);
} catch (final LdapRuntimeException e) {
final ServiceException serviceException = new ServiceException(
HttpStatus.INTERNAL_SERVER_ERROR,
"org.bremersee:base-common-ldaptive:8150d733-cfb2-46a9-94f6-4f3395e7cecf",
e.getLdapException());
log.error("Executing ldap operation failed.", serviceException);
throw serviceException;
} catch (final LdapException e) {
final ServiceException serviceException = new ServiceException(
HttpStatus.INTERNAL_SERVER_ERROR,
"org.bremersee:base-common-ldaptive:af8cb1fc-f9c2-4592-8bd6-de59c6f2a8e6",
e);
log.error("Executing ldap operation failed.", serviceException);
throw serviceException;
} finally {
closeConnection(connection);
}
}
/**
* Execute the given add request.
*
* @param addRequest the add request
*/
public void add(@NotNull final AddRequest addRequest) {
execute(connection -> new AddOperation(connection).execute(addRequest));
}
/**
* Execute the given modify request.
*
* @param modifyRequest the modify request
*/
public void modify(@NotNull final ModifyRequest modifyRequest) {
if (modifyRequest.getAttributeModifications() != null
&& modifyRequest.getAttributeModifications().length > 0) {
execute(connection -> new ModifyOperation(connection).execute(modifyRequest));
}
}
/**
* Find one ldap entry.
*
* @param searchRequest the search request
* @return the ldap entry
*/
public Optional findOne(
@NotNull final SearchRequest searchRequest) {
return Optional.ofNullable(
execute(connection -> new SearchOperation(connection)
.execute(searchRequest)
.getResult()
.getEntry()));
}
/**
* Find one domain object.
*
* @param the type of the mapped domain object
* @param searchRequest the search request
* @param entryMapper the entry mapper that maps a ldap entry into the domain object
* @return the domain object
*/
public Optional findOne(
@NotNull final SearchRequest searchRequest,
@NotNull final LdaptiveEntryMapper entryMapper) {
return Optional.ofNullable(
execute(connection -> entryMapper
.map(new SearchOperation(connection)
.execute(searchRequest)
.getResult()
.getEntry())));
}
/**
* Find all ldap entries.
*
* @param searchRequest the search request
* @return the ldap entries
*/
public Collection findAll(
@NotNull final SearchRequest searchRequest) {
return execute(connection -> new SearchOperation(connection)
.execute(searchRequest)
.getResult()
.getEntries());
}
/**
* Find domain objects.
*
* @param the type of the domain objects
* @param searchRequest the search request
* @param entryMapper the entry mapper that maps a ldap entry into the domain object
* @return the stream of found domain objects
*/
public Stream findAll(
@NotNull final SearchRequest searchRequest,
@NotNull final LdaptiveEntryMapper entryMapper) {
return execute(connection -> new SearchOperation(connection)
.execute(searchRequest)
.getResult()
.getEntries()
.stream()
.map(entryMapper::map))
.filter(Objects::nonNull);
}
/**
* Check whether a domain object exists or not.
*
* @param the type of the domain object
* @param domainObject the domain object
* @param entryMapper the entry mapper that maps a ldap entry into the domain object
* @return {@code true} if the domain object exists, otherwise {@code false}
*/
public boolean exists(
@NotNull final T domainObject,
@NotNull final LdaptiveEntryMapper entryMapper) {
return execute(connection -> {
try {
return entryMapper.map(new SearchOperation(connection)
.execute(SearchRequest.newObjectScopeSearchRequest(entryMapper.mapDn(domainObject)))
.getResult()
.getEntry()) != null;
} catch (LdapException e) {
if (ResultCode.NO_SUCH_OBJECT == e.getResultCode()) {
return false;
}
if (e.getCause() instanceof javax.naming.NameNotFoundException) {
return false;
}
throw e;
}
});
}
/**
* Save domain object.
*
* @param the type of the domain object
* @param domainObject the domain object
* @param entryMapper the entry mapper that maps a ldap entry into the domain object
* @return the saved domain object
*/
public T save(
@NotNull final T domainObject,
@NotNull final LdaptiveEntryMapper entryMapper) {
return execute(connection -> save(domainObject, entryMapper, connection));
}
private T save(
final T domainObject,
final LdaptiveEntryMapper entryMapper,
final Connection connection) throws LdapRuntimeException {
try {
final LdapEntry destination;
final String dn = entryMapper.mapDn(domainObject);
if (exists(domainObject, entryMapper)) {
destination = new SearchOperation(connection)
.execute(SearchRequest.newObjectScopeSearchRequest(dn))
.getResult()
.getEntry();
final AttributeModification[] modifications = entryMapper
.mapAndComputeModifications(domainObject, destination);
if (modifications != null && modifications.length > 0) {
new ModifyOperation(connection)
.execute(new ModifyRequest(dn, modifications));
}
} else {
if (entryMapper.getObjectClasses() == null || entryMapper.getObjectClasses().length == 0) {
final ServiceException se = ServiceException.internalServerError(
"Object classes must be specified to save a new ldap entry.",
"org.bremersee:common-base-ldaptive:d7aa5699-fd2e-45df-a863-97960e8095b8");
log.error("Saving domain object failed.", se);
throw se;
}
destination = new LdapEntry();
entryMapper.map(domainObject, destination);
destination.setDn(dn);
destination.addAttribute(new LdapAttribute(
"objectclass",
entryMapper.getObjectClasses()));
new AddOperation(connection)
.execute(new AddRequest(dn, destination.getAttributes()));
}
return entryMapper.map(destination);
} catch (LdapException e) {
throw new LdapRuntimeException(e);
}
}
/**
* Save all domain objects.
*
* @param the type of the domain objects
* @param domainModels the domain objects
* @param entryMapper the entry mapper that maps a ldap entry into the domain object
* @return the stream of saved domain objects
*/
public Stream saveAll(
final Collection domainModels,
@NotNull final LdaptiveEntryMapper entryMapper) {
if (domainModels == null || domainModels.isEmpty()) {
return Stream.empty();
}
return domainModels.stream()
.filter(Objects::nonNull)
.map(domainModel -> save(domainModel, entryMapper));
}
/**
* Execute the given delete request.
*
* @param deleteRequest the delete request
*/
public void delete(@NotNull final DeleteRequest deleteRequest) {
execute((LdaptiveConnectionCallbackWithoutResult) connection -> new DeleteOperation(connection)
.execute(deleteRequest));
}
/**
* Delete domain object.
*
* @param the type of the domain object
* @param domainObject the domain object
* @param entryMapper the entry mapper that maps a ldap entry into the domain object
*/
public void delete(
@NotNull final T domainObject,
@NotNull final LdaptiveEntryMapper entryMapper) {
execute(
(LdaptiveConnectionCallbackWithoutResult) connection -> delete(
domainObject, entryMapper, connection));
}
private void delete(
final T domainModel,
final LdaptiveEntryMapper entryMapper,
final Connection connection) throws LdapRuntimeException {
try {
new DeleteOperation(connection).execute(new DeleteRequest(entryMapper.mapDn(domainModel)));
} catch (LdapException e) {
throw new LdapRuntimeException(e);
}
}
/**
* Delete all domain objects.
*
* @param the type of the domain objects
* @param domainObjects the domain objects
* @param entryMapper the entry mapper that maps a ldap entry into the domain object
*/
public void deleteAll(
final Collection domainObjects,
@NotNull final LdaptiveEntryMapper entryMapper) {
if (domainObjects != null) {
execute((LdaptiveConnectionCallbackWithoutResult) connection -> {
for (T domainModel : domainObjects) {
if (domainModel != null) {
delete(domainModel, entryMapper, connection);
}
}
});
}
}
private static class LdapRuntimeException extends RuntimeException {
@Getter(AccessLevel.PACKAGE)
private LdapException ldapException;
/**
* Instantiates a new Ldap runtime exception.
*
* @param ldapException the ldap exception
*/
LdapRuntimeException(LdapException ldapException) {
super(ldapException);
this.ldapException = ldapException;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy