Added Asn1Application type for implicit encoding of application specific, and refined dumping output
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
index 80bf9db..8abbad0 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
@@ -91,10 +91,10 @@
 
     public static void dump(byte[] content,
                             boolean useRawFormat) throws IOException {
-        String hexStr = HexUtil.bytesToHex(content);
+        //String hexStr = HexUtil.bytesToHex(content);
         Asn1Dumper dumper = new Asn1Dumper();
-        System.out.println("Dumping data:");
-        dumper.dumpData(hexStr);
+        //System.out.println("Dumping data:");
+        //dumper.dumpData(hexStr);
         dumper.dump(content, useRawFormat);
         String output = dumper.output();
         System.out.println(output);
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java
index 820d08b..8f79b28 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java
@@ -20,6 +20,7 @@
 package org.apache.kerby.asn1;
 
 import org.apache.kerby.asn1.parse.Asn1ParseResult;
+import org.apache.kerby.asn1.type.Asn1Application;
 import org.apache.kerby.asn1.type.Asn1Collection;
 import org.apache.kerby.asn1.type.Asn1Constructed;
 import org.apache.kerby.asn1.type.Asn1Encodeable;
@@ -46,6 +47,10 @@
             Asn1Encodeable tmpValue = new Asn1Constructed(parseResult.tag());
             tmpValue.decode(parseResult);
             return tmpValue;
+        } else if (parseResult.isAppSpecific()) {
+            Asn1Application app = new Asn1Application(parseResult.tag());
+            app.decode(parseResult);
+            return app;
         } else {
             throw new IOException("Unexpected item: " + parseResult.typeStr());
         }
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
index 73d3321..38addf4 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
@@ -23,6 +23,7 @@
 import org.apache.kerby.asn1.parse.Asn1ParseResult;
 import org.apache.kerby.asn1.parse.Asn1Parser;
 import org.apache.kerby.asn1.type.Asn1Any;
+import org.apache.kerby.asn1.type.Asn1Application;
 import org.apache.kerby.asn1.type.Asn1Simple;
 import org.apache.kerby.asn1.type.Asn1Type;
 import org.apache.kerby.asn1.util.HexUtil;
@@ -83,11 +84,11 @@
             indent(indents).append("Null");
         } else if (value instanceof Asn1Simple) {
             indent(indents).append(value.toString());
-        }  else if (value instanceof Asn1Item) {
-            indent(indents).append(value.toString());
         } else if (value instanceof Asn1Dumpable) {
             Asn1Dumpable dumpable = (Asn1Dumpable) value;
             dumpable.dumpWith(this, indents);
+        } else if (value instanceof Asn1Application) {
+            indent(indents).append(value.toString());
         } else if (value instanceof Asn1Any) {
             indent(indents).append("<Any>");
         } else {
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java
index d70af2f..5055c0f 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java
@@ -27,16 +27,8 @@
         super(header, bodyStart, buffer);
     }
 
-    public byte[] readBodyBytes() {
-        ByteBuffer bodyBuffer = getBodyBuffer();
-        byte[] result = new byte[bodyBuffer.remaining()];
-        bodyBuffer.get(result);
-        return result;
-    }
-
     @Override
     public String toString() {
-        String valueStr = "##undecoded##";
-        return typeStr() + valueStr;
+        return typeStr();
     }
 }
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java
index 78b7865..10f8977 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java
@@ -72,6 +72,13 @@
         return result;
     }
 
+    public byte[] readBodyBytes() {
+        ByteBuffer bodyBuffer = getBodyBuffer();
+        byte[] result = new byte[bodyBuffer.remaining()];
+        bodyBuffer.get(result);
+        return result;
+    }
+
     public boolean isDefinitiveLength() {
         return header.isDefinitiveLength();
     }
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java
index 105aed6..96c68a1 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java
@@ -75,4 +75,9 @@
     public void setValue(T value) {
         this.value = value;
     }
+
+    @Override
+    public String toString() {
+        return tag().typeStr();
+    }
 }
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Application.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Application.java
new file mode 100644
index 0000000..a3b885a
--- /dev/null
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Application.java
@@ -0,0 +1,57 @@
+/**
+ *  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.type;
+
+import org.apache.kerby.asn1.Tag;
+import org.apache.kerby.asn1.parse.Asn1ParseResult;
+
+import java.io.IOException;
+
+/**
+ * Application object mainly for using implicit encoding.
+ */
+public class Asn1Application extends AbstractAsn1Type<byte[]> {
+
+    public Asn1Application(Tag tag, byte[] value) {
+        super(tag, value);
+    }
+
+    public Asn1Application(Tag tag) {
+        super(tag);
+    }
+
+    @Override
+    protected int encodingBodyLength() {
+        if (getValue() != null) {
+            return getValue().length;
+        }
+        return 0;
+    }
+
+    @Override
+    protected void decodeBody(Asn1ParseResult parseResult) throws IOException {
+        setValue(parseResult.readBodyBytes());
+    }
+
+    @Override
+    public String toString() {
+        return tag().typeStr() + "  <" + getValue().length + " bytes>";
+    }
+}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java
index edc2562..4bde63b 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java
@@ -85,13 +85,4 @@
             throw new IOException("Failed to create element type", e);
         }
     }
-
-    @Override
-    public void dumpWith(Asn1Dumper dumper, int indents) {
-        dumper.dumpTypeInfo(indents, getClass());
-
-        for (Asn1Type aObj : getValue()) {
-            dumper.dumpType(indents + 4, aObj).newLine();
-        }
-    }
 }
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java
index ddbc75f..65c10f3 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java
@@ -115,8 +115,13 @@
     public void dumpWith(Asn1Dumper dumper, int indents) {
         dumper.indent(indents).append(toString()).newLine();
 
-        for (Asn1Type aObj : getValue()) {
-            dumper.dumpType(indents + 4, aObj).newLine();
+        List<Asn1Type> items = getValue();
+        int i = 0;
+        for (Asn1Type aObj : items) {
+            dumper.dumpType(indents + 4, aObj);
+            if (i != items.size() - 1) {
+                dumper.newLine();
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java
index 45165a8..f0debdb 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java
@@ -142,7 +142,8 @@
     }
 
     /**
-     * Create a simple ASN1 object given tagNo, using the default constructor with no value provided
+     * Create a simple ASN1 object given tagNo, using the default constructor
+     * with no value provided
      * @param tagNo The tag number
      * @return A simple ASN1 object
      */
@@ -154,7 +155,8 @@
     }
 
     /**
-     * Create a simple ASN1 object given tagNo, using the default constructor with no value provided
+     * Create a simple ASN1 object given tagNo, using the default constructor
+     * with no value provided
      * @param tagNo The tag number
      * @return The simple ASN1 object
      */
@@ -201,7 +203,8 @@
             case VISIBLE_STRING:
                 return new Asn1VisibleString();
             default:
-                throw new IllegalArgumentException("Unexpected tag " + tagNo.getValue());
+                throw new IllegalArgumentException(
+                    "Unexpected tag " + tagNo.getValue());
         }
     }
 
diff --git a/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java b/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java
index bbaed2a..da26f24 100644
--- a/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java
+++ b/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java
@@ -34,7 +34,7 @@
 
             byte[] data = TestData.createSammplePersonnelEncodingData();
             Asn1.dump(data, true);
-            //Asn1.dump(data, false);
+            Asn1.dump(data, false);
         } catch (Exception e) {
             e.printStackTrace();
             Assert.fail();
@@ -46,7 +46,7 @@
         String hexStr = TestUtil.readStringFromTxtFile("/compressed-data.txt");
         try {
             Asn1.dump(hexStr, true);
-            //Asn1.dump(hexStr, false);
+            Asn1.dump(hexStr, false);
         } catch (Exception e) {
             e.printStackTrace();
             Assert.fail();
@@ -58,7 +58,7 @@
         String hexStr = TestUtil.readStringFromTxtFile("/signed-data.txt");
         try {
             Asn1.dump(hexStr, true);
-            //Asn1.dump(hexStr, false);
+            Asn1.dump(hexStr, false);
         } catch (Exception e) {
             e.printStackTrace();
             Assert.fail();
@@ -70,7 +70,7 @@
         byte[] data = TestUtil.readBytesFromBinFile("/der-data.dat");
         try {
             Asn1.dump(data, true);
-            //Asn1.dump(data, false);
+            Asn1.dump(data, false);
         } catch (Exception e) {
             e.printStackTrace();
             Assert.fail();