/*
 * Copyright 2005-2007 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.acegisecurity.ldap;

import java.util.Properties;

import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.ContextNotEmptyException;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.NameNotFoundException;
import javax.naming.directory.DirContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.directory.server.core.configuration.ShutdownConfiguration;
import org.apache.directory.server.jndi.ServerContextFactory;
import org.apache.directory.server.protocol.shared.store.LdifFileLoader;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.support.DefaultDirObjectFactory;


/**
 * Utility class to initialize the apache directory server for use in the integration tests.
 *
 * @author Mattias Arthursson
 * @author Luke Taylor (borrowed from Spring Ldap project).
 *
 */
public class LdapServerManager implements DisposableBean {
    private static Log log = LogFactory.getLog(LdapServerManager.class);

    private ContextSource contextSource;

    public void setContextSource(ContextSource contextSource) {
        this.contextSource = contextSource;
    }

    public void destroy() throws Exception {
        Properties env = new Properties();
        env.setProperty(Context.INITIAL_CONTEXT_FACTORY,
                ServerContextFactory.class.getName());
        env.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
        env.setProperty(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
        env.setProperty(Context.SECURITY_CREDENTIALS, "secret");

        ShutdownConfiguration configuration = new ShutdownConfiguration();
        env.putAll(configuration.toJndiEnvironment());

        new InitialContext(env);
    }

    public void cleanAndSetup(String ldifFile) throws Exception {
        DirContext ctx = contextSource.getReadWriteContext();

        // First of all, make sure the database is empty.
        Name startingPoint = null;

        // Different test cases have different base paths. This means that the
        // starting point will be different.
        if (ctx.getEnvironment().get(
                DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY) != null) {
            startingPoint = DistinguishedName.EMPTY_PATH;
        } else {
            startingPoint = new DistinguishedName("dc=acegisecurity,dc=org");
        }

        try {
            log.info("Cleaning all present data.");
            clearSubContexts(ctx, startingPoint);
            // Load the ldif to the recently started server
            log.info("Loading setup data");
            LdifFileLoader loader = new LdifFileLoader(ctx, ldifFile);
            loader.execute();
        } finally {
            ctx.close();
        }
    }

    private void clearSubContexts(DirContext ctx, Name name) throws NamingException {

        NamingEnumeration enumeration = null;
        try {
            enumeration = ctx.listBindings(name);
            while (enumeration.hasMore()) {
                Binding element = (Binding) enumeration.next();
                DistinguishedName childName = new DistinguishedName(element.getName());
                childName.prepend((DistinguishedName) name);

                try {
                    ctx.destroySubcontext(childName);
                } catch (ContextNotEmptyException e) {
                    clearSubContexts(ctx, childName);
                    ctx.destroySubcontext(childName);
                }
            }
        } catch(NameNotFoundException ignored) {
        }
        catch (NamingException e) {
            e.printStackTrace();
        } finally {
            try {
                enumeration.close();
            } catch (Exception e) {
                // Never mind this
            }
        }
    }
}


@@ -1361,16 +1361,75 @@
 leBean;%0A
+import org.springframework.beans.factory.InitializingBean;%0A
 import o
@@ -1472,16 +1472,16 @@
 Source;%0A
-
 import o
@@ -1598,16 +1598,61 @@
 actory;%0A
+import org.springframework.core.io.Resource;%0A
 %0A%0A/**%0A *
@@ -1898,16 +1898,34 @@
 ableBean
+, InitializingBean
  %7B%0A    p
@@ -2033,16 +2033,47 @@
 tSource;
+%0A    private Resource ldifFile;
 %0A%0A    pu
@@ -2718,24 +2718,24 @@
 onment());%0A%0A
-
         new 
@@ -2754,32 +2754,293 @@
 xt(env);%0A    %7D%0A%0A
+%0A    public void afterPropertiesSet() throws Exception %7B%0A        if (ldifFile != null) %7B%0A            cleanAndSetup(ldifFile.getFile().getAbsolutePath());%0A        %7D%0A    %7D%0A%0A    public void setLdifFile(Resource ldifFile) %7B%0A        this.ldifFile = ldifFile;%0A    %7D%0A%0A
     public void 

Allow an ldif file to be set in the configuration and loaded on initialization.