org.adsync4j.testutils.ldap.EmbeddedUnboundIDLdapServer.java Source code

Java tutorial

Introduction

Here is the source code for org.adsync4j.testutils.ldap.EmbeddedUnboundIDLdapServer.java

Source

/*******************************************************************************
 * ADSync4J (https://github.com/zagyi/adsync4j)
 *
 * Copyright (c) 2013 Balazs Zagyvai
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Balazs Zagyvai
 ***************************************************************************** */
package org.adsync4j.testutils.ldap;

import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.schema.Schema;
import com.unboundid.ldif.LDIFException;
import com.unboundid.ldif.LDIFReader;
import com.unboundid.util.LDAPSDKException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.concurrent.NotThreadSafe;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.propagate;
import static java.util.Objects.requireNonNull;

/**
 * Utility class that makes it easy to start an embedded LDAP server. It's basically a lightweight wrapper around UnboundID's
 * {@link com.unboundid.ldap.listener.InMemoryDirectoryServer}.
 */
@NotThreadSafe
public class EmbeddedUnboundIDLdapServer {

    private final static Logger LOG = LoggerFactory.getLogger(EmbeddedUnboundIDLdapServer.class);
    private final static boolean CLOSE_EXISTING_CONNECTIONS_ON_SHUTDOWN = true;
    private final static boolean CLEAR_BEFORE_LDIF_IMPORT = false;

    @Nullable
    private Integer _port;
    private List<String> _rootDNs = new ArrayList<>();
    private List<SchemaFileSupplier> _schemas = new ArrayList<>();
    private List<InputStream> _ldifs = new ArrayList<>();
    private Map<String, String> _bindCredentials = new HashMap<>();
    private boolean _includeStandardSchema = false;

    private boolean _initialized;
    private InMemoryDirectoryServer _server;

    @PostConstruct
    public EmbeddedUnboundIDLdapServer init() {
        assertUninitialized();

        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(
                    _rootDNs.toArray(new String[_rootDNs.size()]));

            initSchema(config);
            initPort(config);
            initBindCredentials(config);

            _server = createInMemoryDirectoryServer(config);
            _server.startListening();

            loadLdifs(_server);

            LOG.debug("LDAP Server is up and listening on: {}", getAddress());

            _initialized = true;
        } catch (LDAPSDKException | IOException e) {
            throw propagate(e);
        }

        return this;
    }

    protected InMemoryDirectoryServer createInMemoryDirectoryServer(InMemoryDirectoryServerConfig config)
            throws LDAPException {
        return new InMemoryDirectoryServer(config);
    }

    @PreDestroy
    public void shutDown() {
        if (_initialized) {
            _server.shutDown(CLOSE_EXISTING_CONNECTIONS_ON_SHUTDOWN);
        } else {
            LOG.warn("shutDown() called on an uninitialized instance.");
        }
    }

    public LDAPConnection getConnection() throws LDAPException {
        return _server.getConnection();
    }

    private void initSchema(InMemoryDirectoryServerConfig config) throws LDAPSDKException, IOException {
        if (_schemas.size() > 0) {
            config.setSchema(Schema.mergeSchemas(getSchemasInArray()));
        }
    }

    private Schema[] getSchemasInArray() throws LDAPSDKException, IOException {
        Schema[] schemaArray;
        int i = 0;

        if (_includeStandardSchema) {
            schemaArray = new Schema[_schemas.size() + 1];
            schemaArray[i++] = Schema.getDefaultStandardSchema();
        } else {
            schemaArray = new Schema[_schemas.size()];
        }

        for (SchemaFileSupplier schemaFileSupplier : _schemas) {
            File schemaFile = schemaFileSupplier.getFile();
            try {
                Schema schema = Schema.getSchema(schemaFile);
                schemaArray[i++] = schema;
                if (schemaFileSupplier.isBackedByTempFile()) {
                    schemaFile.deleteOnExit();
                }
            } catch (LDIFException e) {
                throw new RuntimeException("Could not load schema file: " + schemaFile.getAbsolutePath(), e);
            }
        }

        return schemaArray;
    }

    private void initPort(InMemoryDirectoryServerConfig config) {
        if (_port != null) {
            try {
                InMemoryListenerConfig listenerConfig = new InMemoryListenerConfig("default listener", null, _port,
                        null, null, null);
                config.setListenerConfigs(listenerConfig);
                LOG.debug("Successfully configured listener on port: {}", _port);
            } catch (LDAPException e) {
                throw propagate(e);
            }
        }
    }

    private void initBindCredentials(InMemoryDirectoryServerConfig config) {
        for (Map.Entry<String, String> bindCredentialEntry : _bindCredentials.entrySet()) {
            String user = bindCredentialEntry.getKey();
            String pwd = bindCredentialEntry.getValue();
            try {
                config.addAdditionalBindCredentials(user, pwd);
            } catch (LDAPException e) {
                throw propagate(e);
            }
        }
    }

    private void loadLdifs(InMemoryDirectoryServer ds) {
        try {
            for (InputStream ldif : _ldifs) {
                LDIFReader ldifReader = new LDIFReader(ldif);
                ds.importFromLDIF(CLEAR_BEFORE_LDIF_IMPORT, ldifReader);
            }
        } catch (LDAPException e) {
            throw propagate(e);
        }
    }

    private int obtainPort() {
        int port = _server.getListenPort();
        boolean isListenerActive = port != -1;

        checkState(isListenerActive, "Listener has not yet been actived.");

        _port = port;
        return port;
    }

    private static class SchemaFileSupplier {
        private final File _file;
        private final boolean _isBackedByTempFile;

        public SchemaFileSupplier(File file) {
            _file = file;
            _isBackedByTempFile = false;
        }

        public SchemaFileSupplier(InputStream inputStream) {
            _file = dumpStreamToTempFile(inputStream);
            _isBackedByTempFile = true;
        }

        public File getFile() {
            return _file;
        }

        private boolean isBackedByTempFile() {
            return _isBackedByTempFile;
        }

        private static File dumpStreamToTempFile(InputStream inputStream) {
            try {
                File tmpDir = new File(System.getProperty("java.io.tmpdir"));
                File schemaTempFile = File.createTempFile("unboundid-schema", "tmp", tmpDir);
                ByteStreams.copy(inputStream, Files.newOutputStreamSupplier(schemaTempFile));
                schemaTempFile.deleteOnExit();
                inputStream.close();
                return schemaTempFile;
            } catch (IOException e) {
                throw propagate(e);
            }
        }

    }

    private void assertUninitialized() {
        checkState(!_initialized, "Instance already initialized.");
    }

    //region ############## getters ##############
    public int getPort() {
        return _port == null ? obtainPort() : _port;
    }

    public String getAddress() {
        return "ldap://127.0.0.1:" + getPort();
    }

    public List<String> getRootDNs() {
        return _rootDNs;
    }

    public boolean isInitialized() {
        return _initialized;
    }
    //endregion

    //region ############## setters/adders ##############
    public EmbeddedUnboundIDLdapServer setPort(int port) {
        assertUninitialized();
        _port = port;
        return this;
    }

    public EmbeddedUnboundIDLdapServer setLdifs(Iterable<InputStream> ldifs) {
        assertUninitialized();
        requireNonNull(ldifs);
        _ldifs = Lists.newArrayList(ldifs);
        return this;
    }

    public EmbeddedUnboundIDLdapServer addLdif(InputStream ldif) {
        assertUninitialized();
        requireNonNull(ldif);
        _ldifs.add(ldif);
        return this;
    }

    public EmbeddedUnboundIDLdapServer setSchemaFiles(Iterable<File> schemaFiles) {
        assertUninitialized();
        requireNonNull(schemaFiles);
        _schemas = new ArrayList<>();
        for (File schemaFile : schemaFiles) {
            _schemas.add(new SchemaFileSupplier(schemaFile));
        }
        return this;
    }

    public EmbeddedUnboundIDLdapServer setSchemaStreams(Iterable<InputStream> schemasStreams) {
        assertUninitialized();
        requireNonNull(schemasStreams);
        _schemas = new ArrayList<>();
        for (InputStream schemasStream : schemasStreams) {
            _schemas.add(new SchemaFileSupplier(schemasStream));
        }
        return this;
    }

    public EmbeddedUnboundIDLdapServer addSchema(InputStream schema) {
        assertUninitialized();
        requireNonNull(schema);
        _schemas.add(new SchemaFileSupplier(schema));
        return this;
    }

    public EmbeddedUnboundIDLdapServer addSchema(File schema) {
        assertUninitialized();
        requireNonNull(schema);
        _schemas.add(new SchemaFileSupplier(schema));
        return this;
    }

    public EmbeddedUnboundIDLdapServer setBindCredentials(Map<String, String> bindCredentials) {
        assertUninitialized();
        requireNonNull(bindCredentials);
        _bindCredentials = bindCredentials;
        return this;
    }

    public EmbeddedUnboundIDLdapServer addBindCredentials(String bindUser, String bindPassword) {
        assertUninitialized();
        requireNonNull(bindUser);
        requireNonNull(bindPassword);
        _bindCredentials.put(bindUser, bindPassword);
        return this;
    }

    public EmbeddedUnboundIDLdapServer setRootDN(String rootDN) {
        assertUninitialized();
        requireNonNull(rootDN);
        _rootDNs = Lists.newArrayList(rootDN);
        return this;
    }

    public EmbeddedUnboundIDLdapServer setRootDNs(String firstRootDN, String... restRootDNs) {
        assertUninitialized();
        requireNonNull(firstRootDN);
        requireNonNull(restRootDNs);
        _rootDNs = Lists.newArrayList(Lists.asList(firstRootDN, restRootDNs));
        return this;
    }

    public EmbeddedUnboundIDLdapServer setRootDNs(List<String> rootDNs) {
        assertUninitialized();
        requireNonNull(rootDNs);
        _rootDNs = rootDNs;
        return this;
    }

    public EmbeddedUnboundIDLdapServer addRootDN(String rootDN) {
        assertUninitialized();
        requireNonNull(rootDN);
        _rootDNs.add(rootDN);
        return this;
    }

    public EmbeddedUnboundIDLdapServer setIncludeStandardSchema(boolean includeStandardSchema) {
        assertUninitialized();
        _includeStandardSchema = includeStandardSchema;
        return this;
    }

    public EmbeddedUnboundIDLdapServer includeStandardSchema() {
        assertUninitialized();
        _includeStandardSchema = true;
        return this;
    }
    //endregion
}