X-Git-Url: http://git.nikiroo.be/?p=fanfix.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fserial%2FCustomSerializer.java;fp=src%2Fbe%2Fnikiroo%2Futils%2Fserial%2FCustomSerializer.java;h=e58ccf2af5945eab2ba4b508bd9d04c9213c56f1;hp=0000000000000000000000000000000000000000;hb=d46b7b96f94e88a776bcd2dfd756549ffb300cc9;hpb=c9994f27667bc421bcd448d39e55774fddf5c431 diff --git a/src/be/nikiroo/utils/serial/CustomSerializer.java b/src/be/nikiroo/utils/serial/CustomSerializer.java new file mode 100644 index 0000000..e58ccf2 --- /dev/null +++ b/src/be/nikiroo/utils/serial/CustomSerializer.java @@ -0,0 +1,150 @@ +package be.nikiroo.utils.serial; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import be.nikiroo.utils.streams.BufferedInputStream; +import be.nikiroo.utils.streams.ReplaceInputStream; +import be.nikiroo.utils.streams.ReplaceOutputStream; + +/** + * A {@link CustomSerializer} supports and generates values in the form: + * + *

+ * In this scheme, the values are: + *

+ *

+ * To create a new {@link CustomSerializer}, you are expected to implement the + * abstract methods of this class. The rest should be taken care of bythe + * system. + * + * @author niki + */ +public abstract class CustomSerializer { + /** + * Generate the custom ENCODED_VALUE from this + * value. + *

+ * The value will always be of the supported type. + * + * @param out + * the {@link OutputStream} to write the value to + * @param value + * the value to serialize + * + * @throws IOException + * in case of I/O error + */ + protected abstract void toStream(OutputStream out, Object value) + throws IOException; + + /** + * Regenerate the value from the custom ENCODED_VALUE. + *

+ * The value in the {@link InputStream} in will always be of the + * supported type. + * + * @param in + * the {@link InputStream} containing the + * ENCODED_VALUE + * + * @return the regenerated object + * + * @throws IOException + * in case of I/O error + */ + protected abstract Object fromStream(InputStream in) throws IOException; + + /** + * Return the supported type name. + *

+ * It must be the name returned by {@link Object#getClass() + * #getCanonicalName()}. + * + * @return the supported class name + */ + protected abstract String getType(); + + /** + * Encode the object into the given {@link OutputStream}, i.e., generate the + * ENCODED_VALUE part. + *

+ * Use whatever scheme you wish, the system shall ensure that the content is + * correctly encoded and that you will receive the same content at decode + * time. + * + * @param out + * the builder to append to + * @param value + * the object to encode + * + * @throws IOException + * in case of I/O error + */ + public void encode(OutputStream out, Object value) throws IOException { + ReplaceOutputStream replace = new ReplaceOutputStream(out, // + new String[] { "\\", "\n" }, // + new String[] { "\\\\", "\\n" }); + + try { + SerialUtils.write(replace, "custom^"); + SerialUtils.write(replace, getType()); + SerialUtils.write(replace, "^"); + toStream(replace, value); + } finally { + replace.close(false); + } + } + + /** + * Decode the value back into the supported object type. + *

+ * We do not expect the full content here but only: + *

+ * That is, we do not expect the "custom^TYPE^" + * part. + * + * @param in + * the encoded value + * + * @return the object + * + * @throws IOException + * in case of I/O error + */ + public Object decode(InputStream in) throws IOException { + ReplaceInputStream replace = new ReplaceInputStream(in, // + new String[] { "\\\\", "\\n" }, // + new String[] { "\\", "\n" }); + + try { + return fromStream(replace); + } finally { + replace.close(false); + } + } + + public static boolean isCustom(BufferedInputStream in) throws IOException { + return in.startsWith("custom^"); + } + + public static String typeOf(String encodedValue) { + int pos1 = encodedValue.indexOf('^'); + int pos2 = encodedValue.indexOf('^', pos1 + 1); + String type = encodedValue.substring(pos1 + 1, pos2); + + return type; + } +}