From 8d5e49f4af7da9e6c1311216c6bde13625defab3 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Thu, 12 Dec 2013 11:04:45 +0000
Subject: [PATCH] Checkpoint commit for OPENDJ-1235 : Migrate configuration framework

---
 opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java            |   11 
 opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMock.java     |  217 +++++++++++++++++++++++++++++++
 opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigTestCase.java        |   45 ++++++
 opendj-admin/pom.xml                                                              |   13 +
 opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMockTest.java |   83 +++++++++++
 5 files changed, 361 insertions(+), 8 deletions(-)

diff --git a/opendj-admin/pom.xml b/opendj-admin/pom.xml
index a67d3db..ef20cf6 100644
--- a/opendj-admin/pom.xml
+++ b/opendj-admin/pom.xml
@@ -33,6 +33,13 @@
       <artifactId>i18n-core</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.forgerock.opendj</groupId>
+      <artifactId>opendj-core</artifactId>
+      <type>test-jar</type>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.forgerock.commons</groupId>
       <artifactId>i18n-slf4j</artifactId>
     </dependency>
@@ -145,13 +152,13 @@
             </goals>
             <configuration>
               <outputDirectory>${project.build.directory}/generated-sources/java</outputDirectory>
-              <resources>          
+              <resources>
                 <resource>
                   <directory>src/main/java-templates</directory>
                   <filtering>true</filtering>
                 </resource>
-              </resources>              
-            </configuration>            
+              </resources>
+            </configuration>
           </execution>
         </executions>
       </plugin>
diff --git a/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java b/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java
index 0e59e77..a33ca5f 100644
--- a/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java
+++ b/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -28,16 +28,17 @@
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.schema.AttributeType;
 import org.forgerock.opendj.ldap.schema.ObjectClass;
+import org.forgerock.opendj.ldap.schema.Schema;
 import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
 
 /**
- * TODO : this is a stub
+ * TODO : this is a stub, with default or no implementation
  */
 public class DirectoryServer {
 
     public static AttributeType getAttributeType(String name, boolean b) {
-        throw new RuntimeException("Not implemented");
+        return Schema.getDefaultSchema().getAttributeType(name);
     }
 
     public static String getInstanceRoot() {
@@ -48,12 +49,12 @@
         throw new RuntimeException("Not implemented");
     }
 
-    public static ObjectClass getObjectClass(String lowerCase) {
-        throw new RuntimeException("Not implemented");
+    public static ObjectClass getObjectClass(String name) {
+        return Schema.getDefaultSchema().getObjectClass(name);
     }
 
     public static ObjectClass getDefaultObjectClass(String name) {
-        throw new RuntimeException("Not implemented");
+        return getObjectClass(name);
     }
 
     public static ConfigEntry getConfigEntry(DN dn) throws ConfigException {
diff --git a/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigTestCase.java b/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigTestCase.java
new file mode 100644
index 0000000..92a32e4
--- /dev/null
+++ b/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigTestCase.java
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2013 ForgeRock AS.
+ */
+package org.forgerock.opendj.config;
+
+import org.forgerock.opendj.ldap.SdkTestCase;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.testng.annotations.Test;
+
+/**
+ * An abstract class that all unit tests should extend.
+ */
+@Test(groups = { "precommit", "config" })
+public abstract class ConfigTestCase extends SdkTestCase {
+
+    protected void disableClassValidationForProperties() {
+        ClassPropertyDefinition.setAllowClassValidation(false);
+    }
+
+    protected void enableClassValidationForProperties() {
+        ClassPropertyDefinition.setAllowClassValidation(true);
+    }
+}
diff --git a/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMock.java b/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMock.java
new file mode 100644
index 0000000..1ea2ae0
--- /dev/null
+++ b/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMock.java
@@ -0,0 +1,217 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2013 ForgeRock AS.
+ */
+package org.forgerock.opendj.config;
+
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.util.Collection;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.AliasDefaultBehaviorProvider;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.DefaultBehaviorProvider;
+import org.opends.server.admin.DefaultBehaviorProviderVisitor;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.EnumPropertyDefinition;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+
+/**
+ * Provides Mockito mocks for Configuration objects with default values
+ * corresponding to those defined in xml configuration files.
+ * <p>
+ * These mocks can be used like any other mocks, e.g, you can define stubs using
+ * {@code when} method or verify calls using {@code verify} method.
+ * <p>
+ * Example:
+ *
+ * <pre>
+ * {
+ *     &#064;code
+ *     LDAPConnectionHandlerCfg mockCfg = mockCfg(LDAPConnectionHandlerCfg.class);
+ *     assertThat(mockCfg.getMaxRequestSize()).isEqualTo(5 * 1000 * 1000);
+ * }
+ * </pre>
+ */
+public final class ConfigurationMock {
+
+    private static final ConfigAnswer configAnswer = new ConfigAnswer();
+
+    /**
+     * Returns a mock for the provided configuration class.
+     * <p>
+     * If a setting has a default value, the mock automatically returns the
+     * default value when the getter is called on the setting.
+     * <p>
+     * It is possible to override this default behavior with the usual methods
+     * calls with Mockito (e.g, {@code when} method).
+     *
+     * @param <T>
+     *            The type of configuration.
+     * @param configClass
+     *            The configuration class.
+     * @return a mock
+     */
+    public static <T extends Configuration> T mockCfg(Class<T> configClass) {
+        return mock(configClass, configAnswer);
+    }
+
+    /**
+     * A stubbed answer for Configuration objects, allowing to return default
+     * value for settings when available.
+     */
+    private static class ConfigAnswer implements org.mockito.stubbing.Answer<Object> {
+
+        /** {@inheritDoc} */
+        @Override
+        public Object answer(InvocationOnMock invocation) throws Throwable {
+            String definitionClassName = toDefinitionClassName(invocation.getMethod().getDeclaringClass()
+                    .getName());
+            Class<?> definitionClass = Class.forName(definitionClassName);
+            ManagedObjectDefinition<?, ?> definition = (ManagedObjectDefinition<?, ?>) definitionClass.getMethod(
+                    "getInstance").invoke(null);
+            Method getPropertyDefMethod =
+                    definitionClass.getMethod(invocation.getMethod().getName() + "PropertyDefinition");
+            Class<?> propertyReturnType = getPropertyReturnType(getPropertyDefMethod);
+            return getDefaultValue(definition, getPropertyDefMethod, propertyReturnType);
+        }
+
+        /**
+         * Returns the type of values returned by the property.
+         */
+        private Class<?> getPropertyReturnType(Method getPropertyDefMethod) {
+            Class<?> returnClass = getPropertyDefMethod.getReturnType();
+            return ((ParameterizedType) returnClass.getGenericSuperclass())
+                    .getActualTypeArguments()[0].getClass();
+        }
+
+        /**
+         * Retrieve class name of definition from class name of configuration.
+         * <p>
+         * Convert class name "[package].admin.server.FooCfg" to
+         * "[package].admin.meta.FooCfgDef"
+         */
+        private String toDefinitionClassName(String configClassName) {
+            return configClassName.replaceAll("\\.admin\\.server", ".admin.meta") + "Defn";
+        }
+
+        /**
+         * Returns the default value corresponding to the provided property
+         * definition getter method from the provided managed object definition.
+         *
+         * @param <T>
+         *            The data type of values provided by the property
+         *            definition.
+         * @param definition
+         *            The definition of the managed object.
+         * @param getPropertyDefMethod
+         *            The method to retrieve the property definition from the
+         *            definition.
+         * @param propertyReturnClass
+         *            The class of values provided by the property definition.
+         * @return the default value of property definition, or
+         *         {@code null} if there is no default value.
+         * @throws Exception
+         *             If an error occurs.
+         */
+        @SuppressWarnings({ "unchecked", "unused" })
+        private <T> Object getDefaultValue(ManagedObjectDefinition<?, ?> definition,
+                Method getPropertyDefMethod, Class<T> propertyReturnClass) throws Exception {
+            PropertyDefinition<T> propertyDefinition = (PropertyDefinition<T>) getPropertyDefMethod.invoke(definition);
+            DefaultBehaviorProvider<T> defaultBehaviorProvider = (DefaultBehaviorProvider<T>) propertyDefinition
+                    .getClass().getMethod("getDefaultBehaviorProvider").invoke(propertyDefinition);
+            MockProviderVisitor<T> visitor = new MockProviderVisitor<T>(propertyDefinition);
+            Collection<T> values = defaultBehaviorProvider.accept(visitor, null);
+
+            if (propertyDefinition instanceof EnumPropertyDefinition) {
+                // enum values returned as a sorted set
+                return values;
+            } else {
+                // single value returned
+                return values.iterator().next();
+            }
+        }
+
+    }
+
+    /** Visitor used to retrieve the default value. */
+    private static class MockProviderVisitor<T> implements DefaultBehaviorProviderVisitor<T, Collection<T>, Void> {
+
+        /** The property definition used to decode the values. */
+        private PropertyDefinition<T> propertyDef;
+
+        MockProviderVisitor(PropertyDefinition<T> propertyDef) {
+            this.propertyDef = propertyDef;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Collection<T> visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider<T> provider, Void p) {
+            // not handled
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> provider, Void p) {
+            // not handled
+            return null;
+        }
+
+        /**
+         * Returns the default value for the property as a collection.
+         */
+        @Override
+        public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> provider, Void p) {
+            SortedSet<T> values = new TreeSet<T>();
+            for (String stringValue : provider.getDefaultValues()) {
+                values.add(propertyDef.decodeValue(stringValue));
+            }
+            return values;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Collection<T> visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
+            // not handled
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d, Void p) {
+            // not handled
+            return null;
+        }
+    }
+}
diff --git a/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMockTest.java b/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMockTest.java
new file mode 100644
index 0000000..6673939
--- /dev/null
+++ b/opendj-admin/src/test/java/org/forgerock/opendj/config/ConfigurationMockTest.java
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2013 ForgeRock AS.
+ */
+package org.forgerock.opendj.config;
+
+import static org.fest.assertions.Assertions.*;
+import static org.forgerock.opendj.config.ConfigurationMock.*;
+
+import org.forgerock.opendj.admin.meta.PluginCfgDefn.PluginType;
+import org.forgerock.opendj.admin.server.AttributeCleanupPluginCfg;
+import org.forgerock.opendj.admin.server.CollectiveAttributeSubentriesVirtualAttributeCfg;
+import org.forgerock.opendj.admin.server.GoverningStructureRuleVirtualAttributeCfg;
+import org.forgerock.opendj.admin.server.LDAPConnectionHandlerCfg;
+import org.forgerock.opendj.ldap.schema.Schema;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Test case to ensure that ConfigurationMock class is correct.
+ */
+@SuppressWarnings("javadoc")
+public class ConfigurationMockTest extends ConfigTestCase {
+
+    @BeforeClass
+    void setup() {
+        disableClassValidationForProperties();
+    }
+
+    @AfterClass
+    void cleanup() {
+        enableClassValidationForProperties();
+    }
+
+    @Test
+    public void testPropertyWithStringReturnValue() {
+        GoverningStructureRuleVirtualAttributeCfg mock = mockCfg(GoverningStructureRuleVirtualAttributeCfg.class);
+        assertThat(mock.getJavaClass()).
+            isEqualTo("org.opends.server.extensions.GoverningSturctureRuleVirtualAttributeProvider");
+    }
+
+    @Test
+    public void testPropertyWithLongReturnValue() throws Exception {
+        LDAPConnectionHandlerCfg mock = mockCfg(LDAPConnectionHandlerCfg.class);
+        assertThat(mock.getMaxRequestSize()).isEqualTo(5 * 1000 * 1000);
+    }
+
+    @Test
+    public void testPropertyWithEnumReturnValue() throws Exception {
+        AttributeCleanupPluginCfg mock = mockCfg(AttributeCleanupPluginCfg.class);
+        assertThat(mock.getPluginType()).containsOnly(PluginType.PREPARSEADD, PluginType.PREPARSEMODIFY);
+    }
+
+    @Test
+    public void testPropertyWithAttributeTypeReturnValue() throws Exception {
+        CollectiveAttributeSubentriesVirtualAttributeCfg mock =
+                mockCfg(CollectiveAttributeSubentriesVirtualAttributeCfg.class);
+        assertThat(mock.getAttributeType()).isEqualTo(
+                Schema.getDefaultSchema().getAttributeType("collectiveAttributeSubentries"));
+    }
+}

--
Gitblit v1.10.0