directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dran...@apache.org
Subject [06/13] directory-kerby git commit: Consolidated facility and support modules into kerby-common
Date Sat, 16 Jan 2016 09:38:34 GMT
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1IntegerTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1IntegerTest.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1IntegerTest.java
new file mode 100644
index 0000000..04bb11f
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1IntegerTest.java
@@ -0,0 +1,72 @@
+/**
+ *  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.asn1;
+
+import org.apache.kerby.asn1.type.Asn1Integer;
+import org.apache.kerby.asn1.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class Asn1IntegerTest {
+
+    @Test
+    public void testEncoding() throws IOException {
+        testEncodingWith(0, "0x02 01 00");
+        testEncodingWith(1, "0x02 01 01");
+        testEncodingWith(2, "0x02 01 02");
+        testEncodingWith(127, "0x02 01 7F");
+        testEncodingWith(128, "0x02 02 00 80");
+        testEncodingWith(-1, "0x02 01 FF");
+        testEncodingWith(-128, "0x02 01 80");
+        testEncodingWith(-32768, "0x02 02 80 00");
+        testEncodingWith(1234567890, "0x02 04 49 96 02 D2");
+    }
+
+    private void testEncodingWith(int value, String expectedEncoding) throws IOException {
+        byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+        Asn1Integer aValue = new Asn1Integer(value);
+        aValue.useDER();
+        byte[] encodingBytes = aValue.encode();
+        assertThat(encodingBytes).isEqualTo(expected);
+    }
+
+    @Test
+    public void testDecoding() throws IOException {
+        testDecodingWith(0, "0x02 01 00");
+        testDecodingWith(1, "0x02 01 01");
+        testDecodingWith(2, "0x02 01 02");
+        testDecodingWith(127, "0x02 01 7F");
+        testDecodingWith(128, "0x02 02 00 80");
+        testDecodingWith(-1, "0x02 01 FF");
+        testDecodingWith(-128, "0x02 01 80");
+        testDecodingWith(-32768, "0x02 02 80 00");
+        testDecodingWith(1234567890, "0x02 04 49 96 02 D2");
+    }
+
+    private void testDecodingWith(int expectedValue, String content) throws IOException {
+        Asn1Integer decoded = new Asn1Integer();
+        decoded.useDER();
+        decoded.decode(HexUtil.hex2bytesFriendly(content));
+        assertThat(decoded.getValue().intValue()).isEqualTo(expectedValue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1ObjectIdentifierTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1ObjectIdentifierTest.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1ObjectIdentifierTest.java
new file mode 100644
index 0000000..9106dc7
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1ObjectIdentifierTest.java
@@ -0,0 +1,66 @@
+/**
+ *  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.asn1;
+
+import org.apache.kerby.asn1.type.Asn1ObjectIdentifier;
+import org.apache.kerby.asn1.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class Asn1ObjectIdentifierTest {
+
+    @Test
+    public void testEncoding() throws Exception {
+        /**
+         * Cryptography for Developers -> ASN.1 UTCTIME Type
+         * Applying this to the MD5 OID, we first transform the dotted decimal form into the
+         * array of words.Thus, 1.2.840.113549.2.5 becomes {42, 840, 113549, 2, 5}, and then further
+         * 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 36split into seven-bit digits with the proper most significant bits as
+         * {{0x2A}, {0x86, 0x48},{0x86, 0xF7, 0x0D}, {0x02}, {0x05}}.Therefore, the full encoding for MD5 is 0x06 08 2A
+         * 86 48 86 F7 0D 02 05.
+         */
+        testEncodingWith("1.2.840.113549.2.5",
+                "0x06 08 2A 86 48 86 F7 0D 02 05");
+    }
+
+    private void testEncodingWith(String oid, String expectedEncoding) throws IOException {
+        byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+        Asn1ObjectIdentifier aValue = new Asn1ObjectIdentifier(oid);
+        aValue.useDER();
+        byte[] encodingBytes = aValue.encode();
+        assertThat(encodingBytes).isEqualTo(expected);
+    }
+
+    @Test
+    public void testDecoding() throws Exception {
+        testDecodingWith("1.2.840.113549.2.5",
+                "0x06 08 2A 86 48 86 F7 0D 02 05");
+    }
+
+    private void testDecodingWith(String expectedValue, String content) throws IOException {
+        Asn1ObjectIdentifier decoded = new Asn1ObjectIdentifier();
+        decoded.useDER();
+        decoded.decode(HexUtil.hex2bytesFriendly(content));
+        assertThat(decoded.getValue()).isEqualTo(expectedValue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1UtcTimeTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1UtcTimeTest.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1UtcTimeTest.java
new file mode 100644
index 0000000..271abff
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/Asn1UtcTimeTest.java
@@ -0,0 +1,72 @@
+/**
+ *  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.asn1;
+
+import org.apache.kerby.asn1.type.Asn1UtcTime;
+import org.apache.kerby.asn1.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class Asn1UtcTimeTest {
+
+    @Test
+    public void testEncoding() throws Exception {
+        /**
+         * Cryptography for Developers -> ASN.1 UTCTIME Type
+         * the encoding of July 4, 2003 at 11:33 and 28 seconds would be
+         “030704113328Z” and be encoded as 0x17 0D 30 33 30 37 30 34 31 31 33 33 32 38 5A.
+         */
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(new SimpleTimeZone(0, "Z"));
+        String dateInString = "2003-07-04 11:33:28";
+        Date date = sdf.parse(dateInString);
+        testEncodingWith(date, "0x17 0D 30 33 30 37 30 34 31 31 33 33 32 38 5A");
+    }
+
+    private void testEncodingWith(Date value, String expectedEncoding) throws IOException {
+        byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+        Asn1UtcTime aValue = new Asn1UtcTime(value);
+        aValue.useDER();
+        byte[] encodingBytes = aValue.encode();
+        assertThat(encodingBytes).isEqualTo(expected);
+    }
+
+    @Test
+    public void testDecoding() throws Exception {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String dateInString = "2003-07-04 11:33:28";
+        sdf.setTimeZone(new SimpleTimeZone(0, "Z"));
+        Date date = sdf.parse(dateInString);
+        testDecodingWith(date, "0x17 0D 30 33 30 37 30 34 31 31 33 33 32 38 5A");
+    }
+
+    private void testDecodingWith(Date expectedValue, String content) throws IOException {
+        Asn1UtcTime decoded = new Asn1UtcTime();
+        decoded.useDER();
+        decoded.decode(HexUtil.hex2bytesFriendly(content));
+        assertThat(decoded.getValue()).isEqualTo(expectedValue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/DataTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/DataTest.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/DataTest.java
new file mode 100644
index 0000000..4e5c0a5
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/DataTest.java
@@ -0,0 +1,127 @@
+/**
+ *  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.asn1;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+public class DataTest {
+
+    public static PersonnelRecord createSamplePersonnel() {
+        PersonnelRecord pr = new PersonnelRecord();
+
+        pr.setName(new PersonnelRecord.Name("John", "P", "Smith"));
+
+        pr.setTitle("Director");
+
+        pr.setEmployeeNumber(new PersonnelRecord.EmployeeNumber(51));
+
+        pr.setDateOfHire(new PersonnelRecord.Date("19710917"));
+
+        pr.setNameOfSpouse(new PersonnelRecord.Name("Mary", "T", "Smith"));
+
+        PersonnelRecord.ChildInformation child1 = new PersonnelRecord.ChildInformation();
+        child1.setName(new PersonnelRecord.Name("Ralph", "T", "Smith"));
+        child1.setDateOfBirth(new PersonnelRecord.Date("19571111"));
+
+        PersonnelRecord.ChildInformation child2 = new PersonnelRecord.ChildInformation();
+        child2.setName(new PersonnelRecord.Name("Susan", "B", "Jones"));
+        child2.setDateOfBirth(new PersonnelRecord.Date("19590717"));
+
+        pr.setChildren(new PersonnelRecord.Children(child1, child2));
+
+        return pr;
+    }
+
+    public static byte[] createSammplePersonnelEncodingData() {
+        class BufferOutput {
+            ByteBuffer buffer;
+
+            void put(byte ... bytes) {
+                buffer.put(bytes);
+            }
+
+            void put(String s) {
+                byte[] bytes = s.getBytes(StandardCharsets.US_ASCII);
+                buffer.put(bytes);
+            }
+
+            public byte[] output() {
+                int len = (int) 0x85 + 3;
+                buffer = ByteBuffer.allocate(len);
+
+                // personnel record
+                put((byte) 0x60, (byte) 0x81, (byte) 0x85);
+
+                // -name
+                put((byte) 0x61, (byte) 0x10);
+                put((byte) 0x1A, (byte) 0x04); put("John");
+                put((byte) 0x1A, (byte) 0x01); put("P");
+                put((byte) 0x1A, (byte) 0x05); put("Smith");
+
+                //-title
+                put((byte) 0xA0, (byte) 0x0A);
+                put((byte) 0x1A, (byte) 0x08); put("Director");
+
+                //-employee number
+                put((byte) 0x42, (byte) 0x01, (byte) 0x33);
+
+                //-date of hire
+                put((byte) 0xA1, (byte) 0x0A);
+                put((byte) 0x43, (byte) 0x08); put("19710917");
+
+                //-spouse
+                put((byte) 0xA2, (byte) 0x12);
+                put((byte) 0x61, (byte) 0x10);
+                put((byte) 0x1A, (byte) 0x04); put("Mary");
+                put((byte) 0x1A, (byte) 0x01); put("T");
+                put((byte) 0x1A, (byte) 0x05); put("Smith");
+
+                //-children
+                put((byte) 0xA3, (byte) 0x42);
+                //--child 1
+                put((byte) 0x31, (byte) 0x1F);
+                //---name
+                put((byte) 0x61, (byte) 0x11);
+                put((byte) 0x1A, (byte) 0x05); put("Ralph");
+                put((byte) 0x1A, (byte) 0x01); put("T");
+                put((byte) 0x1A, (byte) 0x05); put("Smith");
+                //-date of birth
+                put((byte) 0xA0, (byte) 0x0A);
+                put((byte) 0x43, (byte) 0x08); put("19571111");
+                //--child 2
+                put((byte) 0x31, (byte) 0x1F);
+                //---name
+                put((byte) 0x61, (byte) 0x11);
+                put((byte) 0x1A, (byte) 0x05); put("Susan");
+                put((byte) 0x1A, (byte) 0x01); put("B");
+                put((byte) 0x1A, (byte) 0x05); put("Jones");
+                //-date of birth
+                put((byte) 0xA0, (byte) 0x0A);
+                put((byte) 0x43, (byte) 0x08); put("19590717");
+
+                return buffer.array();
+            }
+        }
+
+        BufferOutput buffer = new BufferOutput();
+        return buffer.output();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecord.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecord.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecord.java
new file mode 100644
index 0000000..f5c287a
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecord.java
@@ -0,0 +1,248 @@
+/**
+ *  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.asn1;
+
+import org.apache.kerby.asn1.type.Asn1Integer;
+import org.apache.kerby.asn1.type.Asn1SequenceOf;
+import org.apache.kerby.asn1.type.Asn1SetType;
+import org.apache.kerby.asn1.type.Asn1Tagging;
+import org.apache.kerby.asn1.type.Asn1TaggingSequence;
+import org.apache.kerby.asn1.type.Asn1TaggingSet;
+import org.apache.kerby.asn1.type.Asn1VisibleString;
+
+/**
+ * Ref. X.690-0207(http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf),
+ * Annex A, A.1 ASN.1 description of the record structure
+ */
+public class PersonnelRecord extends Asn1TaggingSet {
+    protected enum PersonnelRecordField implements EnumType {
+        NAME,
+        TITLE,
+        NUMBER,
+        DATE_OF_HIRE,
+        NAME_OF_SPOUSE,
+        CHILDREN;
+
+        @Override
+        public int getValue() {
+            return ordinal();
+        }
+
+        @Override
+        public String getName() {
+            return name();
+        }
+    }
+
+    static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
+            new ExplicitField(PersonnelRecordField.NAME, -1, Name.class),
+            new ExplicitField(PersonnelRecordField.TITLE, 0, Asn1VisibleString.class),
+            new ExplicitField(PersonnelRecordField.NUMBER, -1, EmployeeNumber.class),
+            new ExplicitField(PersonnelRecordField.DATE_OF_HIRE, 1, Date.class),
+            new ExplicitField(PersonnelRecordField.NAME_OF_SPOUSE, 2, Name.class),
+            new ImplicitField(PersonnelRecordField.CHILDREN, 3, Children.class)
+    };
+
+    public PersonnelRecord() {
+        super(0, fieldInfos, true, true);
+    }
+
+    public void setName(Name name) {
+        setFieldAs(PersonnelRecordField.NAME, name);
+    }
+
+    public Name getName() {
+        return getFieldAs(PersonnelRecordField.NAME, Name.class);
+    }
+
+    public void setTitle(String title) {
+        setFieldAs(PersonnelRecordField.TITLE, new Asn1VisibleString(title));
+    }
+
+    public String getTitle() {
+        return getFieldAsString(PersonnelRecordField.TITLE);
+    }
+
+    public void setEmployeeNumber(EmployeeNumber employeeNumber) {
+        setFieldAs(PersonnelRecordField.NUMBER, employeeNumber);
+    }
+
+    public EmployeeNumber getEmployeeNumber() {
+        return getFieldAs(PersonnelRecordField.NUMBER, EmployeeNumber.class);
+    }
+
+    public void setDateOfHire(Date dateOfHire) {
+        setFieldAs(PersonnelRecordField.DATE_OF_HIRE, dateOfHire);
+    }
+
+    public Date getDateOfHire() {
+        return getFieldAs(PersonnelRecordField.DATE_OF_HIRE, Date.class);
+    }
+
+    public void setNameOfSpouse(Name spouse) {
+        setFieldAs(PersonnelRecordField.NAME_OF_SPOUSE, spouse);
+    }
+
+    public Name getNameOfSpouse() {
+        return getFieldAs(PersonnelRecordField.NAME_OF_SPOUSE, Name.class);
+    }
+
+    public void setChildren(Children children) {
+        setFieldAs(PersonnelRecordField.CHILDREN, children);
+    }
+
+    public Children getChildren() {
+        return getFieldAs(PersonnelRecordField.CHILDREN, Children.class);
+    }
+
+    public static class Children extends Asn1SequenceOf<ChildInformation> {
+        public Children(ChildInformation ... children) {
+            super();
+            for (ChildInformation child : children) {
+                addElement(child);
+            }
+        }
+
+        public Children() {
+            super();
+        }
+    }
+
+    public static class ChildInformation extends Asn1SetType {
+        protected enum ChildInformationField implements EnumType {
+            CHILD_NAME,
+            DATE_OF_BIRTH;
+
+            @Override
+            public int getValue() {
+                return ordinal();
+            }
+
+            @Override
+            public String getName() {
+                return name();
+            }
+        }
+
+        static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
+                new ExplicitField(ChildInformationField.CHILD_NAME, -1, Name.class),
+                new ExplicitField(ChildInformationField.DATE_OF_BIRTH, 0, Date.class)
+        };
+
+        public ChildInformation() {
+            super(tags);
+        }
+
+        public void setName(Name name) {
+            setFieldAs(ChildInformationField.CHILD_NAME, name);
+        }
+
+        public Name getName() {
+            return getFieldAs(ChildInformationField.CHILD_NAME, Name.class);
+        }
+
+        public void setDateOfBirth(Date date) {
+            setFieldAs(ChildInformationField.DATE_OF_BIRTH, date);
+        }
+
+        public Date getDateOfBirth() {
+            return getFieldAs(ChildInformationField.DATE_OF_BIRTH, Date.class);
+        }
+    }
+
+    public static class Name extends Asn1TaggingSequence {
+
+        protected enum NameField implements EnumType {
+            GIVENNAME,
+            INITIAL,
+            FAMILYNAME;
+
+            @Override
+            public int getValue() {
+                return ordinal();
+            }
+
+            @Override
+            public String getName() {
+                return name();
+            }
+        }
+
+        static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
+                new ExplicitField(NameField.GIVENNAME, -1, Asn1VisibleString.class),
+                new ExplicitField(NameField.INITIAL, -1, Asn1VisibleString.class),
+                new ExplicitField(NameField.FAMILYNAME, -1, Asn1VisibleString.class)
+        };
+
+        public Name() {
+            super(1, tags, true, true);
+        }
+
+        public Name(String givenName, String initial, String familyName) {
+            this();
+            setGivenName(givenName);
+            setInitial(initial);
+            setFamilyName(familyName);
+        }
+
+        public void setGivenName(String givenName) {
+            setFieldAs(NameField.GIVENNAME, new Asn1VisibleString(givenName));
+        }
+
+        public String getGivenName() {
+            return getFieldAsString(NameField.GIVENNAME);
+        }
+
+        public void setInitial(String initial) {
+            setFieldAs(NameField.INITIAL, new Asn1VisibleString(initial));
+        }
+
+        public String getInitial() {
+            return getFieldAsString(NameField.INITIAL);
+        }
+
+        public void setFamilyName(String familyName) {
+            setFieldAs(NameField.FAMILYNAME, new Asn1VisibleString(familyName));
+        }
+
+        public String getFamilyName() {
+            return getFieldAsString(NameField.FAMILYNAME);
+        }
+    }
+
+    public static class EmployeeNumber extends Asn1Tagging<Asn1Integer> {
+        public EmployeeNumber(Integer value) {
+            super(2, new Asn1Integer(value), true, true);
+        }
+
+        public EmployeeNumber() {
+            super(2, new Asn1Integer(), true, true);
+        }
+    }
+
+    public static class Date extends Asn1Tagging<Asn1VisibleString> {
+        public Date(String value) {
+            super(3, new Asn1VisibleString(value), true, true);
+        }
+        public Date() {
+            this(null);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecordTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecordTest.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecordTest.java
new file mode 100644
index 0000000..514b82b
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/PersonnelRecordTest.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.asn1;
+
+import org.apache.kerby.asn1.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Ref. X.690-0207(http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf),
+ * Annex A, A.1 ASN.1 description of the record structure
+ */
+public class PersonnelRecordTest {
+
+    static boolean verbose = false;
+
+    @Test
+    public void testEncoding() throws IOException {
+        PersonnelRecord pr = DataTest.createSamplePersonnel();
+
+        if (verbose) {
+            System.out.println("Name:");
+            System.out.println(HexUtil.bytesToHexFriendly(pr.getName().encode()));
+
+            System.out.println("DateOfHire:");
+            System.out.println(HexUtil.bytesToHexFriendly(pr.getDateOfHire().encode()));
+
+            System.out.println("SpouseName:");
+            System.out.println(HexUtil.bytesToHexFriendly(pr.getNameOfSpouse().encode()));
+
+            System.out.println("Child1:");
+            System.out.println(HexUtil.bytesToHexFriendly(pr.getChildren().getElements().get(0).encode()));
+
+            System.out.println("Child2:");
+            System.out.println(HexUtil.bytesToHexFriendly(pr.getChildren().getElements().get(1).encode()));
+
+            System.out.println("Children:");
+            System.out.println(HexUtil.bytesToHexFriendly(pr.getChildren().encode()));
+        }
+
+        byte[] data = DataTest.createSammplePersonnelEncodingData();
+        byte[] encoded = pr.encode();
+
+        if (verbose) {
+            System.out.println("ExpectedData:");
+            System.out.println(HexUtil.bytesToHexFriendly(data));
+
+            System.out.println("Encoded:");
+            System.out.println(HexUtil.bytesToHexFriendly(encoded));
+        }
+
+        assertThat(encoded).isEqualTo(data);
+    }
+
+    @Test
+    public void testDecoding() throws IOException {
+        PersonnelRecord expected = DataTest.createSamplePersonnel();
+        byte[] data = DataTest.createSammplePersonnelEncodingData();
+        Asn1.parseAndDump(data);
+        PersonnelRecord decoded = new PersonnelRecord();
+        decoded.decode(data);
+        Asn1.dump(decoded);
+
+        assertThat(decoded.getName().getGivenName())
+                .isEqualTo(expected.getName().getGivenName());
+        assertThat(decoded.getName().getInitial())
+                .isEqualTo(expected.getName().getInitial());
+        assertThat(decoded.getName().getFamilyName())
+                .isEqualTo(expected.getName().getFamilyName());
+        assertThat(decoded.getDateOfHire().getValue().getValue())
+                .isEqualTo(expected.getDateOfHire().getValue().getValue());
+        assertThat(decoded.getTitle())
+                .isEqualTo(expected.getTitle());
+        assertThat(decoded.getEmployeeNumber().getValue().getValue())
+                .isEqualTo(expected.getEmployeeNumber().getValue().getValue());
+        assertThat(decoded.getNameOfSpouse().getGivenName())
+                .isEqualTo(expected.getNameOfSpouse().getGivenName());
+        assertThat(decoded.getNameOfSpouse().getInitial())
+                .isEqualTo(expected.getNameOfSpouse().getInitial());
+        assertThat(decoded.getNameOfSpouse().getFamilyName())
+                .isEqualTo(expected.getNameOfSpouse().getFamilyName());
+        assertThat(decoded.getChildren().getElements().size())
+            .isEqualTo(expected.getChildren().getElements().size());
+        assertThat(decoded.getChildren().getElements().get(0).getName().getGivenName())
+                .isEqualTo(expected.getChildren().getElements().get(0).getName().getGivenName());
+        assertThat(decoded.getChildren().getElements().get(0).getName().getInitial())
+                .isEqualTo(expected.getChildren().getElements().get(0).getName().getInitial());
+        assertThat(decoded.getChildren().getElements().get(0).getName().getFamilyName())
+                .isEqualTo(expected.getChildren().getElements().get(0).getName().getFamilyName());
+        assertThat(decoded.getChildren().getElements().get(0).getDateOfBirth().getValue().getValue())
+                .isEqualTo(expected.getChildren().getElements().get(0).getDateOfBirth().getValue().getValue());
+        assertThat(decoded.getChildren().getElements().get(1).getName().getGivenName())
+                .isEqualTo(expected.getChildren().getElements().get(1).getName().getGivenName());
+        assertThat(decoded.getChildren().getElements().get(1).getName().getInitial())
+                .isEqualTo(expected.getChildren().getElements().get(1).getName().getInitial());
+        assertThat(decoded.getChildren().getElements().get(1).getName().getFamilyName())
+                .isEqualTo(expected.getChildren().getElements().get(1).getName().getFamilyName());
+        assertThat(decoded.getChildren().getElements().get(1).getDateOfBirth().getValue().getValue())
+                .isEqualTo(expected.getChildren().getElements().get(1).getDateOfBirth().getValue().getValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TaggingEncodingTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TaggingEncodingTest.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TaggingEncodingTest.java
new file mode 100644
index 0000000..ad9be01
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TaggingEncodingTest.java
@@ -0,0 +1,205 @@
+/**
+ *  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.asn1;
+
+import org.apache.kerby.asn1.type.Asn1Tagging;
+import org.apache.kerby.asn1.type.Asn1VisibleString;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ Ref. X.690-0207 8.14 Encoding of a tagged value
+ EXAMPLE
+ With ASN.1 type definitions (in an explicit tagging environment) of:
+ Type1 ::= VisibleString
+ Type2 ::= [APPLICATION 3] IMPLICIT Type1
+ Type3 ::= [2] Type2
+ Type4 ::= [APPLICATION 7] IMPLICIT Type3
+ Type5 ::= [2] IMPLICIT Type2
+ a value of:
+ "Jones"
+ is encoded as follows:
+ For Type1:
+ VisibleString Length Contents
+ 1A16 0516 4A6F6E657316
+ For Type2:
+ [Application 3] Length Contents
+ 4316 0516 4A6F6E657316
+ For Type3:
+ [2] Length Contents
+ A216 0716
+ [APPLICATION 3] Length Contents
+ 4316 0516 4A6F6E657316
+ For Type4:
+ [Application 7] Length Contents
+ 6716 0716
+ [APPLICATION 3] Length Contents
+ 4316 0516 4A6F6E657316
+ For Type5:
+ [2] Length Contents
+ 8216 0516 4A6F6E657316
+ */
+
+public class TaggingEncodingTest {
+    static final String TEST_STRING = "Jones";
+    static final byte[] TYPE1_EXPECTED_BYTES = new byte[] {(byte) 0x1A, (byte) 0x05,
+            (byte) 0x4A, (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x73};
+    static final byte[] TYPE2_EXPECTED_BYTES = new byte[] {(byte) 0x43, (byte) 0x05,
+            (byte) 0x4A, (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x73};
+    static final byte[] TYPE3_EXPECTED_BYTES = new byte[] {(byte) 0xA2, (byte) 0x07,
+            (byte) 0x43, (byte) 0x05, (byte) 0x4A, (byte) 0x6F, (byte) 0x6E,
+            (byte) 0x65, (byte) 0x73};
+    static final byte[] TYPE4_EXPECTED_BYTES = new byte[] {(byte) 0x67, (byte) 0x07,
+            (byte) 0x43, (byte) 0x05, (byte) 0x4A, (byte) 0x6F, (byte) 0x6E,
+            (byte) 0x65, (byte) 0x73};
+    static final byte[] TYPE5_EXPECTED_BYTES = new byte[] {(byte) 0x82, (byte) 0x05,
+            (byte) 0x4A, (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x73};
+
+
+    public static class Type1 extends Asn1VisibleString {
+        public Type1(String value) {
+            super(value);
+        }
+        public Type1() {
+            this(null);
+        }
+    }
+
+    public static class Type2 extends Asn1Tagging<Type1> {
+        public Type2(Type1 value) {
+            super(3, value, true, true);
+        }
+        public Type2() {
+            this(null);
+        }
+    }
+
+    public static class Type3 extends Asn1Tagging<Type2> {
+        public Type3(Type2 value) {
+            super(2, value, false, false);
+        }
+        public Type3() {
+            this(null);
+        }
+    }
+
+    public static class Type4 extends Asn1Tagging<Type3> {
+        public Type4(Type3 value) {
+            super(7, value, true, true);
+        }
+        public Type4() {
+            this(null);
+        }
+    }
+
+    public static class Type5 extends Asn1Tagging<Type2> {
+        public Type5(Type2 value) {
+            super(2, value, false, true);
+        }
+        public Type5() {
+            this(null);
+        }
+    }
+
+    @Test
+    public void testAsn1TaggingEncoding() throws IOException {
+        Type1 aType1 = new Type1(TEST_STRING);
+        Type2 aType2 = new Type2(aType1);
+        Type3 aType3 = new Type3(aType2);
+        Type4 aType4 = new Type4(aType3);
+        Type5 aType5 = new Type5(aType2);
+
+        assertThat(aType1.encode()).isEqualTo(TYPE1_EXPECTED_BYTES);
+        assertThat(aType2.encode()).isEqualTo(TYPE2_EXPECTED_BYTES);
+        assertThat(aType3.encode()).isEqualTo(TYPE3_EXPECTED_BYTES);
+        assertThat(aType4.encode()).isEqualTo(TYPE4_EXPECTED_BYTES);
+        assertThat(aType5.encode()).isEqualTo(TYPE5_EXPECTED_BYTES);
+    }
+
+    @Test
+    public void testAsn1TaggingDecoding() throws IOException {
+        Type1 aType1 = new Type1();
+        aType1.decode(TYPE1_EXPECTED_BYTES);
+        assertThat(aType1.getValue()).isEqualTo(TEST_STRING);
+
+        Type2 aType2 = new Type2();
+        aType2.decode(TYPE2_EXPECTED_BYTES);
+        assertThat(aType2.getValue().getValue()).isEqualTo(TEST_STRING);
+
+        Type3 aType3 = new Type3();
+        aType3.decode(TYPE3_EXPECTED_BYTES);
+        assertThat(aType3.getValue().getValue().getValue()).isEqualTo(TEST_STRING);
+
+        Type4 aType4 = new Type4();
+        aType4.decode(TYPE4_EXPECTED_BYTES);
+        assertThat(aType4.getValue().getValue().getValue().getValue()).isEqualTo(TEST_STRING);
+
+        Type5 aType5 = new Type5();
+        aType5.decode(TYPE5_EXPECTED_BYTES);
+        assertThat(aType5.getValue().getValue().getValue()).isEqualTo(TEST_STRING);
+    }
+
+    @Test
+    public void testTaggingEncodingOption() throws IOException {
+        Type1 aType1 = new Type1(TEST_STRING);
+        Type2 aType2 = new Type2(aType1);
+        Type3 aType3 = new Type3(aType2);
+
+        assertThat(aType1.encode()).isEqualTo(TYPE1_EXPECTED_BYTES);
+        assertThat(TYPE2_EXPECTED_BYTES)
+                .isEqualTo(aType1.taggedEncode(TaggingOption.newImplicitAppSpecific(3))); // for Type2
+        assertThat(TYPE3_EXPECTED_BYTES)
+                .isEqualTo(aType2.taggedEncode(TaggingOption.newExplicitContextSpecific(2))); // for Type3
+        assertThat(TYPE4_EXPECTED_BYTES)
+                .isEqualTo(aType3.taggedEncode(TaggingOption.newImplicitAppSpecific(7))); // for Type4
+        assertThat(TYPE5_EXPECTED_BYTES)
+                .isEqualTo(aType2.taggedEncode(TaggingOption.newImplicitContextSpecific(2))); // for Type5
+    }
+
+    @Test
+    public void testTaggingDecodingOption() throws IOException {
+        Type1 aType1 = new Type1();
+        aType1.decode(TYPE1_EXPECTED_BYTES);
+        assertThat(aType1.getValue()).isEqualTo(TEST_STRING);
+
+        // for Type2
+        aType1 = new Type1();
+        aType1.taggedDecode(TYPE2_EXPECTED_BYTES, TaggingOption.newImplicitAppSpecific(3));
+        assertThat(aType1.getValue()).isEqualTo(TEST_STRING);
+
+        // for Type3
+        Type2 aType2 = new Type2();
+        aType2.taggedDecode(TYPE3_EXPECTED_BYTES, TaggingOption.newExplicitContextSpecific(2));
+        assertThat(aType2.getValue().getValue()).isEqualTo(TEST_STRING);
+
+        // for Type4
+        Type3 aType3 = new Type3();
+        aType3.taggedDecode(TYPE4_EXPECTED_BYTES, TaggingOption.newImplicitAppSpecific(7));
+        assertThat(aType3.getValue().getValue().getValue()).isEqualTo(TEST_STRING);
+
+        // for Type5
+        aType2 = new Type2();
+        aType2.taggedDecode(TYPE5_EXPECTED_BYTES, TaggingOption.newImplicitContextSpecific(2));
+        assertThat(aType2.getValue().getValue()).isEqualTo(TEST_STRING);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestUtil.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestUtil.java b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestUtil.java
new file mode 100644
index 0000000..619af7b
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestUtil.java
@@ -0,0 +1,47 @@
+/**
+ *  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.asn1;
+
+import org.apache.kerby.asn1.util.HexUtil;
+import org.apache.kerby.asn1.util.IOUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public final class TestUtil {
+    private TestUtil() {
+
+    }
+
+    static byte[] readBytesFromTxtFile(String resource) throws IOException {
+        String hexStr = readStringFromTxtFile(resource);
+        return HexUtil.hex2bytes(hexStr);
+    }
+
+    static String readStringFromTxtFile(String resource) throws IOException {
+        InputStream is = TestUtil.class.getResourceAsStream(resource);
+        return IOUtil.readInput(is);
+    }
+
+    static byte[] readBytesFromBinFile(String resource) throws IOException {
+        InputStream is = TestUtil.class.getResourceAsStream(resource);
+        return IOUtil.readInputStream(is);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/resources/compressed-data.txt
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/resources/compressed-data.txt b/kerby-common/kerby-asn1/src/test/resources/compressed-data.txt
new file mode 100644
index 0000000..3012abe
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/resources/compressed-data.txt
@@ -0,0 +1 @@
+3080060B2A864886F70D0109100109A0803080020100300D060B2A864886F70D0109100308308006092A864886F70D010701A08024800482021E789CED945D6FDA301486EF2BF93FE4FA9560F15718AD76618C9BA15140492A75BD0B591A22D1002644E3DFD71E8516ED2FF4B573FC11FBB17D4E62BD69DAB2697BD9715BDE06F976BBAE8BBCAD37CD37339EF49E28BB0B9AFCB5FC11DBCD61CBFA7F292337FA3CC7E6CDFEA5B43DD3149B3F7553DD06CBBAC9EDF163C8B8DE6F37FBDA036F83BA59D74D7917BCD4EBF23F28B999A40A6188FD45BE652FC2F333F46F3D9DCF4CF02EDFB550493633C9A56B18D1301C808594E3D111988384EFA2089101244EB19823A5570909BD4A57A43341E0C9D57928439266F82E4F6CE1D9646462BFE39101CB2138678271D149C9F805C5DB427447263AB6E29DCFFE041333453844629C25FA3101A5C8921964242344D29511260FF78E1DBD834862EE1129BF88A505B75CB85C704ED9AE68AB420A24A58B4BD91465303BBC2E4B4B16268152F8E92216C487D605077A01DAE78CB987F78513BC6C5589B2EA442B48A69E20DAAA5DB6A2B52E239EA25A552B9C154393FBF908D9025AE1D1C78F613C7F80D66E07D5619DDB60BA397D4FFB605BDA202BEDEB9E6837616CA09D3B85E460D2F90FE32152E709C61915CE8A93FF9CF34C0AC198F075922A0
 D85911FAF0CB814125CB8176178F6DC201A60E04D24C9624E5D17EDE5790E7A0A20548A61D8F7711A43FDC2BF2564C72517BBE8C5179DF056F26EC7779CE1438AE2D8DAD517F58BFA4575FF70064A5277D9B14F77606C403F2E4B3231EA539B923773F79734000000000000000000000000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/resources/constructed-octet-string.txt
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/resources/constructed-octet-string.txt b/kerby-common/kerby-asn1/src/test/resources/constructed-octet-string.txt
new file mode 100644
index 0000000..66f28f1
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/resources/constructed-octet-string.txt
@@ -0,0 +1 @@
+24800482021E789CED945D6FDA301486EF2BF93FE4FA9560F15718AD76618C9BA15140492A75BD0B591A22D1002644E3DFD71E8516ED2FF4B573FC11FBB17D4E62BD69DAB2697BD9715BDE06F976BBAE8BBCAD37CD37339EF49E28BB0B9AFCB5FC11DBCD61CBFA7F292337FA3CC7E6CDFEA5B43DD3149B3F7553DD06CBBAC9EDF163C8B8DE6F37FBDA036F83BA59D74D7917BCD4EBF23F28B999A40A6188FD45BE652FC2F333F46F3D9DCF4CF02EDFB550493633C9A56B18D1301C808594E3D111988384EFA2089101244EB19823A5570909BD4A57A43341E0C9D57928439266F82E4F6CE1D9646462BFE39101CB2138678271D149C9F805C5DB427447263AB6E29DCFFE041333453844629C25FA3101A5C8921964242344D29511260FF78E1DBD834862EE1129BF88A505B75CB85C704ED9AE68AB420A24A58B4BD91465303BBC2E4B4B16268152F8E92216C487D605077A01DAE78CB987F78513BC6C5589B2EA442B48A69E20DAAA5DB6A2B52E239EA25A552B9C154393FBF908D9025AE1D1C78F613C7F80D66E07D5619DDB60BA397D4FFB605BDA202BEDEB9E6837616CA09D3B85E460D2F90FE32152E709C61915CE8A93FF9CF34C0AC198F075922A0D85911FAF0CB814125CB8176178F6DC201A60E04D24C9624E5D17EDE5790E7A0A20548A61D8F7711A43FDC2BF2564C72517BBE8C
 5179DF056F26EC7779CE1438AE2D8DAD517F58BFA4575FF70064A5277D9B14F77606C403F2E4B3231EA539B923773F797340000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/resources/der-data.dat
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/resources/der-data.dat b/kerby-common/kerby-asn1/src/test/resources/der-data.dat
new file mode 100644
index 0000000..6d503b3
Binary files /dev/null and b/kerby-common/kerby-asn1/src/test/resources/der-data.dat differ

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/resources/empty-container.txt
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/resources/empty-container.txt b/kerby-common/kerby-asn1/src/test/resources/empty-container.txt
new file mode 100644
index 0000000..40945ee
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/resources/empty-container.txt
@@ -0,0 +1 @@
+6A819F30819CA103020105A20302010AA3023000A4818B308188A00703050050000010A1143012A003020101A10B30091B076472616E6B7965A20A1B08544553542E434F4DA31D301BA003020102A11430121B066B72627467741B08544553542E434F4DA411180F32303135313231303130323831305AA511180F32303135313231303138323831305AA706020434D354A9A80E300C020111020110020101020103
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/test/resources/signed-data.txt
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/test/resources/signed-data.txt b/kerby-common/kerby-asn1/src/test/resources/signed-data.txt
new file mode 100644
index 0000000..bf018ef
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/test/resources/signed-data.txt
@@ -0,0 +1 @@
+308006092A864886F70D010702A0803080020101310B300906052B0E03021A0500308006092A864886F70D010701A0802480040C48656C6C6F20576F726C6421000000000000A08204623082020D30820176A003020102020101300D06092A864886F70D0101040500302531163014060355040A130D426F756E637920436173746C65310B3009060355040613024155301E170D3034313032343034333035385A170D3035303230313034333035385A302531163014060355040A130D426F756E637920436173746C65310B300906035504061302415530819F300D06092A864886F70D010101050003818D003081890281810098F7380B2100E80398F7186758DD352BA1387447F55842FCF1B5EC5762227546736BA52611227C44206BFBAA642A527759C7B095192A6F64D5B567796CC2D3DE358BD6677F181BDA39D75EC6B99300762845444AB396B118D246D9D888B82A046D2BCE968C9F90399EDBBB374E34E847AC0617B5F5C8D901A81E1071990DBB9F0203010001A34D304B301D0603551D0E041604147F88734A3A8E9FE01C96145CB044D67AE574ABD6301F0603551D230418301680147F88734A3A8E9FE01C96145CB044D67AE574ABD630090603551D1304023000300D06092A864886F70D010104050003818100530927B40EA47A37D1B9E5438372DCF0A72BE49EF86C374
 E96981A9F38F9AF1F183F4399EEFC1BA344B20BE91464F2A0BC6F278081F382B3CACFB5A761DD5F3A198B25C07ABE52E08C29B44DD3C711702B28F6F1C46B33A74AE3B0C3C97524574AB004030D96EC2793F9E8E0AEE297337631993997BC17C8D6BDC89E821D6E9D3082024D308201B6A003020102020102300D06092A864886F70D0101040500302531163014060355040A130D426F756E637920436173746C65310B3009060355040613024155301E170D3034313032343034333035395A170D3035303230313034333035395A3065311830160603550403130F4572696320482E2045636869646E613124302206092A864886F70D01090116156572696340626F756E6379636173746C652E6F726731163014060355040A130D426F756E637920436173746C65310B300906035504061302415530819F300D06092A864886F70D010101050003818D00308189028181009BEE429C653A5B8E625290AC686927E600EBB99BF78FFA3B37A6A09916618A468B1B6245E8409A5F5DE28A85497E6CC1B0F2B1000096C2E4D70A84925C6F2F88AFEAA521F02697D01D8121B5C0B40B122A96796DBF7290006C21FCF770A523EF48D9E44011AFB45ABEFBD8275C305BCA77CFF1BD8BD848ACD17F54DB2EA016230203010001A34D304B301D0603551D0E0416041440263A4B2717AE85A109BA21
 005537AEAF268D53301F0603551D230418301680147F88734A3A8E9FE01C96145CB044D67AE574ABD630090603551D1304023000300D06092A864886F70D01010405000381810011E223BCD90A30F53F6580AED53AA31993C4AA2FA0967B60DA10BF085D281B21C5A4CB86B4C7A9177A6E5BEBB328CD6CEB56ABDDA862769DD7161AFF18453F5F12B6E00A25237C858313FC3D18145A6422CD3417A56526865B017B5B8829511F340CC282D61F250F072482AC50271D59E08A54AB388D18A89EC7A4D6BA3390F13182012F3082012B020101302A302531163014060355040A130D426F756E637920436173746C65310B3009060355040613024155020102300906052B0E03021A0500A05D301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70D010905310F170D3034313032343034333035395A302306092A864886F70D010904311604142EF7BDE608CE5404E97D5F042F95F89F1C232871300D06092A864886F70D010101050004818061DB7B7FE3719BBA6FF7AB4617373C48E23143BC98421188D601AF9FEF14D864AF2F13AC67CEA48E399BB82ED4C4B4FEF75AB3BCA4BE2765FEC3597CED06A6110851A2233114F753ACAE4D617868BA5AB496DB46C21EA493BF07691D2006D5E5209B6605432483CE476AA7AEE1CDDB02C56BE7C4BF827CC10
 F17C2F9340BC88C000000000000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-config/README
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/README b/kerby-common/kerby-config/README
new file mode 100644
index 0000000..505efca
--- /dev/null
+++ b/kerby-common/kerby-config/README
@@ -0,0 +1,20 @@
+<!--
+  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.
+-->
+
+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/9e4dbd6e/kerby-common/kerby-config/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/pom.xml b/kerby-common/kerby-config/pom.xml
new file mode 100644
index 0000000..54b3c76
--- /dev/null
+++ b/kerby-common/kerby-config/pom.xml
@@ -0,0 +1,41 @@
+<?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>kerby-common</artifactId>
+    <version>1.0.0-RC2-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>
+      <version>${slf4j.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <version>${slf4j.version}</version>
+   </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Conf.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Conf.java b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Conf.java
new file mode 100644
index 0000000..c0bea4b
--- /dev/null
+++ b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Conf.java
@@ -0,0 +1,318 @@
+/**
+ *  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.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * A general class to describe and store all the config files.
+ */
+public class Conf implements Config {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Conf.class);
+
+    private List<ConfigLoader> resourceConfigs;
+    private final ConfigImpl config;
+
+    public Conf() {
+        this.resourceConfigs = new ArrayList<ConfigLoader>(1);
+        this.config = new ConfigImpl("Conf");
+    }
+
+    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, Object> mapConfig) {
+        addResource(Resource.createMapResource(mapConfig));
+    }
+
+    /**
+     * Load the resource name and content in one step.
+     * Add synchronized to avoid conflicts
+     * @param resource the config resource
+     */
+    public synchronized void addResource(Resource resource) {
+        ConfigLoader loader = getLoader(resource);
+        resourceConfigs.add(loader);
+        Config loaded = loader.load();
+        config.add(loaded);
+    }
+
+    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;
+    }
+
+    /**
+     * For users usage, to determine whether to reload config files.
+     * Add synchronized to avoid conflicts
+     */
+    public synchronized void reload() {
+        config.reset();
+        for (ConfigLoader loader : resourceConfigs) {
+            Config loaded = loader.load();
+            config.add(loaded);
+        }
+    }
+
+    @Override
+    public String getResource() {
+        return config.getResource();
+    }
+
+    @Override
+    public Set<String> getNames() {
+        return config.getNames();
+    }
+
+    @Override
+    public String getString(String name) {
+        return config.getString(name);
+    }
+
+    @Override
+    public String getString(ConfigKey name, boolean useDefault) {
+        return config.getString(name, useDefault);
+    }
+
+    @Override
+    public String getString(String name, String defaultValue) {
+        return config.getString(name, defaultValue);
+    }
+
+    /**
+     * Values user sets will be add in config directly.
+     * Add synchronized to avoid conflicts
+     * @param name The property name
+     * @param value The string value
+     */
+    @Override
+    public synchronized void setString(String name, String value) {
+        config.set(name, value);
+    }
+
+    @Override
+    public void setString(ConfigKey name, String value) {
+        setString(name.getPropertyKey(), value);
+    }
+
+    @Override
+    public String getTrimmed(String name) {
+        return config.getTrimmed(name);
+    }
+
+    @Override
+    public String getTrimmed(ConfigKey name) {
+        return config.getTrimmed(name);
+    }
+
+    @Override
+    public Boolean getBoolean(String name) {
+        return config.getBoolean(name);
+    }
+
+    @Override
+    public Boolean getBoolean(ConfigKey name, boolean useDefault) {
+        return config.getBoolean(name, useDefault);
+    }
+
+    @Override
+    public Boolean getBoolean(String name, Boolean defaultValue) {
+        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) {
+        return config.getInt(name);
+    }
+
+    @Override
+    public Integer getInt(ConfigKey name, boolean useDefault) {
+        return config.getInt(name, useDefault);
+    }
+
+    @Override
+    public Integer getInt(String name, Integer defaultValue) {
+        return config.getInt(name, defaultValue);
+    }
+
+    @Override
+    public void setInt(String name, Integer value) {
+        setString(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setInt(ConfigKey name, Integer value) {
+        setString(name.getPropertyKey(), String.valueOf(value));
+    }
+
+    @Override
+    public Long getLong(String name) {
+        return config.getLong(name);
+    }
+
+    @Override
+    public Long getLong(ConfigKey name, boolean useDefault) {
+        return config.getLong(name, useDefault);
+    }
+
+    @Override
+    public Long getLong(String name, Long defaultValue) {
+        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) {
+        return config.getFloat(name);
+    }
+
+    @Override
+    public Float getFloat(ConfigKey name, boolean useDefault) {
+        return config.getFloat(name, useDefault);
+    }
+
+    @Override
+    public Float getFloat(String name, Float defaultValue) {
+        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) {
+        return config.getList(name);
+    }
+
+    @Override
+    public List<String> getList(String name, String[] defaultValue) {
+        return config.getList(name, defaultValue);
+    }
+
+    @Override
+    public List<String> getList(ConfigKey name) {
+        return config.getList(name);
+    }
+
+    @Override
+    public Config getConfig(String name) {
+        return config.getConfig(name);
+    }
+
+    @Override
+    public Config getConfig(ConfigKey name) {
+        return config.getConfig(name);
+    }
+
+    @Override
+    public Class<?> getClass(String name) throws ClassNotFoundException {
+        return config.getClass(name);
+    }
+
+    @Override
+    public Class<?> getClass(String name, Class<?> defaultValue)
+            throws ClassNotFoundException {
+        return config.getClass(name, defaultValue);
+    }
+
+    @Override
+    public Class<?> getClass(ConfigKey name, boolean useDefault)
+            throws ClassNotFoundException {
+        return config.getClass(name, useDefault);
+    }
+
+    @Override
+    public <T> T getInstance(String name) throws ClassNotFoundException {
+        return config.getInstance(name);
+    }
+
+    @Override
+    public <T> T getInstance(ConfigKey name) throws ClassNotFoundException {
+        return config.getInstance(name);
+    }
+
+    @Override
+    public <T> T getInstance(String name, Class<T> xface) throws ClassNotFoundException {
+        return config.getInstance(name, xface);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Config.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Config.java b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Config.java
new file mode 100644
index 0000000..c71405a
--- /dev/null
+++ b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Config.java
@@ -0,0 +1,138 @@
+/**
+ *  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, boolean useDefault);
+    String getString(String name, String defaultValue);
+
+    /**
+     * Set a string value for the specified property
+     * @param name The property name
+     * @param value The string value
+     */
+    void setString(String name, String value);
+
+    /**
+     * Set a string value for the specified property
+     * @param name The config key name
+     * @param value The string value
+     */
+    void setString(ConfigKey name, String value);
+
+    String getTrimmed(String name);
+    String getTrimmed(ConfigKey name);
+    Boolean getBoolean(String name);
+    Boolean getBoolean(ConfigKey name, boolean useDefault);
+    Boolean getBoolean(String name, Boolean defaultValue);
+
+    /**
+     * Set a boolean value for the specified property
+     * @param name The property name
+     * @param value The boolean value
+     */
+    void setBoolean(String name, Boolean value);
+
+    /**
+     * Set a boolean value for the specified property
+     * @param name The config key name
+     * @param value The boolean value
+     */
+    void setBoolean(ConfigKey name, Boolean value);
+
+    Integer getInt(String name);
+    Integer getInt(ConfigKey name, boolean useDefault);
+    Integer getInt(String name, Integer defaultValue);
+
+    /**
+     * Set an int value for the specified property
+     * @param name The property name
+     * @param value The string value
+     */
+    void setInt(String name, Integer value);
+
+    /**
+     * Set an int value for the specified property
+     * @param name The config key name
+     * @param value The int value
+     */
+    void setInt(ConfigKey name, Integer value);
+
+    Long getLong(String name);
+    Long getLong(ConfigKey name, boolean useDefault);
+    Long getLong(String name, Long defaultValue);
+
+    /**
+     * Set a long value for the specified property
+     * @param name The property name
+     * @param value The long value
+     */
+    void setLong(String name, Long value);
+
+    /**
+     * Set a long value for the specified property
+     * @param name The config key name
+     * @param value The long value
+     */
+    void setLong(ConfigKey name, Long value);
+
+    Float getFloat(String name);
+    Float getFloat(ConfigKey name, boolean useDefault);
+    Float getFloat(String name, Float defaultValue);
+
+    /**
+     * Set a float value for the specified property
+     * @param name The property name
+     * @param value The float value
+     */
+    void setFloat(String name, Float value);
+
+    /**
+     * Set a float value for the specified property
+     * @param name The config key name
+     * @param value The float 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, boolean useDefault) 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/9e4dbd6e/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java
new file mode 100644
index 0000000..ec3090f
--- /dev/null
+++ b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigImpl.java
@@ -0,0 +1,428 @@
+/**
+ *  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;
+
+    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() {
+        Set<String>propNames = new HashSet<String>(properties.keySet());
+        for (Config config : configs) {
+            propNames.addAll(config.getNames());
+        }
+        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, boolean useDefault) {
+        if (useDefault) {
+            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, boolean useDefault) {
+        if (useDefault) {
+            return getInt(name.getPropertyKey(),
+                    getDefaultValueAs(name, Integer.class));
+        }
+        return getInt(name.getPropertyKey());
+    }
+
+    private <T> T getDefaultValueAs(ConfigKey confKey, Class<T> cls) {
+        Object defValue = confKey.getDefaultValue();
+        if (defValue != null && cls != null) {
+            return (T) defValue;
+        }
+        return null;
+    }
+
+    @Override
+    public Integer getInt(String name, Integer defaultValue) {
+        Integer result = getInt(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    @Override
+    public void setInt(String name, Integer value) {
+        set(name, String.valueOf(value));
+    }
+
+    @Override
+    public void setInt(ConfigKey name, Integer 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, boolean useDefault) {
+        if (useDefault) {
+            return getLong(name.getPropertyKey(),
+                getDefaultValueAs(name, Long.class));
+        }
+        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, boolean useDefault) {
+        if (useDefault) {
+            return getFloat(name.getPropertyKey(),
+                    getDefaultValueAs(name, Float.class));
+        }
+        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, boolean useDefault) {
+        if (useDefault) {
+            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, boolean useDefault)
+            throws ClassNotFoundException {
+        if (useDefault) {
+            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);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigKey.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigKey.java b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigKey.java
new file mode 100644
index 0000000..4424f22
--- /dev/null
+++ b/kerby-common/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/9e4dbd6e/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigLoader.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigLoader.java b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigLoader.java
new file mode 100644
index 0000000..6282559
--- /dev/null
+++ b/kerby-common/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/9e4dbd6e/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigObject.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigObject.java b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/ConfigObject.java
new file mode 100644
index 0000000..2be3972
--- /dev/null
+++ b/kerby-common/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/9e4dbd6e/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Configurable.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Configurable.java b/kerby-common/kerby-config/src/main/java/org/apache/kerby/config/Configurable.java
new file mode 100644
index 0000000..fd41dab
--- /dev/null
+++ b/kerby-common/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();
+}


Mime
View raw message