This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f682d99264e752092187ec6c2d9a7ae8d925261e
Author: Guillaume Nodet <[email protected]>
AuthorDate: Wed Jul 15 13:54:37 2020 +0200

    [CAMEL-11807] Upgrade camel-ldif to junit5
---
 components/camel-ldif/pom.xml                      |   2 +-
 .../apache/camel/component/ldif/LdifRouteTest.java |  24 +-
 .../server/core/integ5/DSAnnotationProcessor.java  | 481 +++++++++++++++++++++
 .../directory/server/core/integ5/Description.java  |  45 ++
 .../server/core/integ5/DirectoryExtension.java     | 281 ++++++++++++
 .../core/integ5/ServerAnnotationProcessor.java     | 459 ++++++++++++++++++++
 6 files changed, 1279 insertions(+), 13 deletions(-)

diff --git a/components/camel-ldif/pom.xml b/components/camel-ldif/pom.xml
index 72f473e..a8cc8af 100644
--- a/components/camel-ldif/pom.xml
+++ b/components/camel-ldif/pom.xml
@@ -56,7 +56,7 @@
         <!-- test dependencies -->
         <dependency>
             <groupId>org.apache.camel</groupId>
-            <artifactId>camel-test</artifactId>
+            <artifactId>camel-test-junit5</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git 
a/components/camel-ldif/src/test/java/org/apache/camel/component/ldif/LdifRouteTest.java
 
b/components/camel-ldif/src/test/java/org/apache/camel/component/ldif/LdifRouteTest.java
index 91feefe..6084495 100644
--- 
a/components/camel-ldif/src/test/java/org/apache/camel/component/ldif/LdifRouteTest.java
+++ 
b/components/camel-ldif/src/test/java/org/apache/camel/component/ldif/LdifRouteTest.java
@@ -40,21 +40,21 @@ import 
org.apache.directory.server.annotations.CreateLdapServer;
 import org.apache.directory.server.annotations.CreateTransport;
 import org.apache.directory.server.core.annotations.ApplyLdifFiles;
 import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
-import org.apache.directory.server.core.integ.FrameworkRunner;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.apache.directory.server.core.integ5.DirectoryExtension;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 
 import static 
org.apache.directory.server.integ.ServerIntegrationUtils.getWiredConnection;
 import static 
org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-@RunWith(FrameworkRunner.class)
+@ExtendWith(DirectoryExtension.class)
 @CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")})
 public class LdifRouteTest extends AbstractLdapTestUnit {
     // Constants
@@ -67,8 +67,8 @@ public class LdifRouteTest extends AbstractLdapTestUnit {
     private CamelContext camel;
     private ProducerTemplate template;
     private LdapContext ldapContext;
-    
-    @Before
+
+    @BeforeEach
     public void setup() throws Exception {
         // Create the LDAPConnection
         ldapContext = getWiredContext(ldapServer);
@@ -79,7 +79,7 @@ public class LdifRouteTest extends AbstractLdapTestUnit {
         template = camel.createProducerTemplate();
     }
 
-    @After
+    @AfterEach
     public void tearDown() throws Exception {
         camel.stop();
     }
@@ -326,7 +326,7 @@ public class LdifRouteTest extends AbstractLdapTestUnit {
         assertNotNull(out);
         assertNotNull(out.getMessage());
         List<String> data = out.getMessage().getBody(List.class);
-        assertNotNull("out body could not be converted to a List - was: " + 
out.getMessage().getBody(), data);
+        assertNotNull(data, "out body could not be converted to a List - was: 
" + out.getMessage().getBody());
         return data;
     }
 
diff --git 
a/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/DSAnnotationProcessor.java
 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/DSAnnotationProcessor.java
new file mode 100644
index 0000000..68b64b0
--- /dev/null
+++ 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/DSAnnotationProcessor.java
@@ -0,0 +1,481 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.directory.server.core.integ5;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import 
org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Network;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.server.core.annotations.AnnotationUtils;
+import org.apache.directory.server.core.annotations.ApplyLdifFiles;
+import org.apache.directory.server.core.annotations.ApplyLdifs;
+import org.apache.directory.server.core.annotations.ContextEntry;
+import org.apache.directory.server.core.annotations.CreateAuthenticator;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreateIndex;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.annotations.LoadSchema;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.DnFactory;
+import org.apache.directory.server.core.api.interceptor.Interceptor;
+import org.apache.directory.server.core.api.partition.Partition;
+import org.apache.directory.server.core.authn.AuthenticationInterceptor;
+import org.apache.directory.server.core.authn.Authenticator;
+import org.apache.directory.server.core.authn.DelegatingAuthenticator;
+import org.apache.directory.server.core.factory.DirectoryServiceFactory;
+import org.apache.directory.server.core.factory.PartitionFactory;
+import 
org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
+import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
+import 
org.apache.directory.server.core.partition.impl.btree.mavibot.MavibotIndex;
+import org.apache.directory.server.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Helper class used to create a DS from the annotations
+ *
+ * @author <a href="mailto:[email protected]";>Apache Directory 
Project</a>
+ */
+public final class DSAnnotationProcessor {
+
+    /**
+     * A logger for this class
+     */
+    private static final Logger LOG = 
LoggerFactory.getLogger(DSAnnotationProcessor.class);
+
+    private DSAnnotationProcessor() {
+    }
+
+    /**
+     * Create the DirectoryService
+     *
+     * @param dsBuilder The DirectoryService builder
+     * @return an instance of DirectoryService
+     * @throws Exception If the DirectoryService cannot be created
+     */
+    public static DirectoryService createDS(CreateDS dsBuilder)
+            throws Exception {
+        LOG.debug("Starting DS {}...", dsBuilder.name());
+        Class<?> factory = dsBuilder.factory();
+        DirectoryServiceFactory dsf = (DirectoryServiceFactory) factory
+                .getDeclaredConstructor().newInstance();
+
+        DirectoryService service = dsf.getDirectoryService();
+        service.setAccessControlEnabled(dsBuilder.enableAccessControl());
+        service.setAllowAnonymousAccess(dsBuilder.allowAnonAccess());
+        service.getChangeLog().setEnabled(dsBuilder.enableChangeLog());
+
+        dsf.init(dsBuilder.name());
+
+        for (Class<?> interceptorClass : dsBuilder.additionalInterceptors()) {
+            service.addLast((Interceptor) 
interceptorClass.getDeclaredConstructor().newInstance());
+        }
+
+        List<Interceptor> interceptorList = service.getInterceptors();
+
+        if (dsBuilder.authenticators().length != 0) {
+            AuthenticationInterceptor authenticationInterceptor = null;
+
+            for (Interceptor interceptor : interceptorList) {
+                if (interceptor instanceof AuthenticationInterceptor) {
+                    authenticationInterceptor = (AuthenticationInterceptor) 
interceptor;
+                    break;
+                }
+            }
+
+            if (authenticationInterceptor == null) {
+                throw new IllegalStateException(
+                        "authentication interceptor not found");
+            }
+
+            Set<Authenticator> authenticators = new HashSet<Authenticator>();
+
+            for (CreateAuthenticator createAuthenticator : 
dsBuilder.authenticators()) {
+                Authenticator auth = 
createAuthenticator.type().getDeclaredConstructor().newInstance();
+
+                if (auth instanceof DelegatingAuthenticator) {
+                    DelegatingAuthenticator dauth = (DelegatingAuthenticator) 
auth;
+
+                    String host = createAuthenticator.delegateHost();
+
+                    if (Strings.isEmpty(host)) {
+                        host = Network.LOOPBACK_HOSTNAME;
+                    }
+
+                    dauth.setDelegateHost(host);
+                    dauth.setDelegatePort(createAuthenticator.delegatePort());
+                    dauth.setDelegateSsl(createAuthenticator.delegateSsl());
+                    dauth.setDelegateTls(createAuthenticator.delegateTls());
+                    
dauth.setBaseDn(service.getDnFactory().create(createAuthenticator.baseDn()));
+                    
dauth.setDelegateSslTrustManagerFQCN(createAuthenticator.delegateSslTrustManagerFQCN());
+                    
dauth.setDelegateTlsTrustManagerFQCN(createAuthenticator.delegateTlsTrustManagerFQCN());
+                }
+
+                authenticators.add(auth);
+            }
+
+            authenticationInterceptor.setAuthenticators(authenticators);
+            authenticationInterceptor.init(service);
+        }
+
+        service.setInterceptors(interceptorList);
+
+        SchemaManager schemaManager = service.getSchemaManager();
+
+        // process the schemas
+        for (LoadSchema loadedSchema : dsBuilder.loadedSchemas()) {
+            String schemaName = loadedSchema.name();
+            Boolean enabled = loadedSchema.enabled();
+
+            // Check if the schema is loaded or not
+            boolean isLoaded = schemaManager.isSchemaLoaded(schemaName);
+
+            if (!isLoaded) {
+                // We have to load the schema, if it exists
+                try {
+                    isLoaded = schemaManager.load(schemaName);
+                } catch (LdapUnwillingToPerformException lutpe) {
+                    // Cannot load the schema, it does not exists
+                    LOG.error(lutpe.getMessage());
+                    continue;
+                }
+            }
+
+            if (isLoaded) {
+                if (enabled) {
+                    schemaManager.enable(schemaName);
+
+                    if (schemaManager.isDisabled(schemaName)) {
+                        LOG.error("Cannot enable " + schemaName);
+                    }
+                } else {
+                    schemaManager.disable(schemaName);
+
+                    if (schemaManager.isEnabled(schemaName)) {
+                        LOG.error("Cannot disable " + schemaName);
+                    }
+                }
+            }
+
+            LOG.debug("Loading schema {}, enabled= {}", schemaName, enabled);
+        }
+
+        // Process the Partition, if any.
+        for (CreatePartition createPartition : dsBuilder.partitions()) {
+            Partition partition;
+
+            // Determine the partition type
+            if (createPartition.type() == Partition.class) {
+                // The annotation does not specify a specific partition type.
+                // We use the partition factory to create partition and index
+                // instances.
+                PartitionFactory partitionFactory = dsf.getPartitionFactory();
+                partition = partitionFactory.createPartition(
+                        schemaManager,
+                        service.getDnFactory(),
+                        createPartition.name(),
+                        createPartition.suffix(),
+                        createPartition.cacheSize(),
+                        new 
File(service.getInstanceLayout().getPartitionsDirectory(), 
createPartition.name()));
+
+                partition.setCacheService(service.getCacheService());
+
+                CreateIndex[] indexes = createPartition.indexes();
+
+                for (CreateIndex createIndex : indexes) {
+                    partitionFactory.addIndex(partition,
+                            createIndex.attribute(), createIndex.cacheSize());
+                }
+
+                partition.initialize();
+            } else {
+                // The annotation contains a specific partition type, we use
+                // that type.
+                Class<?>[] partypes = new Class[] {
+                    SchemaManager.class, DnFactory.class };
+                Constructor<?> constructor = 
createPartition.type().getConstructor(partypes);
+                partition = (Partition) constructor.newInstance(new Object[] {
+                    schemaManager, service.getDnFactory() });
+                partition.setId(createPartition.name());
+                partition.setSuffixDn(new Dn(schemaManager, 
createPartition.suffix()));
+
+                if (partition instanceof AbstractBTreePartition) {
+                    AbstractBTreePartition btreePartition = 
(AbstractBTreePartition) partition;
+                    btreePartition.setCacheService(service.getCacheService());
+                    btreePartition.setCacheSize(createPartition.cacheSize());
+                    btreePartition.setPartitionPath(new File(service
+                            .getInstanceLayout().getPartitionsDirectory(),
+                            createPartition.name()).toURI());
+
+                    // Process the indexes if any
+                    CreateIndex[] indexes = createPartition.indexes();
+
+                    for (CreateIndex createIndex : indexes) {
+                        if (createIndex.type() == JdbmIndex.class) {
+                            // JDBM index
+                            JdbmIndex index = new 
JdbmIndex(createIndex.attribute(), false);
+
+                            btreePartition.addIndexedAttributes(index);
+                        } else if (createIndex.type() == MavibotIndex.class) {
+                            // Mavibot index
+                            MavibotIndex index = new 
MavibotIndex(createIndex.attribute(), false);
+
+                            btreePartition.addIndexedAttributes(index);
+                        } else {
+                            // The annotation does not specify a specific index
+                            // type.
+                            // We use the generic index implementation.
+                            JdbmIndex index = new 
JdbmIndex(createIndex.attribute(), false);
+
+                            btreePartition.addIndexedAttributes(index);
+                        }
+                    }
+                }
+            }
+
+            partition.setSchemaManager(schemaManager);
+
+            // Inject the partition into the DirectoryService
+            service.addPartition(partition);
+
+            // Last, process the context entry
+            ContextEntry contextEntry = createPartition.contextEntry();
+
+            if (contextEntry != null) {
+                injectEntries(service, contextEntry.entryLdif());
+            }
+        }
+
+        return service;
+    }
+
+
+    /**
+     * Create a DirectoryService from a Unit test annotation
+     *
+     * @param description The annotations containing the info from which we 
will create
+     *                    the DS
+     * @return A valid DirectoryService
+     * @throws Exception If the DirectoryService instance can't be returned
+     */
+    public static DirectoryService getDirectoryService(Description description)
+            throws Exception {
+        CreateDS dsBuilder = description.getAnnotation(CreateDS.class);
+
+        if (dsBuilder != null) {
+            return createDS(dsBuilder);
+        } else {
+            LOG.debug("No {} DS.", description.getDisplayName());
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a DirectoryService from an annotation. The @CreateDS annotation
+     * must be associated with either the method or the encapsulating class. We
+     * will first try to get the annotation from the method, and if there is
+     * none, then we try at the class level.
+     *
+     * @return A valid DS
+     * @throws Exception If the DirectoryService instance can't be returned
+     */
+    public static DirectoryService getDirectoryService() throws Exception {
+        Object instance = AnnotationUtils.getInstance(CreateDS.class);
+        CreateDS dsBuilder = null;
+
+        if (instance != null) {
+            dsBuilder = (CreateDS) instance;
+
+            // Ok, we have found a CreateDS annotation. Process it now.
+            return createDS(dsBuilder);
+        }
+
+        throw new LdapException(I18n.err(I18n.ERR_114));
+    }
+
+
+    /**
+     * injects an LDIF entry in the given DirectoryService
+     *
+     * @param entry   the LdifEntry to be injected
+     * @param service the DirectoryService
+     * @throws Exception If the entry cannot be injected
+     */
+    private static void injectEntry(LdifEntry entry, DirectoryService service)
+            throws LdapException {
+        if (entry.isChangeAdd() || entry.isLdifContent()) {
+            service.getAdminSession().add(
+                    new DefaultEntry(service.getSchemaManager(), entry
+                            .getEntry()));
+        } else if (entry.isChangeModify()) {
+            service.getAdminSession().modify(entry.getDn(),
+                    entry.getModifications());
+        } else {
+            String message = I18n.err(I18n.ERR_117, entry.getChangeType());
+            throw new LdapException(message);
+        }
+    }
+
+
+    /**
+     * injects the LDIF entries present in a LDIF file
+     *
+     * @param clazz     The class which classLoaded will be use to retrieve 
the resources
+     * @param service   the DirectoryService
+     * @param ldifFiles array of LDIF file names (only )
+     * @throws Exception If we weren't able to inject LdifFiles
+     */
+    public static void injectLdifFiles(Class<?> clazz,
+                                       DirectoryService service, String[] 
ldifFiles) throws Exception {
+        if ((ldifFiles != null) && (ldifFiles.length > 0)) {
+            for (String ldifFile : ldifFiles) {
+                InputStream is = clazz.getClassLoader().getResourceAsStream(
+                        ldifFile);
+                if (is == null) {
+                    throw new FileNotFoundException("LDIF file '" + ldifFile
+                            + "' not found.");
+                } else {
+                    LdifReader ldifReader = new LdifReader(is);
+
+                    for (LdifEntry entry : ldifReader) {
+                        injectEntry(entry, service);
+                    }
+
+                    ldifReader.close();
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Inject an ldif String into the server. Dn must be relative to the root.
+     *
+     * @param service the directory service to use
+     * @param ldif    the ldif containing entries to add to the server.
+     * @throws Exception if there is a problem adding the entries from the LDIF
+     */
+    public static void injectEntries(DirectoryService service, String ldif)
+            throws Exception {
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif(ldif);
+
+        for (LdifEntry entry : entries) {
+            injectEntry(entry, service);
+        }
+
+        // And close the reader
+        reader.close();
+    }
+
+
+    /**
+     * Load the schemas, and enable/disable them.
+     *
+     * @param desc    The description
+     * @param service The DirectoryService instance
+     */
+    public static void loadSchemas(Description desc, DirectoryService service) 
{
+        if (desc == null) {
+            return;
+        }
+
+        /*for ( Class<?> loadSchema : dsBuilder.additionalInterceptors() )
+        {
+            service.addLast( ( Interceptor ) interceptorClass.newInstance() );
+        }*/
+        LoadSchema loadSchema = desc
+                .getAnnotation(LoadSchema.class);
+
+        if (loadSchema != null) {
+            System.out.println(loadSchema);
+        }
+    }
+
+
+    /**
+     * Apply the LDIF entries to the given service
+     *
+     * @param desc    The description
+     * @param service The DirectoryService instance
+     * @throws Exception If we can't apply the ldifs
+     */
+    public static void applyLdifs(Description desc, DirectoryService service)
+            throws Exception {
+        if (desc == null) {
+            return;
+        }
+
+        ApplyLdifFiles applyLdifFiles = desc
+                .getAnnotation(ApplyLdifFiles.class);
+
+        if (applyLdifFiles != null) {
+            LOG.debug("Applying {} to {}", applyLdifFiles.value(),
+                    desc.getDisplayName());
+            injectLdifFiles(applyLdifFiles.clazz(), service, 
applyLdifFiles.value());
+        }
+
+        ApplyLdifs applyLdifs = desc.getAnnotation(ApplyLdifs.class);
+
+        if ((applyLdifs != null) && (applyLdifs.value() != null)) {
+            String[] ldifs = applyLdifs.value();
+
+            String dnStart = "dn:";
+
+            StringBuilder sb = new StringBuilder();
+
+            for (int i = 0; i < ldifs.length;) {
+                String s = ldifs[i++].trim();
+                if (s.startsWith(dnStart)) {
+                    sb.append(s).append('\n');
+
+                    // read the rest of lines till we encounter Dn again
+                    while (i < ldifs.length) {
+                        s = ldifs[i++];
+                        if (!s.startsWith(dnStart)) {
+                            sb.append(s).append('\n');
+                        } else {
+                            break;
+                        }
+                    }
+
+                    LOG.debug("Applying {} to {}", sb, desc.getDisplayName());
+                    injectEntries(service, sb.toString());
+                    sb.setLength(0);
+
+                    i--; // step up a line
+                }
+            }
+        }
+    }
+}
diff --git 
a/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/Description.java
 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/Description.java
new file mode 100644
index 0000000..f8c1b11
--- /dev/null
+++ 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/Description.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.directory.server.core.integ5;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+
+public class Description {
+
+    private final String displayName;
+    private final AnnotatedElement annotated;
+
+    public Description(Method method) {
+        annotated = method;
+        displayName = String.format("%s(%s)", method.getName(), 
method.getDeclaringClass().getName());
+    }
+
+    public Description(Class clazz) {
+        annotated = clazz;
+        displayName = clazz.getName();
+    }
+
+    public <A extends Annotation> A getAnnotation(Class<A> annotation) {
+        return annotated.getAnnotation(annotation);
+    }
+
+    public String getDisplayName() {
+        return displayName;
+    }
+}
diff --git 
a/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/DirectoryExtension.java
 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/DirectoryExtension.java
new file mode 100644
index 0000000..3b8c2cd
--- /dev/null
+++ 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/DirectoryExtension.java
@@ -0,0 +1,281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.directory.server.core.integ5;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.FileUtils;
+import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.changelog.ChangeLog;
+import org.apache.directory.server.core.factory.DefaultDirectoryServiceFactory;
+import org.apache.directory.server.core.factory.DirectoryServiceFactory;
+import org.apache.directory.server.core.factory.PartitionFactory;
+import org.apache.directory.server.core.security.TlsKeyGenerator;
+import org.apache.directory.server.kerberos.kdc.KdcServer;
+import org.apache.directory.server.ldap.LdapServer;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The class responsible for running all the tests. t read the annotations,
+ * initialize the DirectoryService, call each test and do the cleanup at the 
end.
+ *
+ * @author <a href="mailto:[email protected]";>Apache Directory 
Project</a>
+ */
+public class DirectoryExtension implements BeforeAllCallback, 
AfterAllCallback, BeforeEachCallback, AfterEachCallback {
+    /**
+     * A logger for this class
+     */
+    private static final Logger LOG = 
LoggerFactory.getLogger(DirectoryExtension.class);
+
+    private static final ExtensionContext.Namespace NAMESPACE = 
ExtensionContext.Namespace.create(DirectoryExtension.class);
+
+    /**
+     * The 'service' field in the run tests
+     */
+    private static final String SET_SERVICE_METHOD_NAME = "setService";
+
+    /**
+     * The 'ldapServer' field in the run tests
+     */
+    private static final String SET_LDAP_SERVER_METHOD_NAME = "setLdapServer";
+
+    /**
+     * The 'kdcServer' field in the run tests
+     */
+    private static final String SET_KDC_SERVER_METHOD_NAME = "setKdcServer";
+
+    public static class State {
+        DirectoryService classDirectoryService;
+        DirectoryService methodDirectoryService;
+        DirectoryService directoryService;
+        LdapServer classLdapServer;
+        LdapServer methodLdapServer;
+        LdapServer ldapServer;
+        KdcServer classKdcServer;
+        KdcServer methodKdcServer;
+        KdcServer kdcServer;
+        DirectoryService oldLdapServerDirService;
+        DirectoryService oldKdcServerDirService;
+        long revision;
+
+        public void beforeAll(ExtensionContext context) throws Exception {
+            Description description = new 
Description(context.getRequiredTestClass());
+
+            // Before running any test, check to see if we must create a class 
DS
+            // Get the LdapServerBuilder, if any
+
+            classDirectoryService = 
DSAnnotationProcessor.getDirectoryService(description);
+            if (classDirectoryService == null) {
+                // define a default class DS then
+                DirectoryServiceFactory dsf = new 
DefaultDirectoryServiceFactory();
+                classDirectoryService = dsf.getDirectoryService();
+                // enable CL explicitly cause we are not using 
DSAnnotationProcessor
+                classDirectoryService.getChangeLog().setEnabled(true);
+                dsf.init("default" + UUID.randomUUID().toString());
+                // Load the schemas
+                DSAnnotationProcessor.loadSchemas(description, 
classDirectoryService);
+            }
+            // Apply the class LDIFs
+            DSAnnotationProcessor.applyLdifs(description, 
classDirectoryService);
+            updateTlsKey(classDirectoryService);
+
+            // check if it has a LdapServerBuilder, then use the DS created 
above
+            classLdapServer = 
ServerAnnotationProcessor.createLdapServer(description, classDirectoryService);
+
+            classKdcServer = 
ServerAnnotationProcessor.getKdcServer(description, classDirectoryService);
+
+            // print out information which partition factory we use
+            DirectoryServiceFactory dsFactory = new 
DefaultDirectoryServiceFactory();
+            PartitionFactory partitionFactory = 
dsFactory.getPartitionFactory();
+            LOG.debug("Using partition factory {}", 
partitionFactory.getClass().getSimpleName());
+        }
+
+        public void beforeEach(ExtensionContext context) throws Exception {
+            Description classDescription = new 
Description(context.getRequiredTestClass());
+            Description methodDescription = new 
Description(context.getRequiredTestMethod());
+
+            // Check if this method has a dedicated DSBuilder
+            methodDirectoryService = 
DSAnnotationProcessor.getDirectoryService(methodDescription);
+            // give #1 priority to method level DS if present
+            if (methodDirectoryService != null) {
+                // Apply all the LDIFs
+                DSAnnotationProcessor.applyLdifs(classDescription, 
methodDirectoryService);
+                updateTlsKey(methodDirectoryService);
+                directoryService = methodDirectoryService;
+            } else if (classDirectoryService != null) {
+                directoryService = classDirectoryService;
+            } else if (classLdapServer != null) {
+                directoryService = classLdapServer.getDirectoryService();
+            } else if (classKdcServer != null) {
+                directoryService = classKdcServer.getDirectoryService();
+            }
+            // apply the method LDIFs, and tag for reversion
+            revision = getCurrentRevision(directoryService);
+            DSAnnotationProcessor.applyLdifs(methodDescription, 
directoryService);
+
+            methodLdapServer = 
ServerAnnotationProcessor.createLdapServer(methodDescription, directoryService);
+            if (methodLdapServer != null) {
+                ldapServer = methodLdapServer;
+            } else if (classLdapServer != null) {
+                ldapServer = classLdapServer;
+            }
+            if (ldapServer != null) {
+                oldLdapServerDirService = ldapServer.getDirectoryService();
+                ldapServer.setDirectoryService(directoryService);
+            }
+
+            methodKdcServer = 
ServerAnnotationProcessor.getKdcServer(methodDescription, directoryService);
+            if (methodKdcServer != null) {
+                kdcServer = methodKdcServer;
+            } else if (classKdcServer != null) {
+                kdcServer = classKdcServer;
+            }
+            if (kdcServer != null) {
+                oldKdcServerDirService = kdcServer.getDirectoryService();
+                kdcServer.setDirectoryService(directoryService);
+            }
+
+            // At this point, we know which services to use, so inject them 
into the test instance
+            inject(context, SET_SERVICE_METHOD_NAME, DirectoryService.class, 
directoryService);
+            inject(context, SET_LDAP_SERVER_METHOD_NAME, LdapServer.class, 
ldapServer);
+            inject(context, SET_KDC_SERVER_METHOD_NAME, KdcServer.class, 
kdcServer);
+        }
+
+        public void afterEach(ExtensionContext context) throws Exception {
+            if (oldLdapServerDirService != null) {
+                ldapServer.setDirectoryService(oldLdapServerDirService);
+            }
+            if (oldKdcServerDirService != null) {
+                kdcServer.setDirectoryService(oldKdcServerDirService);
+            }
+            if (methodLdapServer != null) {
+                methodLdapServer.stop();
+            }
+            if (methodKdcServer != null) {
+                methodKdcServer.stop();
+            }
+            // Cleanup the methodDS if it has been created
+            if (methodDirectoryService != null) {
+                LOG.debug("Shuting down DS for {}", 
methodDirectoryService.getInstanceId());
+                methodDirectoryService.shutdown();
+                
FileUtils.deleteDirectory(methodDirectoryService.getInstanceLayout().getInstanceDirectory());
+            } else {
+                // We use a class or suite DS, just revert the current test's 
modifications
+                revert(classDirectoryService, revision);
+            }
+        }
+
+        public void afterAll(ExtensionContext context) throws Exception {
+            if (classLdapServer != null) {
+                classLdapServer.stop();
+            }
+            if (classKdcServer != null) {
+                classKdcServer.stop();
+            }
+            if (classDirectoryService != null) {
+                LOG.debug("Shuting down DS for {}", 
classDirectoryService.getInstanceId());
+                classDirectoryService.shutdown();
+                
FileUtils.deleteDirectory(classDirectoryService.getInstanceLayout().getInstanceDirectory());
+            }
+        }
+
+        private <T> void inject(ExtensionContext context, String name, 
Class<T> type, T instance) throws InvocationTargetException, 
IllegalAccessException {
+            try {
+                Method setter = context.getRequiredTestClass().getMethod(name, 
type);
+                setter.invoke(context.getRequiredTestInstance(), instance);
+            } catch (NoSuchMethodException nsme) {
+                // Do nothing
+            }
+        }
+
+        private long getCurrentRevision(DirectoryService dirService) throws 
Exception {
+            if ((dirService != null) && 
(dirService.getChangeLog().isEnabled())) {
+                long revision = dirService.getChangeLog().getCurrentRevision();
+                LOG.debug("Create revision {}", revision);
+                return revision;
+            }
+            return 0;
+        }
+
+        private void revert(DirectoryService dirService, long revision) throws 
Exception {
+            if (dirService == null) {
+                return;
+            }
+            ChangeLog cl = dirService.getChangeLog();
+            if (cl.isEnabled() && (revision < cl.getCurrentRevision())) {
+                LOG.debug("Revert revision {}", revision);
+                dirService.revert(revision);
+            }
+        }
+
+
+        private void updateTlsKey(DirectoryService ds) throws LdapException, 
LdapInvalidDnException {
+            // Update TLS key for tests. Newer Java 8 releases consider RSA 
keys
+            // with less than 1024 bits as insecure and such are disabled by 
default, see
+            // 
http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html
+            Entry adminEntry = ds.getAdminSession().lookup(new 
Dn(ServerDNConstants.ADMIN_SYSTEM_DN));
+            TlsKeyGenerator.addKeyPair(adminEntry, 
TlsKeyGenerator.CERTIFICATE_PRINCIPAL_DN,
+                    TlsKeyGenerator.CERTIFICATE_PRINCIPAL_DN, "RSA", 1024);
+            Modification mod1 = new 
DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE,
+                    adminEntry.get(TlsKeyGenerator.PRIVATE_KEY_AT));
+            Modification mod2 = new 
DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE,
+                    adminEntry.get(TlsKeyGenerator.PUBLIC_KEY_AT));
+            Modification mod3 = new 
DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE,
+                    adminEntry.get(TlsKeyGenerator.USER_CERTIFICATE_AT));
+            ds.getAdminSession().modify(adminEntry.getDn(), mod1, mod2, mod3);
+        }
+    }
+
+    @Override
+    public void beforeAll(ExtensionContext context) throws Exception {
+        
context.getStore(NAMESPACE).getOrComputeIfAbsent(State.class).beforeAll(context);
+    }
+
+    @Override
+    public void beforeEach(ExtensionContext context) throws Exception {
+        
context.getStore(NAMESPACE).getOrComputeIfAbsent(State.class).beforeEach(context);
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) throws Exception {
+        
context.getStore(NAMESPACE).getOrComputeIfAbsent(State.class).afterEach(context);
+    }
+
+    @Override
+    public void afterAll(ExtensionContext context) throws Exception {
+        
context.getStore(NAMESPACE).getOrComputeIfAbsent(State.class).afterAll(context);
+    }
+
+}
diff --git 
a/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/ServerAnnotationProcessor.java
 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/ServerAnnotationProcessor.java
new file mode 100644
index 0000000..bd918a5
--- /dev/null
+++ 
b/components/camel-ldif/src/test/java/org/apache/directory/server/core/integ5/ServerAnnotationProcessor.java
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.directory.server.core.integ5;
+
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
+import org.apache.directory.api.util.Network;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.server.annotations.CreateChngPwdServer;
+import org.apache.directory.server.annotations.CreateConsumer;
+import org.apache.directory.server.annotations.CreateKdcServer;
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.annotations.SaslMechanism;
+import org.apache.directory.server.core.annotations.AnnotationUtils;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.server.kerberos.ChangePasswordConfig;
+import org.apache.directory.server.kerberos.KerberosConfig;
+import org.apache.directory.server.kerberos.changepwd.ChangePasswordServer;
+import org.apache.directory.server.kerberos.kdc.KdcServer;
+import org.apache.directory.server.ldap.ExtendedOperationHandler;
+import org.apache.directory.server.ldap.LdapServer;
+import org.apache.directory.server.ldap.handlers.sasl.MechanismHandler;
+import 
org.apache.directory.server.ldap.handlers.sasl.ntlm.NtlmMechanismHandler;
+import org.apache.directory.server.ldap.handlers.sasl.ntlm.NtlmProvider;
+import org.apache.directory.server.ldap.replication.SyncReplConfiguration;
+import 
org.apache.directory.server.ldap.replication.consumer.ReplicationConsumer;
+import 
org.apache.directory.server.ldap.replication.consumer.ReplicationConsumerImpl;
+import org.apache.directory.server.protocol.shared.transport.TcpTransport;
+import org.apache.directory.server.protocol.shared.transport.Transport;
+import org.apache.directory.server.protocol.shared.transport.UdpTransport;
+
+
+/**
+ * Annotation processor for creating LDAP and Kerberos servers.
+ *
+ * @author <a href="mailto:[email protected]";>Apache Directory 
Project</a>
+ */
+public final class ServerAnnotationProcessor {
+
+    private ServerAnnotationProcessor() {
+    }
+
+    private static void createTransports(LdapServer ldapServer, 
CreateTransport[] transportBuilders) {
+        if (transportBuilders.length != 0) {
+            for (CreateTransport transportBuilder : transportBuilders) {
+                List<Transport> transports = 
createTransports(transportBuilder);
+
+                for (Transport t : transports) {
+                    ldapServer.addTransports(t);
+                }
+            }
+        } else {
+            // Create default LDAP and LDAPS transports
+            try {
+                int port = getFreePort();
+                Transport ldap = new TcpTransport(port);
+                ldapServer.addTransports(ldap);
+            } catch (IOException ioe) {
+                // Don't know what to do here...
+            }
+
+            try {
+                int port = getFreePort();
+                Transport ldaps = new TcpTransport(port);
+                ldaps.setEnableSSL(true);
+                ldapServer.addTransports(ldaps);
+            } catch (IOException ioe) {
+                // Don't know what to do here...
+            }
+        }
+    }
+
+
+    /**
+     * Just gives an instance of {@link LdapServer} without starting it.
+     * For getting a running LdapServer instance see {@link 
#createLdapServer(CreateLdapServer, DirectoryService)}
+     *
+     * @param createLdapServer The LdapServer to create
+     * @param directoryService the directory service
+     * @return The created LdapServer
+     * @see #createLdapServer(CreateLdapServer, DirectoryService)
+     */
+    public static LdapServer instantiateLdapServer(CreateLdapServer 
createLdapServer, DirectoryService directoryService) {
+        if (createLdapServer != null) {
+            LdapServer ldapServer = new LdapServer();
+
+            ldapServer.setServiceName(createLdapServer.name());
+
+            // Read the transports
+            createTransports(ldapServer, createLdapServer.transports());
+
+            // Associate the DS to this LdapServer
+            ldapServer.setDirectoryService(directoryService);
+
+            // Propagate the anonymous flag to the DS
+            
directoryService.setAllowAnonymousAccess(createLdapServer.allowAnonymousAccess());
+
+            ldapServer.setSaslHost(createLdapServer.saslHost());
+
+            ldapServer.setSaslPrincipal(createLdapServer.saslPrincipal());
+
+            if (!Strings.isEmpty(createLdapServer.keyStore())) {
+                ldapServer.setKeystoreFile(createLdapServer.keyStore());
+                
ldapServer.setCertificatePassword(createLdapServer.certificatePassword());
+            }
+
+            for (Class<?> extOpClass : createLdapServer.extendedOpHandlers()) {
+                try {
+                    ExtendedOperationHandler extOpHandler = 
(ExtendedOperationHandler) extOpClass
+                            .getDeclaredConstructor().newInstance();
+                    ldapServer.addExtendedOperationHandler(extOpHandler);
+                } catch (Exception e) {
+                    throw new RuntimeException(I18n.err(I18n.ERR_690, 
extOpClass.getName()), e);
+                }
+            }
+
+            for (SaslMechanism saslMech : createLdapServer.saslMechanisms()) {
+                try {
+                    MechanismHandler handler = (MechanismHandler) 
saslMech.implClass()
+                            .getDeclaredConstructor().newInstance();
+                    ldapServer.addSaslMechanismHandler(saslMech.name(), 
handler);
+                } catch (Exception e) {
+                    throw new RuntimeException(
+                            I18n.err(I18n.ERR_691, saslMech.name(), 
saslMech.implClass().getName()), e);
+                }
+            }
+
+            NtlmMechanismHandler ntlmHandler = (NtlmMechanismHandler) 
ldapServer.getSaslMechanismHandlers().get(
+                    SupportedSaslMechanisms.NTLM);
+
+            if (ntlmHandler != null) {
+                Class<?> ntlmProviderClass = createLdapServer.ntlmProvider();
+                // default value is a invalid Object.class
+                if ((ntlmProviderClass != null) && (ntlmProviderClass != 
Object.class)) {
+                    try {
+                        ntlmHandler.setNtlmProvider((NtlmProvider) 
ntlmProviderClass
+                                .getDeclaredConstructor().newInstance());
+                    } catch (Exception e) {
+                        throw new RuntimeException(I18n.err(I18n.ERR_692), e);
+                    }
+                }
+            }
+
+            List<String> realms = new ArrayList<String>();
+            for (String s : createLdapServer.saslRealms()) {
+                realms.add(s);
+            }
+
+            ldapServer.setSaslRealms(realms);
+
+            return ldapServer;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Returns an LdapServer instance and starts it before returning the 
instance, infering
+     * the configuration from the Stack trace
+     *
+     * @param directoryService the directory service
+     * @return a running LdapServer instance
+     * @throws ClassNotFoundException If the CreateLdapServer class cannot be 
loaded
+     */
+    public static LdapServer getLdapServer(DirectoryService directoryService) 
throws ClassNotFoundException {
+        Object instance = AnnotationUtils.getInstance(CreateLdapServer.class);
+        LdapServer ldapServer = null;
+
+        if (instance != null) {
+            CreateLdapServer createLdapServer = (CreateLdapServer) instance;
+
+            ldapServer = createLdapServer(createLdapServer, directoryService);
+        }
+
+        return ldapServer;
+    }
+
+
+    /**
+     * Create a replication consumer
+     */
+    private static ReplicationConsumer createConsumer(CreateConsumer 
createConsumer) {
+        ReplicationConsumer consumer = new ReplicationConsumerImpl();
+
+        SyncReplConfiguration config = new SyncReplConfiguration();
+
+        String remoteHost = createConsumer.remoteHost();
+
+        if (Strings.isEmpty(remoteHost)) {
+            remoteHost = Network.LOOPBACK_HOSTNAME;
+        }
+
+        config.setRemoteHost(remoteHost);
+        config.setRemotePort(createConsumer.remotePort());
+        config.setReplUserDn(createConsumer.replUserDn());
+        
config.setReplUserPassword(Strings.getBytesUtf8(createConsumer.replUserPassword()));
+        config.setUseTls(createConsumer.useTls());
+        config.setBaseDn(createConsumer.baseDn());
+        config.setRefreshInterval(createConsumer.refreshInterval());
+
+        consumer.setConfig(config);
+
+        return consumer;
+    }
+
+
+    /**
+     * creates an LdapServer and starts before returning the instance, infering
+     * the configuration from the Stack trace
+     *
+     * @return a running LdapServer instance
+     * @throws ClassNotFoundException If the CreateConsumer class cannot be 
loaded
+     */
+    public static ReplicationConsumer createConsumer() throws 
ClassNotFoundException {
+        Object instance = AnnotationUtils.getInstance(CreateConsumer.class);
+        ReplicationConsumer consumer = null;
+
+        if (instance != null) {
+            CreateConsumer createConsumer = (CreateConsumer) instance;
+
+            consumer = createConsumer(createConsumer);
+        }
+
+        return consumer;
+    }
+
+
+    /**
+     * creates an LdapServer and starts before returning the instance
+     *
+     * @param createLdapServer the annotation containing the custom 
configuration
+     * @param directoryService the directory service
+     * @return a running LdapServer instance
+     */
+    private static LdapServer createLdapServer(CreateLdapServer 
createLdapServer, DirectoryService directoryService) {
+        LdapServer ldapServer = instantiateLdapServer(createLdapServer, 
directoryService);
+
+        if (ldapServer == null) {
+            return null;
+        }
+
+        // Launch the server
+        try {
+            ldapServer.start();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return ldapServer;
+    }
+
+
+    /**
+     * Create a new instance of LdapServer
+     *
+     * @param description      A description for the created LdapServer
+     * @param directoryService The associated DirectoryService
+     * @return An LdapServer instance
+     */
+    public static LdapServer createLdapServer(Description description, 
DirectoryService directoryService) {
+        CreateLdapServer createLdapServer = 
description.getAnnotation(CreateLdapServer.class);
+
+        // Ok, we have found a CreateLdapServer annotation. Process it now.
+        return createLdapServer(createLdapServer, directoryService);
+    }
+
+
+    @SuppressWarnings("unchecked")
+    private static Annotation getAnnotation(Class annotationClass) throws 
Exception {
+        // Get the caller by inspecting the stackTrace
+        StackTraceElement[] stackTrace = 
Thread.currentThread().getStackTrace();
+
+        // In Java5 the 0th stacktrace element is: 
java.lang.Thread.dumpThreads(Native Method)
+        int index = stackTrace[0].getMethodName().equals("dumpThreads") ? 4 : 
3;
+
+        // Get the enclosing class
+        Class<?> classCaller = Class.forName(stackTrace[index].getClassName());
+
+        // Get the current method
+        String methodCaller = stackTrace[index].getMethodName();
+
+        // Check if we have any annotation associated with the method
+        Method[] methods = classCaller.getMethods();
+
+        for (Method method : methods) {
+            if (methodCaller.equals(method.getName())) {
+                Annotation annotation = method.getAnnotation(annotationClass);
+
+                if (annotation != null) {
+                    return annotation;
+                }
+            }
+        }
+
+        // No : look at the class level
+        return classCaller.getAnnotation(annotationClass);
+    }
+
+
+    public static KdcServer getKdcServer(DirectoryService directoryService, 
int startPort) throws Exception {
+        CreateKdcServer createKdcServer = (CreateKdcServer) 
getAnnotation(CreateKdcServer.class);
+        return createKdcServer(createKdcServer, directoryService);
+    }
+
+
+    private static KdcServer createKdcServer(CreateKdcServer createKdcServer, 
DirectoryService directoryService) {
+        if (createKdcServer == null) {
+            return null;
+        }
+
+        KerberosConfig kdcConfig = new KerberosConfig();
+        kdcConfig.setServicePrincipal(createKdcServer.kdcPrincipal());
+        kdcConfig.setPrimaryRealm(createKdcServer.primaryRealm());
+        
kdcConfig.setMaximumTicketLifetime(createKdcServer.maxTicketLifetime());
+        
kdcConfig.setMaximumRenewableLifetime(createKdcServer.maxRenewableLifetime());
+
+        KdcServer kdcServer = new KdcServer(kdcConfig);
+
+        kdcServer.setSearchBaseDn(createKdcServer.searchBaseDn());
+
+        CreateTransport[] transportBuilders = createKdcServer.transports();
+
+        if (transportBuilders == null) {
+            // create only UDP transport if none specified
+            int port = 0;
+            try {
+                port = getFreePort();
+            } catch (IOException ioe) {
+                // Don't know what to do here...
+            }
+            UdpTransport defaultTransport = new UdpTransport(port);
+            kdcServer.addTransports(defaultTransport);
+        } else if (transportBuilders.length > 0) {
+            for (CreateTransport transportBuilder : transportBuilders) {
+                List<Transport> transports = 
createTransports(transportBuilder);
+                for (Transport t : transports) {
+                    kdcServer.addTransports(t);
+                }
+            }
+        }
+
+        CreateChngPwdServer[] createChngPwdServers = 
createKdcServer.chngPwdServer();
+
+        if (createChngPwdServers.length > 0) {
+
+            CreateChngPwdServer createChngPwdServer = createChngPwdServers[0];
+            ChangePasswordConfig config = new ChangePasswordConfig(kdcConfig);
+            config.setServicePrincipal(createChngPwdServer.srvPrincipal());
+
+            ChangePasswordServer chngPwdServer = new 
ChangePasswordServer(config);
+
+            for (CreateTransport transportBuilder : 
createChngPwdServer.transports()) {
+                List<Transport> transports = 
createTransports(transportBuilder);
+                for (Transport t : transports) {
+                    chngPwdServer.addTransports(t);
+                }
+            }
+
+            chngPwdServer.setDirectoryService(directoryService);
+
+            kdcServer.setChangePwdServer(chngPwdServer);
+        }
+
+        kdcServer.setDirectoryService(directoryService);
+
+        // Launch the server
+        try {
+            kdcServer.start();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return kdcServer;
+    }
+
+
+    private static List<Transport> createTransports(CreateTransport 
transportBuilder) {
+        String protocol = transportBuilder.protocol();
+        int port = transportBuilder.port();
+        int nbThreads = transportBuilder.nbThreads();
+        int backlog = transportBuilder.backlog();
+        String address = transportBuilder.address();
+
+        if (Strings.isEmpty(address)) {
+            address = Network.LOOPBACK_HOSTNAME;
+        }
+
+        if (port <= 0) {
+            try {
+                port = getFreePort();
+            } catch (IOException ioe) {
+                // Don't know what to do here...
+            }
+        }
+
+        if (protocol.equalsIgnoreCase("TCP") || 
protocol.equalsIgnoreCase("LDAP")) {
+            Transport tcp = new TcpTransport(address, port, nbThreads, 
backlog);
+            return Collections.singletonList(tcp);
+        } else if (protocol.equalsIgnoreCase("LDAPS")) {
+            Transport tcp = new TcpTransport(address, port, nbThreads, 
backlog);
+            tcp.setEnableSSL(true);
+            return Collections.singletonList(tcp);
+        } else if (protocol.equalsIgnoreCase("UDP")) {
+            Transport udp = new UdpTransport(address, port);
+            return Collections.singletonList(udp);
+        } else if (protocol.equalsIgnoreCase("KRB") || 
protocol.equalsIgnoreCase("CPW")) {
+            Transport tcp = new TcpTransport(address, port, nbThreads, 
backlog);
+            List<Transport> transports = new ArrayList<Transport>();
+            transports.add(tcp);
+
+            Transport udp = new UdpTransport(address, port);
+            transports.add(udp);
+            return transports;
+        }
+
+        throw new IllegalArgumentException(I18n.err(I18n.ERR_689, protocol));
+    }
+
+    private static int getFreePort() throws IOException {
+        ServerSocket ss = new ServerSocket(0);
+        int port = ss.getLocalPort();
+        ss.close();
+
+        return port;
+    }
+
+    public static KdcServer getKdcServer(Description description, 
DirectoryService directoryService)
+            throws Exception {
+        CreateKdcServer createLdapServer = 
description.getAnnotation(CreateKdcServer.class);
+
+        return createKdcServer(createLdapServer, directoryService);
+    }
+
+}

Reply via email to