You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2015/07/30 08:24:35 UTC

[28/50] [abbrv] directory-kerby git commit: DIRKRB-382 Promote kerby-config and kerby-util as top level modules, getting rid of lib

DIRKRB-382 Promote kerby-config and kerby-util as top level modules, getting rid of lib


Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/6bb66073
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/6bb66073
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/6bb66073

Branch: refs/heads/pkinit-support
Commit: 6bb6607360a972a8cab546c2750f0c663975e214
Parents: fcc6ab3
Author: drankye <ka...@intel.com>
Authored: Sun Jul 19 05:32:00 2015 +0800
Committer: Drankye <dr...@gmail.com>
Committed: Sun Jul 19 05:32:00 2015 +0800

----------------------------------------------------------------------
 kerby-config/README                             |    1 +
 kerby-config/pom.xml                            |   37 +
 .../main/java/org/apache/kerby/config/Conf.java |  342 ++++++
 .../java/org/apache/kerby/config/Config.java    |  139 +++
 .../org/apache/kerby/config/ConfigImpl.java     |  422 +++++++
 .../java/org/apache/kerby/config/ConfigKey.java |   25 +
 .../org/apache/kerby/config/ConfigLoader.java   |   50 +
 .../org/apache/kerby/config/ConfigObject.java   |   85 ++
 .../org/apache/kerby/config/Configurable.java   |   30 +
 .../org/apache/kerby/config/Configured.java     |   45 +
 .../apache/kerby/config/IniConfigLoader.java    |   75 ++
 .../apache/kerby/config/JsonConfigLoader.java   |   27 +
 .../apache/kerby/config/MapConfigLoader.java    |   33 +
 .../kerby/config/PropertiesConfigLoader.java    |   42 +
 .../config/PropertiesFileConfigLoader.java      |   33 +
 .../java/org/apache/kerby/config/Resource.java  |  121 ++
 .../apache/kerby/config/XmlConfigLoader.java    |  153 +++
 .../java/org/apache/kerby/config/ConfTest.java  |  131 +++
 .../org/apache/kerby/config/ConfigImplTest.java |   63 ++
 .../org/apache/kerby/config/IniConfigTest.java  |   88 ++
 kerby-util/pom.xml                              |   29 +
 .../src/main/java/org/apache/kerby/KOption.java |   41 +
 .../main/java/org/apache/kerby/KOptionType.java |   35 +
 .../main/java/org/apache/kerby/KOptions.java    |  188 ++++
 .../main/java/org/apache/kerby/util/Base64.java | 1048 ++++++++++++++++++
 .../apache/kerby/util/Base64InputStream.java    |  174 +++
 .../apache/kerby/util/Base64OutputStream.java   |  198 ++++
 .../main/java/org/apache/kerby/util/Hex.java    |   77 ++
 .../java/org/apache/kerby/util/HexUtil.java     |   59 +
 .../main/java/org/apache/kerby/util/IOUtil.java |  106 ++
 .../java/org/apache/kerby/util/NetworkUtil.java |   48 +
 .../main/java/org/apache/kerby/util/OSUtil.java |   62 ++
 .../java/org/apache/kerby/util/SysUtil.java     |   35 +
 .../main/java/org/apache/kerby/util/Utf8.java   |   42 +
 lib/README.md                                   |    1 -
 lib/kerby-config/README                         |    1 -
 lib/kerby-config/pom.xml                        |   37 -
 .../main/java/org/apache/kerby/config/Conf.java |  342 ------
 .../java/org/apache/kerby/config/Config.java    |  139 ---
 .../org/apache/kerby/config/ConfigImpl.java     |  422 -------
 .../java/org/apache/kerby/config/ConfigKey.java |   25 -
 .../org/apache/kerby/config/ConfigLoader.java   |   50 -
 .../org/apache/kerby/config/ConfigObject.java   |   85 --
 .../org/apache/kerby/config/Configurable.java   |   30 -
 .../org/apache/kerby/config/Configured.java     |   45 -
 .../apache/kerby/config/IniConfigLoader.java    |   75 --
 .../apache/kerby/config/JsonConfigLoader.java   |   27 -
 .../apache/kerby/config/MapConfigLoader.java    |   33 -
 .../kerby/config/PropertiesConfigLoader.java    |   42 -
 .../config/PropertiesFileConfigLoader.java      |   33 -
 .../java/org/apache/kerby/config/Resource.java  |  121 --
 .../apache/kerby/config/XmlConfigLoader.java    |  153 ---
 .../java/org/apache/kerby/config/ConfTest.java  |  131 ---
 .../org/apache/kerby/config/ConfigImplTest.java |   63 --
 .../org/apache/kerby/config/IniConfigTest.java  |   88 --
 lib/kerby-util/pom.xml                          |   29 -
 .../src/main/java/org/apache/kerby/KOption.java |   41 -
 .../main/java/org/apache/kerby/KOptionType.java |   35 -
 .../main/java/org/apache/kerby/KOptions.java    |  188 ----
 .../main/java/org/apache/kerby/util/Base64.java | 1048 ------------------
 .../apache/kerby/util/Base64InputStream.java    |  174 ---
 .../apache/kerby/util/Base64OutputStream.java   |  198 ----
 .../main/java/org/apache/kerby/util/Hex.java    |   77 --
 .../java/org/apache/kerby/util/HexUtil.java     |   59 -
 .../main/java/org/apache/kerby/util/IOUtil.java |  106 --
 .../java/org/apache/kerby/util/NetworkUtil.java |   48 -
 .../main/java/org/apache/kerby/util/OSUtil.java |   62 --
 .../java/org/apache/kerby/util/SysUtil.java     |   35 -
 .../main/java/org/apache/kerby/util/Utf8.java   |   42 -
 lib/pom.xml                                     |   37 -
 70 files changed, 4084 insertions(+), 4122 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/README
----------------------------------------------------------------------
diff --git a/kerby-config/README b/kerby-config/README
new file mode 100644
index 0000000..37eb019
--- /dev/null
+++ b/kerby-config/README
@@ -0,0 +1 @@
+An unified configuration API that crosses various popular configuration formats like XML, JSON, INI and etc.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-config/pom.xml b/kerby-config/pom.xml
new file mode 100644
index 0000000..1499d09
--- /dev/null
+++ b/kerby-config/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.apache.kerby</groupId>
+    <artifactId>lib</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>kerby-config</artifactId>
+  <name>Kerby Config</name>
+  <description>Kerby config library</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/Conf.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/Conf.java b/kerby-config/src/main/java/org/apache/kerby/config/Conf.java
new file mode 100644
index 0000000..a207f52
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/Conf.java
@@ -0,0 +1,342 @@
+/**
+ *  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.kerby.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+public class Conf implements Config {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Conf.class);
+
+    private List<ConfigLoader> resourceConfigs;
+    private final ConfigImpl config;
+    private final Map<String, String> setValues;
+    private boolean needReload;
+
+    public Conf() {
+        this.resourceConfigs = new ArrayList<ConfigLoader>(1);
+        this.config = new ConfigImpl("Conf");
+        this.setValues = new HashMap<>(10);
+        this.needReload = true;
+
+        addMapConfig(setValues);
+    }
+
+    public void addXmlConfig(File xmlFile) throws IOException {
+        addResource(Resource.createXmlResource(xmlFile));
+    }
+
+    public void addIniConfig(File iniFile) throws IOException {
+        addResource(Resource.createIniResource(iniFile));
+    }
+
+    public void addJsonConfig(File jsonFile) throws IOException {
+        addResource(Resource.createJsonResource(jsonFile));
+    }
+
+    public void addPropertiesConfig(File propertiesFile) throws IOException {
+        addResource(Resource.createPropertiesFileResource(propertiesFile));
+    }
+
+    public void addPropertiesConfig(Properties propertiesConfig) {
+        addResource(Resource.createPropertiesResource(propertiesConfig));
+    }
+
+    public void addMapConfig(Map<String, String> mapConfig) {
+        addResource(Resource.createMapResource(mapConfig));
+    }
+
+    public void addResource(Resource resource) {
+        ConfigLoader loader = getLoader(resource);
+        resourceConfigs.add(loader);
+        needReload = true;
+    }
+
+    private static ConfigLoader getLoader(Resource resource) {
+        ConfigLoader loader = null;
+
+        Class<? extends ConfigLoader> loaderClass = resource.getFormat().getLoaderClass();
+        try {
+            loader = loaderClass.newInstance();
+        } catch (Exception e) {
+            LOGGER.error("Failed to create " + Conf.class.getPackage().getName()
+                    + " for " + loaderClass.getName(), e);
+            throw new RuntimeException("Failed to create "
+                    + Conf.class.getPackage().getName() + " for " + loaderClass.getName(), e);
+        }
+        loader.setResource(resource);
+        return loader;
+    }
+
+    private void checkAndLoad() {
+        if (needReload) {
+            reload();
+            needReload = false;
+        }
+    }
+
+    public void reload() {
+        config.reset();
+
+        for (ConfigLoader loader : resourceConfigs) {
+            Config loaded = loader.load();
+            config.add(loaded);
+        }
+    }
+
+    @Override
+    public String getResource() {
+        checkAndLoad();
+        return config.getResource();
+    }
+
+    @Override
+    public Set<String> getNames() {
+        checkAndLoad();
+        return config.getNames();
+    }
+
+    @Override
+    public String getString(String name) {
+        checkAndLoad();
+        return config.getString(name);
+    }
+
+    @Override
+    public String getString(ConfigKey name) {
+        checkAndLoad();
+        return config.getString(name);
+    }
+
+    @Override
+    public String getString(String name, String defaultValue) {
+        checkAndLoad();
+        return config.getString(name, defaultValue);
+    }
+
+    @Override
+    public void setString(String name, String value) {
+        setValues.put(name, value);
+    }
+
+    @Override
+    public void setString(ConfigKey name, String value) {
+        setString(name.getPropertyKey(), value);
+    }
+
+    @Override
+    public String getTrimmed(String name) {
+        checkAndLoad();
+        return config.getTrimmed(name);
+    }
+
+    @Override
+    public String getTrimmed(ConfigKey name) {
+        checkAndLoad();
+        return config.getTrimmed(name);
+    }
+
+    @Override
+    public Boolean getBoolean(String name) {
+        checkAndLoad();
+        return config.getBoolean(name);
+    }
+
+    @Override
+    public Boolean getBoolean(ConfigKey name) {
+        checkAndLoad();
+        return config.getBoolean(name);
+    }
+
+    @Override
+    public Boolean getBoolean(String name, boolean defaultValue) {
+        checkAndLoad();
+        return config.getBoolean(name, defaultValue);
+    }
+
+    @Override
+    public void setBoolean(String name, boolean value) {
+        setString(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setBoolean(ConfigKey name, boolean value) {
+        setString(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public Integer getInt(String name) {
+        checkAndLoad();
+        return config.getInt(name);
+    }
+
+    @Override
+    public Integer getInt(ConfigKey name) {
+        checkAndLoad();
+        return config.getInt(name);
+    }
+
+    @Override
+    public Integer getInt(String name, int defaultValue) {
+        checkAndLoad();
+        return config.getInt(name, defaultValue);
+    }
+
+    @Override
+    public void setInt(String name, int value) {
+        setString(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setInt(ConfigKey name, int value) {
+        setString(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public Long getLong(String name) {
+        checkAndLoad();
+        return config.getLong(name);
+    }
+
+    @Override
+    public Long getLong(ConfigKey name) {
+        checkAndLoad();
+        return config.getLong(name);
+    }
+
+    @Override
+    public Long getLong(String name, long defaultValue) {
+        checkAndLoad();
+        return config.getLong(name, defaultValue);
+    }
+
+    @Override
+    public void setLong(String name, long value) {
+        setString(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setLong(ConfigKey name, long value) {
+        setString(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public Float getFloat(String name) {
+        checkAndLoad();
+        return config.getFloat(name);
+    }
+
+    @Override
+    public Float getFloat(ConfigKey name) {
+        checkAndLoad();
+        return config.getFloat(name);
+    }
+
+    @Override
+    public Float getFloat(String name, float defaultValue) {
+        checkAndLoad();
+        return config.getFloat(name, defaultValue);
+    }
+
+    @Override
+    public void setFloat(String name, float value) {
+        setString(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setFloat(ConfigKey name, float value) {
+        setString(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public List<String> getList(String name) {
+        checkAndLoad();
+        return config.getList(name);
+    }
+
+    @Override
+    public List<String> getList(String name, String[] defaultValue) {
+        checkAndLoad();
+        return config.getList(name, defaultValue);
+    }
+
+    @Override
+    public List<String> getList(ConfigKey name) {
+        checkAndLoad();
+        return config.getList(name);
+    }
+
+    @Override
+    public Config getConfig(String name) {
+        checkAndLoad();
+        return config.getConfig(name);
+    }
+
+    @Override
+    public Config getConfig(ConfigKey name) {
+        checkAndLoad();
+        return config.getConfig(name);
+    }
+
+    @Override
+    public Class<?> getClass(String name) throws ClassNotFoundException {
+        checkAndLoad();
+        return config.getClass(name);
+    }
+
+    @Override
+    public Class<?> getClass(String name, Class<?> defaultValue) throws ClassNotFoundException {
+        checkAndLoad();
+        return config.getClass(name, defaultValue);
+    }
+
+    @Override
+    public Class<?> getClass(ConfigKey name) throws ClassNotFoundException {
+        checkAndLoad();
+        return config.getClass(name);
+    }
+
+    @Override
+    public <T> T getInstance(String name) throws ClassNotFoundException {
+        checkAndLoad();
+        return config.getInstance(name);
+    }
+
+    @Override
+    public <T> T getInstance(ConfigKey name) throws ClassNotFoundException {
+        checkAndLoad();
+        return config.getInstance(name);
+    }
+
+    @Override
+    public <T> T getInstance(String name, Class<T> xface) throws ClassNotFoundException {
+        checkAndLoad();
+        return config.getInstance(name, xface);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/Config.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/Config.java b/kerby-config/src/main/java/org/apache/kerby/config/Config.java
new file mode 100644
index 0000000..2eade15
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/Config.java
@@ -0,0 +1,139 @@
+/**
+ *  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.kerby.config;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Config API to get configuration properties from resources, like XML, Json,
+ * ini, Java Properties and Map. It doesn't support writing back. It allows to
+ * set configuration properties to ease the preparation of a Config.
+ */
+public interface Config {
+    String getResource();
+    Set<String> getNames();
+
+    String getString(String name);
+    String getString(ConfigKey name);
+    String getString(String name, String defaultValue);
+
+    /**
+     * Set a string value for the specified property
+     * @param name
+     * @param value
+     */
+    void setString(String name, String value);
+
+    /**
+     * Set a string value for the specified property
+     * @param name
+     * @param value
+     */
+    void setString(ConfigKey name, String value);
+
+    String getTrimmed(String name);
+    String getTrimmed(ConfigKey name);
+    Boolean getBoolean(String name);
+    Boolean getBoolean(ConfigKey name);
+    Boolean getBoolean(String name, boolean defaultValue);
+
+    /**
+     * Set a boolean value for the specified property
+     * @param name
+     * @param value
+     */
+    void setBoolean(String name, boolean value);
+
+    /**
+     * Set a boolean value for the specified property
+     * @param name
+     * @param value
+     */
+    void setBoolean(ConfigKey name, boolean value);
+
+    Integer getInt(String name);
+    Integer getInt(ConfigKey name);
+    Integer getInt(String name, int defaultValue);
+
+    /**
+     * Set an int value for the specified property
+     * @param name
+     * @param value
+     */
+    void setInt(String name, int value);
+
+    /**
+     * Set an int value for the specified property
+     * @param name
+     * @param value
+     */
+    void setInt(ConfigKey name, int value);
+
+
+    Long getLong(String name);
+    Long getLong(ConfigKey name);
+    Long getLong(String name, long defaultValue);
+
+    /**
+     * Set a long value for the specified property
+     * @param name
+     * @param value
+     */
+    void setLong(String name, long value);
+
+    /**
+     * Set a long value for the specified property
+     * @param name
+     * @param value
+     */
+    void setLong(ConfigKey name, long value);
+
+    Float getFloat(String name);
+    Float getFloat(ConfigKey name);
+    Float getFloat(String name, float defaultValue);
+
+    /**
+     * Set a float value for the specified property
+     * @param name
+     * @param value
+     */
+    void setFloat(String name, float value);
+
+    /**
+     * Set a float value for the specified property
+     * @param name
+     * @param value
+     */
+    void setFloat(ConfigKey name, float value);
+
+    List<String> getList(String name);
+    List<String> getList(String name, String[] defaultValue);
+    List<String> getList(ConfigKey name);
+    Config getConfig(String name);
+    Config getConfig(ConfigKey name);
+
+    Class<?> getClass(String name) throws ClassNotFoundException;
+    Class<?> getClass(String name, Class<?> defaultValue) throws ClassNotFoundException;
+    Class<?> getClass(ConfigKey name) throws ClassNotFoundException;
+    <T> T getInstance(String name) throws ClassNotFoundException;
+    <T> T getInstance(ConfigKey name) throws ClassNotFoundException;
+    <T> T getInstance(String name, Class<T> xface) throws ClassNotFoundException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java b/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java
new file mode 100644
index 0000000..e8a5b50
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java
@@ -0,0 +1,422 @@
+/**
+ *  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.kerby.config;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ConfigImpl implements Config {
+
+    private String resource;
+    private Map<String, ConfigObject> properties;
+    /**
+     * Config resources
+     */
+    private List<Config> configs;
+
+    private Set<String> propNames;
+
+    protected ConfigImpl(String resource) {
+        this.resource = resource;
+        this.properties = new HashMap<String, ConfigObject>();
+        this.configs = new ArrayList<Config>(0);
+    }
+
+    protected void reset() {
+        this.properties.clear();
+        this.configs.clear();
+    }
+
+    @Override
+    public String getResource() {
+        return resource;
+    }
+
+    @Override
+    public Set<String> getNames() {
+        reloadNames();
+        return propNames;
+    }
+
+    @Override
+    public String getString(String name) {
+        String result = null;
+
+        ConfigObject co = properties.get(name);
+        if (co != null) {
+            result = co.getPropertyValue();
+        } else {
+            for (Config config : configs) {
+                result = config.getString(name);
+                if (result != null) {
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public String getString(ConfigKey name) {
+        if (name.getDefaultValue() != null) {
+            return getString(name.getPropertyKey(), (String) name.getDefaultValue());
+        }
+        return getString(name.getPropertyKey());
+    }
+
+    @Override
+    public String getString(String name, String defaultValue) {
+        String result = getString(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    @Override
+    public String getTrimmed(String name) {
+        String result = getString(name);
+        if (null != result) {
+            result = result.trim();
+        }
+        return result;
+    }
+
+    @Override
+    public String getTrimmed(ConfigKey name) {
+        return getTrimmed(name.getPropertyKey());
+    }
+
+    @Override
+    public Integer getInt(String name) {
+        Integer result = null;
+        String value = getTrimmed(name);
+        if (value != null) {
+            result = Integer.valueOf(value);
+        }
+        return result;
+    }
+
+    @Override
+    public Integer getInt(ConfigKey name) {
+        if (name.getDefaultValue() != null) {
+            return getInt(name.getPropertyKey(), (Integer) name.getDefaultValue());
+        }
+        return getInt(name.getPropertyKey());
+    }
+
+    @Override
+    public Integer getInt(String name, int defaultValue) {
+        Integer result = getInt(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    @Override
+    public void setInt(String name, int value) {
+        set(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setInt(ConfigKey name, int value) {
+        set(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public Long getLong(String name) {
+        Long result = null;
+        String value = getTrimmed(name);
+        if (value != null) {
+            result = Long.valueOf(value);
+        }
+        return result;
+    }
+
+    @Override
+    public Long getLong(ConfigKey name) {
+        if (name.getDefaultValue() != null) {
+            return getLong(name.getPropertyKey(), (Long) name.getDefaultValue());
+        }
+        return getLong(name.getPropertyKey());
+    }
+
+    @Override
+    public Long getLong(String name, long defaultValue) {
+        Long result = getLong(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    @Override
+    public void setLong(String name, long value) {
+        set(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setLong(ConfigKey name, long value) {
+        set(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public Float getFloat(String name) {
+        Float result = null;
+        String value = getTrimmed(name);
+        if (value != null) {
+            result = Float.valueOf(value);
+        }
+        return result;
+    }
+
+    @Override
+    public Float getFloat(ConfigKey name) {
+        if (name.getDefaultValue() != null) {
+            return getFloat(name.getPropertyKey(), (Float) name.getDefaultValue());
+        }
+        return getFloat(name.getPropertyKey());
+    }
+
+    @Override
+    public Float getFloat(String name, float defaultValue) {
+        Float result = getFloat(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    @Override
+    public void setFloat(String name, float value) {
+        set(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setFloat(ConfigKey name, float value) {
+        set(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public Boolean getBoolean(String name) {
+        Boolean result = null;
+        String value = getTrimmed(name);
+        if (value != null) {
+            result = Boolean.valueOf(value);
+        }
+        return result;
+    }
+
+    @Override
+    public Boolean getBoolean(ConfigKey name) {
+        if (name.getDefaultValue() != null) {
+            return getBoolean(name.getPropertyKey(),
+                    (Boolean) name.getDefaultValue());
+        }
+        return getBoolean(name.getPropertyKey());
+    }
+
+    @Override
+    public Boolean getBoolean(String name, boolean defaultValue) {
+        Boolean result = getBoolean(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    @Override
+    public void setBoolean(String name, boolean value) {
+        set(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setBoolean(ConfigKey name, boolean value) {
+        set(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public List<String> getList(String name) {
+        List<String> results = null;
+        ConfigObject co = properties.get(name);
+        if (co != null) {
+            results = co.getListValues();
+        } else {
+            for (Config config : configs) {
+                results = config.getList(name);
+                if (results != null) {
+                    break;
+                }
+            }
+        }
+        return results;
+    }
+
+    @Override
+    public List<String> getList(String name, String[] defaultValue) {
+        List<String> results = getList(name);
+        if (results == null) {
+            results = Arrays.asList(defaultValue);
+        }
+        return results;
+    }
+
+    @Override
+    public List<String> getList(ConfigKey name) {
+        if (name.getDefaultValue() != null) {
+            return getList(name.getPropertyKey(), (String[]) name.getDefaultValue());
+        }
+        return getList(name.getPropertyKey());
+    }
+
+    @Override
+    public Config getConfig(String name) {
+        Config result = null;
+        ConfigObject co = properties.get(name);
+        if (co != null) {
+            result = co.getConfigValue();
+        } else {
+            for (Config config : configs) {
+                result = config.getConfig(name);
+                if (result != null) {
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public Config getConfig(ConfigKey name) {
+        return getConfig(name.getPropertyKey());
+    }
+
+    @Override
+    public Class<?> getClass(String name) throws ClassNotFoundException {
+        Class<?> result = null;
+
+        String valueString = getString(name);
+        if (valueString != null) {
+            Class<?> cls = Class.forName(name);
+            result = cls;
+        }
+
+        return result;
+    }
+
+    @Override
+    public Class<?> getClass(String name, Class<?> defaultValue) throws ClassNotFoundException {
+        Class<?> result = getClass(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    @Override
+    public Class<?> getClass(ConfigKey name) throws ClassNotFoundException {
+        if (name.getDefaultValue() != null) {
+            return getClass(name.getPropertyKey(), (Class<?>) name.getDefaultValue());
+        }
+        return getClass(name.getPropertyKey());
+    }
+
+    @Override
+    public <T> T getInstance(String name) throws ClassNotFoundException {
+        return getInstance(name, null);
+    }
+
+    @Override
+    public <T> T getInstance(ConfigKey name) throws ClassNotFoundException {
+        return getInstance(name.getPropertyKey());
+    }
+
+    @Override
+    public <T> T getInstance(String name, Class<T> xface) throws ClassNotFoundException {
+        T result = null;
+
+        Class<?> cls = getClass(name, null);
+        if (xface != null && !xface.isAssignableFrom(cls)) {
+            throw new RuntimeException(cls + " does not implement " + xface);
+        }
+        try {
+            result = (T) cls.newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to create instance with class " + cls.getName());
+        }
+
+        return result;
+    }
+
+
+    @Override
+    public void setString(String name, String value) {
+        set(name, value);
+    }
+
+    @Override
+    public void setString(ConfigKey name, String value) {
+        set(name.getPropertyKey(), value);
+    }
+
+    protected void set(String name, String value) {
+        ConfigObject co = new ConfigObject(value);
+        set(name, co);
+    }
+
+    protected void set(String name, Config value) {
+        ConfigObject co = new ConfigObject(value);
+        set(name, co);
+    }
+
+    protected void set(String name, ConfigObject value) {
+        this.properties.put(name, value);
+    }
+
+    protected void add(Config config) {
+        if (config != null) {
+            if (this == config) {
+                throw new IllegalArgumentException(
+                        "You can not add a config to itself");
+            }
+            this.configs.add(config);
+        }
+    }
+
+    private void reloadNames() {
+        if (propNames != null) {
+            propNames.clear();
+        }
+        propNames = new HashSet<String>(properties.keySet());
+        for (Config config : configs) {
+            propNames.addAll(config.getNames());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/ConfigKey.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/ConfigKey.java b/kerby-config/src/main/java/org/apache/kerby/config/ConfigKey.java
new file mode 100644
index 0000000..4424f22
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/ConfigKey.java
@@ -0,0 +1,25 @@
+/**
+ *  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.kerby.config;
+
+public interface ConfigKey {
+    String getPropertyKey();
+    Object getDefaultValue();
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/ConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/ConfigLoader.java b/kerby-config/src/main/java/org/apache/kerby/config/ConfigLoader.java
new file mode 100644
index 0000000..6282559
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/ConfigLoader.java
@@ -0,0 +1,50 @@
+/**
+ *  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.kerby.config;
+
+public abstract class ConfigLoader {
+    private Resource resource;
+    private ConfigImpl config;
+
+    protected void setResource(Resource resource) {
+        this.resource = resource;
+    }
+
+    protected void setConfig(ConfigImpl config) {
+        this.config = config;
+    }
+
+    public Config load() {
+        if (config == null) {
+            config = new ConfigImpl(resource.getName());
+        }
+        config.reset();
+
+        try {
+            loadConfig(config, resource);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to load " + ConfigLoader.class.getPackage().getName(), e);
+        }
+
+        return this.config;
+    }
+
+    protected abstract void loadConfig(ConfigImpl config, Resource resource) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/ConfigObject.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/ConfigObject.java b/kerby-config/src/main/java/org/apache/kerby/config/ConfigObject.java
new file mode 100644
index 0000000..2be3972
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/ConfigObject.java
@@ -0,0 +1,85 @@
+/**
+ *  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.kerby.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConfigObject {
+    protected static enum ValueType { PROPERTY, LIST, CONFIG };
+
+    private ValueType valueType;
+    private Object value;
+
+    public ConfigObject(String value) {
+        this.value = value;
+        this.valueType = ValueType.PROPERTY;
+    }
+
+    public ConfigObject(String[] values) {
+        List<String> valuesList = new ArrayList<String>();
+        for (String v : values) {
+            valuesList.add(v);
+        }
+
+        this.value = valuesList;
+        this.valueType = ValueType.LIST;
+    }
+
+    public ConfigObject(List<String> values) {
+        if (values != null) {
+            this.value = new ArrayList<String>(values);
+        } else {
+            this.value = new ArrayList<String>();
+        }
+        this.valueType = ValueType.LIST;
+    }
+
+    public ConfigObject(Config value) {
+        this.value = value;
+        this.valueType = ValueType.CONFIG;
+    }
+
+    public String getPropertyValue() {
+        String result = null;
+        if (valueType == ValueType.PROPERTY) {
+            result = (String) value;
+        }
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<String> getListValues() {
+        List<String> results = null;
+        if (valueType == ValueType.LIST && value instanceof List<?>) {
+            results = (List<String>) value;
+        }
+
+        return results;
+    }
+
+    public Config getConfigValue() {
+        Config result = null;
+        if (valueType == ValueType.CONFIG) {
+            result = (Config) value;
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/Configurable.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/Configurable.java b/kerby-config/src/main/java/org/apache/kerby/config/Configurable.java
new file mode 100644
index 0000000..fd41dab
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/Configurable.java
@@ -0,0 +1,30 @@
+/**
+ *  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.kerby.config;
+
+/**
+ * An interface for constructs that desire to be configurable thru the framework.
+ */
+public interface Configurable {
+
+    void setConfig(Config config);
+
+    Config getConfig();
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/Configured.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/Configured.java b/kerby-config/src/main/java/org/apache/kerby/config/Configured.java
new file mode 100644
index 0000000..eadfb54
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/Configured.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.kerby.config;
+
+/**
+ * An abstract for constructs that desire to be configurable.
+ */
+public class Configured implements Configurable {
+    private Config config;
+
+    public Configured() {
+        config = null;
+    }
+
+    public Configured(Config config) {
+        this.config = config;
+    }
+
+    @Override
+    public Config getConfig() {
+        return config;
+    }
+
+    @Override
+    public void setConfig(Config config) {
+        this.config = config;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/IniConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/IniConfigLoader.java b/kerby-config/src/main/java/org/apache/kerby/config/IniConfigLoader.java
new file mode 100644
index 0000000..69e58ab
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/IniConfigLoader.java
@@ -0,0 +1,75 @@
+/**
+ *  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.kerby.config;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+public class IniConfigLoader extends ConfigLoader {
+    private static final String COMMENT_SYMBOL = "#";
+
+    private ConfigImpl rootConfig;
+    private ConfigImpl currentConfig;
+
+    /**
+     *  Load configs form the INI configuration format file.
+     */
+    @Override
+    protected void loadConfig(ConfigImpl config, Resource resource) throws IOException {
+        rootConfig = config;
+        currentConfig = config;
+
+        InputStream is = (InputStream) resource.getResource();
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
+
+        String line;
+        while ((line = reader.readLine()) != null) {
+            parseLine(line);
+        }
+        reader.close();
+    }
+
+    private void parseLine(String line) {
+        if (line == null) {
+            return;
+        }
+        
+        line = line.trim();
+
+        if (line.startsWith(COMMENT_SYMBOL)) {
+            return;
+        }
+
+        if (line.matches("\\[.*\\]")) {
+            String subConfigName = line.replaceFirst("\\[(.*)\\]", "$1");
+            ConfigImpl subConfig = new ConfigImpl(subConfigName);
+            rootConfig.set(subConfigName, subConfig);
+            currentConfig = subConfig;
+        } else if (line.matches(".*=.*")) {
+            int i = line.indexOf('=');
+            String name = line.substring(0, i).trim();
+            String value = line.substring(i + 1).trim();
+            currentConfig.set(name, value);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/JsonConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/JsonConfigLoader.java b/kerby-config/src/main/java/org/apache/kerby/config/JsonConfigLoader.java
new file mode 100644
index 0000000..5a51175
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/JsonConfigLoader.java
@@ -0,0 +1,27 @@
+/**
+ *  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.kerby.config;
+
+public class JsonConfigLoader extends ConfigLoader {
+    @Override
+    protected void loadConfig(ConfigImpl config, Resource resource) {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/MapConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/MapConfigLoader.java b/kerby-config/src/main/java/org/apache/kerby/config/MapConfigLoader.java
new file mode 100644
index 0000000..9a212c3
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/MapConfigLoader.java
@@ -0,0 +1,33 @@
+/**
+ *  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.kerby.config;
+
+import java.util.Map;
+
+public class MapConfigLoader extends ConfigLoader {
+    @Override
+    protected void loadConfig(ConfigImpl config, Resource resource) {
+        @SuppressWarnings("unchecked")
+        Map<String, String> mapConfig = (Map<String, String>) resource.getResource();
+        for (Map.Entry<String, String> entry : mapConfig.entrySet()) {
+            config.set(entry.getKey(), entry.getValue());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/PropertiesConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/PropertiesConfigLoader.java b/kerby-config/src/main/java/org/apache/kerby/config/PropertiesConfigLoader.java
new file mode 100644
index 0000000..58a04b9
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/PropertiesConfigLoader.java
@@ -0,0 +1,42 @@
+/**
+ *  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.kerby.config;
+
+import java.util.Properties;
+
+public class PropertiesConfigLoader extends ConfigLoader {
+
+    @Override
+    protected void loadConfig(ConfigImpl config, Resource resource) throws Exception {
+        Properties propConfig = (Properties) resource.getResource();
+        loadConfig(config, propConfig);
+    }
+
+    protected void loadConfig(ConfigImpl config, Properties propConfig) {
+        for (Object key : propConfig.keySet()) {
+            if (key instanceof String) {
+                String value = propConfig.getProperty((String) key);
+                if (value != null) {
+                    config.set((String) key, value);
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/PropertiesFileConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/PropertiesFileConfigLoader.java b/kerby-config/src/main/java/org/apache/kerby/config/PropertiesFileConfigLoader.java
new file mode 100644
index 0000000..ba8660f
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/PropertiesFileConfigLoader.java
@@ -0,0 +1,33 @@
+/**
+ *  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.kerby.config;
+
+import java.io.InputStream;
+import java.util.Properties;
+
+public class PropertiesFileConfigLoader extends PropertiesConfigLoader {
+
+    @Override
+    protected void loadConfig(ConfigImpl config, Resource resource) throws Exception {
+        Properties propConfig = new Properties();
+        propConfig.load((InputStream) resource.getResource());
+        loadConfig(config, propConfig);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/Resource.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/Resource.java b/kerby-config/src/main/java/org/apache/kerby/config/Resource.java
new file mode 100644
index 0000000..9988ffa
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/Resource.java
@@ -0,0 +1,121 @@
+/**
+ *  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.kerby.config;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+import java.util.Properties;
+
+public final class Resource {
+    public static enum Format {
+        XML_FILE(XmlConfigLoader.class),
+        INI_FILE(IniConfigLoader.class),
+        JSON_FILE(JsonConfigLoader.class),
+        PROPERTIES_FILE(PropertiesFileConfigLoader.class),
+        MAP(MapConfigLoader.class),
+        PROPERTIES(PropertiesConfigLoader.class);
+
+        private Class<? extends ConfigLoader> loaderClass;
+
+        private Format(Class<? extends ConfigLoader> loaderClass) {
+            this.loaderClass = loaderClass;
+        }
+
+        public Class<? extends ConfigLoader> getLoaderClass() {
+            return loaderClass;
+        }
+    }
+
+    private String name;
+    private Object resource;
+    private Format format;
+
+    public static Resource createXmlResource(File xmlFile) throws IOException {
+        return new Resource(xmlFile.getName(), xmlFile, Format.XML_FILE);
+    }
+
+    public static Resource createIniResource(File iniFile) throws IOException {
+        return new Resource(iniFile.getName(), iniFile, Format.INI_FILE);
+    }
+
+    public static Resource createJsonResource(File jsonFile) throws IOException {
+        return new Resource(jsonFile.getName(), jsonFile, Format.JSON_FILE);
+    }
+
+    public static Resource createXmlResource(URL xmlUrl) throws IOException {
+        return new Resource(xmlUrl, Format.XML_FILE);
+    }
+
+    public static Resource createIniResource(URL iniUrl) throws IOException {
+        return new Resource(iniUrl, Format.INI_FILE);
+    }
+
+    public static Resource createJsonResource(URL jsonUrl) throws IOException {
+        return new Resource(jsonUrl, Format.JSON_FILE);
+    }
+
+    public static Resource createMapResource(Map<String, String> mapConfig) {
+        return new Resource("mapConfig", mapConfig, Format.MAP);
+    }
+
+    public static Resource createPropertiesFileResource(File propFile) throws IOException {
+        return new Resource(propFile.getName(), propFile, Format.PROPERTIES_FILE);
+    }
+
+    public static Resource createPropertiesResource(Properties propertiesConfig) {
+        return new Resource("propConfig", propertiesConfig, Format.PROPERTIES);
+    }
+
+    private Resource(String name, File resourceFile, Format format) throws FileNotFoundException {
+        this.name = name;
+        this.resource = new FileInputStream(resourceFile);
+        this.format = format;
+    }
+
+    private Resource(URL resourceUrl, Format format) throws IOException {
+        this(resourceUrl.toString(), resourceUrl.openStream(), format);
+    }
+
+    private Resource(String name, Object resourceStream, Format format) {
+        this.name = name;
+        this.resource = resourceStream;
+        this.format = format;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Object getResource() {
+        return resource;
+    }
+
+    public Format getFormat() {
+        return format;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java b/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java
new file mode 100644
index 0000000..2fd2f9c
--- /dev/null
+++ b/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java
@@ -0,0 +1,153 @@
+/**
+ *  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.kerby.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class XmlConfigLoader extends ConfigLoader {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Config.class);
+
+    @Override
+    protected void loadConfig(ConfigImpl config, Resource resource) throws Exception {
+        Element doc = loadResourceDocument(resource);
+        loadConfig(config, doc);
+    }
+
+    private Element loadResourceDocument(Resource resource) throws Exception {
+        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+
+        docBuilderFactory.setIgnoringComments(true);
+        docBuilderFactory.setNamespaceAware(true);
+        try {
+            docBuilderFactory.setXIncludeAware(true);
+        } catch (UnsupportedOperationException e) {
+            LOGGER.error("Failed to set setXIncludeAware(true) for parser", e);
+        }
+        DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
+        InputStream is = (InputStream) resource.getResource();
+        Document doc = null;
+        try {
+            doc = builder.parse(is);
+        } finally {
+            is.close();
+        }
+
+        Element root = doc.getDocumentElement();
+        validateConfig(root);
+
+        return root;
+    }
+
+    private boolean validateConfig(Element root) {
+        boolean valid = false;
+
+        if ("config".equals(root.getTagName())) {
+            valid = true;
+        } else {
+            LOGGER.error("bad conf element: top-level element not <configuration>");
+        }
+
+        return valid;
+    }
+
+    private void loadConfig(ConfigImpl config, Element element) {
+        NodeList props = element.getChildNodes();
+        for (int i = 0; i < props.getLength(); i++) {
+            Node subNode = props.item(i);
+            if (!(subNode instanceof Element)) {
+                continue;
+            }
+
+            Element prop = (Element) subNode;
+            String name = getElementName(prop);
+            if (name == null) {
+                continue;
+            }
+
+            ConfigObject value = null;
+            String tagName = prop.getTagName();
+            if ("property".equals(tagName) && prop.hasChildNodes()) {
+                value = loadProperty(prop);
+            } else if ("config".equals(tagName) && prop.hasChildNodes()) {
+                ConfigImpl cfg = new ConfigImpl(name);
+                loadConfig(cfg, prop);
+                value = new ConfigObject(cfg);
+            }
+                config.set(name, value);
+        }
+    }
+
+    private static ConfigObject loadProperty(Element ele) {
+        if (ele.getFirstChild() instanceof Text) {
+            String value = ((Text) ele.getFirstChild()).getData();
+            return new ConfigObject(value);
+        }
+
+        NodeList nodes = ele.getChildNodes();
+        List<String> values = new ArrayList<String>(nodes.getLength());
+        for (int i = 0; i < nodes.getLength(); i++) {
+            String value = null;
+            Node valueNode = nodes.item(i);
+            if (!(valueNode instanceof Element)) {
+                continue;
+            }
+
+            Element valueEle = (Element) valueNode;
+            if ("value".equals(valueEle.getTagName()) && valueEle.hasChildNodes()) {
+                value = ((Text) valueEle.getFirstChild()).getData();
+            }
+
+            if (value != null) {
+                values.add(value);
+            }
+        }
+        return new ConfigObject(values);
+    }
+
+    private static String getElementName(Element ele) {
+        NamedNodeMap nnm = ele.getAttributes();
+        for (int i = 0; i < nnm.getLength(); ++i) {
+            Node node = nnm.item(i);
+            if (!(node instanceof Attr)) {
+                continue;
+            }
+            Attr attr = (Attr) node;
+
+            if ("name".equals(attr.getName())) {
+                return attr.getValue();
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java b/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java
new file mode 100644
index 0000000..185fe3f
--- /dev/null
+++ b/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java
@@ -0,0 +1,131 @@
+/**
+ *  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.kerby.config;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The test is base on the Conf level.
+ * We hope users use the Conf object only, and don't need to care about its internal implementation.
+ */
+public class ConfTest {
+
+    @Test
+    public void testMapConfig() {
+        String strProp = "hello";
+        Integer intProp = 123456;
+        Boolean boolProp = true;
+        Map<String, String> mapConfig = new HashMap<String, String>();
+        mapConfig.put("strProp", strProp);
+        mapConfig.put("intProp", String.valueOf(intProp));
+        mapConfig.put("boolProp", String.valueOf(boolProp));
+
+        Conf conf = new Conf();
+        conf.addMapConfig(mapConfig);
+        assertThat(conf.getString("strProp")).isEqualTo(strProp);
+        assertThat(conf.getInt("intProp")).isEqualTo(intProp);
+        assertThat(conf.getBoolean("boolProp")).isEqualTo(boolProp);
+    }
+
+    @Test
+    public void testPropertiesConfig() {
+        String strProp = "hello";
+        Integer intProp = 123456;
+        Boolean boolProp = true;
+        Properties properties = new Properties();
+        properties.setProperty("strProp", strProp);
+        properties.setProperty("intProp", String.valueOf(intProp));
+        properties.setProperty("boolProp", String.valueOf(boolProp));
+
+        Conf conf = new Conf();
+        conf.addPropertiesConfig(properties);
+        assertThat(conf.getString("strProp")).isEqualTo(strProp);
+        assertThat(conf.getInt("intProp")).isEqualTo(intProp);
+        assertThat(conf.getBoolean("boolProp")).isEqualTo(boolProp);
+    }
+
+    /**
+     * Test for whether can get right value form the conf which contains many config resources.
+     */
+    @Test
+    public void testMixedConfig() {
+        String mapStrProp = "hello map";
+        Integer intProp = 123456;
+        Map<String, String> mapConfig = new HashMap<String, String>();
+        mapConfig.put("mapStrProp", mapStrProp);
+        mapConfig.put("intProp", String.valueOf(intProp));
+
+        String propertiesStrProp = "hello properties";
+        Boolean boolProp = true;
+        Properties properties = new Properties();
+        properties.setProperty("propertiesStrProp", propertiesStrProp);
+        properties.setProperty("boolProp", String.valueOf(boolProp));
+
+        Conf conf = new Conf();
+        conf.addMapConfig(mapConfig);
+        conf.addPropertiesConfig(properties);
+        assertThat(conf.getConfig("mapConfig")).isNull();
+        assertThat(conf.getString("mapStrProp")).isEqualTo(mapStrProp);
+        assertThat(conf.getString("propertiesStrProp")).isEqualTo(propertiesStrProp);
+        assertThat(conf.getInt("intProp")).isEqualTo(intProp);
+        assertThat(conf.getBoolean("boolProp")).isEqualTo(boolProp);
+    }
+
+    static enum TestConfKey implements ConfigKey {
+        ADDRESS("127.0.0.1"),
+        PORT(8015),
+        ENABLE(false);
+
+        private Object defaultValue;
+
+        private TestConfKey(Object defaultValue) {
+            this.defaultValue = defaultValue;
+        }
+
+        @Override
+        public String getPropertyKey() {
+            return name().toLowerCase();
+        }
+
+        @Override
+        public Object getDefaultValue() {
+            return this.defaultValue;
+        }
+    }
+
+    @Test
+    public void testConfKey() {
+        Conf conf = new Conf();
+        assertThat(conf.getString(TestConfKey.ADDRESS)).isEqualTo(TestConfKey.ADDRESS.getDefaultValue());
+        Map<String, String> mapConfig = new HashMap<String, String>();
+        String myAddress = "www.google.com";
+        mapConfig.put(TestConfKey.ADDRESS.getPropertyKey(), myAddress);
+        conf.addMapConfig(mapConfig);
+        assertThat(conf.getString(TestConfKey.ADDRESS)).isEqualTo(myAddress);
+        assertThat(conf.getInt(TestConfKey.PORT)).isEqualTo(TestConfKey.PORT.getDefaultValue());
+        assertThat(conf.getBoolean(TestConfKey.ENABLE)).isEqualTo(TestConfKey.ENABLE.getDefaultValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java b/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java
new file mode 100644
index 0000000..f8c927f
--- /dev/null
+++ b/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java
@@ -0,0 +1,63 @@
+/**
+ *  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.kerby.config;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The test is on ConfigImpl level.
+ * ConfigImpl is the internal implementation of Conf, only visual by developers.
+ */
+public class ConfigImplTest {
+
+    /**
+     * Test for section config support.
+     */
+    @Test
+    public void testSectionConfig() {
+        ConfigImpl rootConfig = new ConfigImpl(null);
+        rootConfig.set("globalConfig", "true");
+
+        ConfigImpl sectionA = new ConfigImpl("libdefaults");
+        rootConfig.set("libdefaults", sectionA);
+        sectionA.set("default_realm", "EXAMPLE.COM");
+        sectionA.set("forwardable", "true");
+        sectionA.set("dns_lookup_realm", "false");
+
+        ConfigImpl sectionB = new ConfigImpl("logging");
+        rootConfig.set("logging", sectionB);
+        sectionB.set("kdc", "FILE:/var/log/krb5kdc.log");
+
+        assertThat(rootConfig.getString("globalConfig")).isEqualTo("true");
+        assertThat(rootConfig.getString("default_realm")).isNull(); //section config should not get the global value
+
+        Config subA = rootConfig.getConfig("libdefaults");
+        assertThat(subA.getString("default_realm")).isEqualTo("EXAMPLE.COM");
+        assertThat(subA.getString("globalConfig")).isNull();
+        assertThat(subA.getString("kdc")).isNull();
+
+        Config subB = rootConfig.getConfig("logging");
+        assertThat(subB.getString("kdc")).isEqualTo("FILE:/var/log/krb5kdc.log");
+        assertThat(subB.getString("globalConfig")).isNull();
+        assertThat(subB.getBoolean("forwardable")).isNull();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java
----------------------------------------------------------------------
diff --git a/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java b/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java
new file mode 100644
index 0000000..4198560
--- /dev/null
+++ b/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java
@@ -0,0 +1,88 @@
+/**
+ *  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.kerby.config;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class IniConfigTest {
+
+    private static final File TEST_DIR = new File(System.getProperty("test.dir", "target"));
+    private static final File TEST_FILE = new File(TEST_DIR, "test-ini-config");
+
+    @Before
+    public void setUp() throws IOException {
+        if (TEST_FILE.exists()) {
+            TEST_FILE.delete();
+        }
+        buildFile();
+    }
+
+    /**
+     * Build a INI format configuration file.
+     */
+    private void buildFile() throws IOException {
+        PrintWriter out = new PrintWriter(new FileWriter(TEST_FILE));
+        out.println("#note = notenote");
+        out.println("default = FILE:/var/log/krb5libs.log");
+        out.println("kdc = FILE:/var/log/krb5kdc.log");
+        out.println("admin_server = FILE:/var/log/kadmind.log");
+        out.println("[libdefaults]");
+        out.println("default_realm = EXAMPLE.COM");
+        out.println("dns_lookup_realm = false");
+        out.println("dns_lookup_kdc = false");
+        out.println("ticket_lifetime = 24h");
+        out.println("renew_lifetime = 7d");
+        out.println("forwardable = true");
+        out.println("[lib1]");
+        out.println("default_realm = EXAMPLE.COM1");
+        out.println("dns_lookup_realm = true");
+        out.close();
+    }
+
+    @Test
+    public void testIniConfig() throws IOException {
+        Conf conf = new Conf();
+        conf.addIniConfig(TEST_FILE);
+
+        assertThat(conf.getString("default")).isEqualTo("FILE:/var/log/krb5libs.log");
+        assertThat(conf.getString("#note")).isNull(); //Comments should be ignored when loading.
+
+        Config config = conf.getConfig("libdefaults");
+        assertThat(config.getBoolean("dns_lookup_realm")).isFalse();
+        assertThat(config.getBoolean("forwardable")).isTrue();
+
+        Config config1 = conf.getConfig("lib1");
+        assertThat(config1.getBoolean("dns_lookup_realm")).isTrue();
+    }
+
+    @After
+    public void tearDown() {
+        TEST_FILE.delete();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-util/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-util/pom.xml b/kerby-util/pom.xml
new file mode 100644
index 0000000..b3ccb27
--- /dev/null
+++ b/kerby-util/pom.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.kerby</groupId>
+    <artifactId>lib</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>kerby-util</artifactId>
+
+  <name>Kerby Util</name>
+  <description>Kerby common util, without any 3rd party dependency</description>
+
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-util/src/main/java/org/apache/kerby/KOption.java
----------------------------------------------------------------------
diff --git a/kerby-util/src/main/java/org/apache/kerby/KOption.java b/kerby-util/src/main/java/org/apache/kerby/KOption.java
new file mode 100644
index 0000000..3809232
--- /dev/null
+++ b/kerby-util/src/main/java/org/apache/kerby/KOption.java
@@ -0,0 +1,41 @@
+/**
+ *  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.kerby;
+
+public interface KOption {
+
+    void setType(KOptionType type);
+
+    KOptionType getType();
+
+    String getOptionName();
+
+    void setName(String name);
+
+    String getName();
+
+    void setDescription(String description);
+
+    String getDescription();
+
+    void setValue(Object value);
+
+    Object getValue();
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-util/src/main/java/org/apache/kerby/KOptionType.java
----------------------------------------------------------------------
diff --git a/kerby-util/src/main/java/org/apache/kerby/KOptionType.java b/kerby-util/src/main/java/org/apache/kerby/KOptionType.java
new file mode 100644
index 0000000..d7e53b3
--- /dev/null
+++ b/kerby-util/src/main/java/org/apache/kerby/KOptionType.java
@@ -0,0 +1,35 @@
+/**
+ *  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.kerby;
+
+/**
+ * Option type.
+ */
+public enum KOptionType {
+    NONE,
+    NOV, // no value, a control flag
+    STR, // string value
+    INT, // integer value
+    BOOL, // boolean value
+    FILE, // file path value
+    DIR, // dir path value
+    OBJ,  // arbitrary object
+    DATE // date value
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6bb66073/kerby-util/src/main/java/org/apache/kerby/KOptions.java
----------------------------------------------------------------------
diff --git a/kerby-util/src/main/java/org/apache/kerby/KOptions.java b/kerby-util/src/main/java/org/apache/kerby/KOptions.java
new file mode 100644
index 0000000..0094610
--- /dev/null
+++ b/kerby-util/src/main/java/org/apache/kerby/KOptions.java
@@ -0,0 +1,188 @@
+/**
+ *  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.kerby;
+
+import java.io.File;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A KOption container.
+ */
+public class KOptions {
+
+    private final Map<KOption, KOption> options =
+            new HashMap<KOption, KOption>();
+
+    /**
+     * Parse string value according to kopt type.
+     * @param kopt
+     * @param strValue
+     * @return true when successful, false otherwise
+     */
+    public static boolean parseSetValue(KOption kopt, String strValue) {
+        KOptionType kt = kopt.getType();
+        if (kt == KOptionType.NOV) {
+            return true; // no need of a value
+        }
+        if (strValue == null || strValue.isEmpty()) {
+            return false;
+        }
+
+        if (kt == KOptionType.FILE) {
+            // May check file sanity
+            kopt.setValue(new File(strValue));
+        } else if (kt == KOptionType.DIR) {
+            File dir = new File(strValue);
+            if (!dir.exists()) {
+                throw new IllegalArgumentException("Invalid dir:" + strValue);
+            }
+            kopt.setValue(dir);
+        } else if (kt == KOptionType.INT) {
+            try {
+                Integer num = Integer.valueOf(strValue);
+                kopt.setValue(num);
+            } catch (NumberFormatException nfe) {
+                throw new IllegalArgumentException("Invalid integer:" + strValue);
+            }
+        } else if (kt == KOptionType.STR) {
+            kopt.setValue(strValue);
+        } else if (kt == KOptionType.DATE) {
+            DateFormat df = new SimpleDateFormat("dd/MM/yy:HH:mm:ss");
+            Date date = null;
+            try {
+                date = df.parse(strValue);
+                kopt.setValue(date);
+            } catch (ParseException e) {
+                throw new IllegalArgumentException("Fail to parse the date: " + strValue);
+            }
+        } else if (kt == KOptionType.BOOL) {
+            kopt.setValue(Boolean.valueOf(strValue));
+        } else {
+            throw new IllegalArgumentException("Not recognised option:" + strValue);
+        }
+        return true;
+    }
+
+    public void add(KOption option) {
+        if (option != null) {
+            options.put(option, option);
+        }
+    }
+
+    public void add(KOption option, Object optionValue) {
+        if (option != null) {
+            option.setValue(optionValue);
+            add(option);
+        }
+    }
+
+    public boolean contains(KOption option) {
+        return options.containsKey(option);
+    }
+
+    public List<KOption> getOptions() {
+        return new ArrayList<>(options.keySet());
+    }
+
+    public KOption getOption(KOption option) {
+        if (!options.containsKey(option)) {
+            return null;
+        }
+
+        return options.get(option);
+    }
+
+    public Object getOptionValue(KOption option) {
+        if (!contains(option)) {
+            return null;
+        }
+        return options.get(option).getValue();
+    }
+
+    public String getStringOption(KOption option) {
+        Object value = getOptionValue(option);
+        if (value instanceof String) {
+            return (String) value;
+        }
+        return null;
+    }
+
+    public boolean getBooleanOption(KOption option, Boolean defaultValue) {
+        Object value = getOptionValue(option);
+        if (value instanceof String) {
+            String strVal = (String) value;
+            if (strVal.equalsIgnoreCase("true")
+                    || strVal.equalsIgnoreCase("yes")
+                    || strVal.equals("1")) {
+                return true;
+            } else if (strVal.equalsIgnoreCase("false")
+                    || strVal.equalsIgnoreCase("no")
+                    || strVal.equals("0")) {
+                return false;
+            }
+        } else if (value instanceof Boolean) {
+            return (Boolean) value;
+        }
+
+        return defaultValue;
+    }
+
+    public int getIntegerOption(KOption option) {
+        Object value = getOptionValue(option);
+        if (value instanceof String) {
+            String strVal = (String) value;
+            return Integer.parseInt(strVal);
+        } else if (value instanceof Integer) {
+            return ((Integer) value).intValue();
+        }
+        return -1;
+    }
+
+    public File getFileOption(KOption option) {
+        Object value = getOptionValue(option);
+        if (value instanceof File) {
+            return (File) value;
+        }
+        return null;
+    }
+
+    public File getDirOption(KOption option) {
+        Object value = getOptionValue(option);
+        if (value instanceof File) {
+            return (File) value;
+        }
+        return null;
+    }
+
+    public Date getDateOption(KOption option) {
+        Object value = getOptionValue(option);
+        if (value instanceof Date) {
+            return (Date) value;
+        }
+        return null;
+    }
+}