X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fserial%2FImporter.java;fp=src%2Fbe%2Fnikiroo%2Futils%2Fserial%2FImporter.java;h=0000000000000000000000000000000000000000;hb=46add0670fdee4bd936a13fe2448c5e20a7ffd0a;hp=81814dfdbadf6a71ec2224d14be5926314bbd105;hpb=1b5197ed4ceec2025a9a40c417b37c646b756138;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/serial/Importer.java b/src/be/nikiroo/utils/serial/Importer.java deleted file mode 100644 index 81814df..0000000 --- a/src/be/nikiroo/utils/serial/Importer.java +++ /dev/null @@ -1,288 +0,0 @@ -package be.nikiroo.utils.serial; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; -import java.util.zip.GZIPInputStream; - -import be.nikiroo.utils.IOUtils; -import be.nikiroo.utils.streams.Base64InputStream; -import be.nikiroo.utils.streams.BufferedInputStream; -import be.nikiroo.utils.streams.NextableInputStream; -import be.nikiroo.utils.streams.NextableInputStreamStep; - -/** - * A simple class that can accept the output of {@link Exporter} to recreate - * objects as they were sent to said exporter. - *

- * This class requires the objects (and their potential enclosing objects) to - * have an empty constructor, and does not support inner classes (it does - * support nested classes, though). - * - * @author niki - */ -public class Importer { - private Boolean link; - private Object me; - private Importer child; - private Map map; - - private String currentFieldName; - - /** - * Create a new {@link Importer}. - */ - public Importer() { - map = new HashMap(); - map.put("NULL", null); - } - - private Importer(Map map) { - this.map = map; - } - - /** - * Read some data into this {@link Importer}: it can be the full serialised - * content, or a number of lines of it (any given line MUST be - * complete though) and accumulate it with the already present data. - * - * @param in - * the data to parse - * - * @return itself so it can be chained - * - * @throws NoSuchFieldException - * if the serialised data contains information about a field - * which does actually not exist in the class we know of - * @throws NoSuchMethodException - * if a class described in the serialised data cannot be created - * because it is not compatible with this code - * @throws ClassNotFoundException - * if a class described in the serialised data cannot be found - * @throws IOException - * if the content cannot be read (for instance, corrupt data) - * @throws NullPointerException - * if the stream is empty - */ - public Importer read(InputStream in) throws NoSuchFieldException, - NoSuchMethodException, ClassNotFoundException, IOException, - NullPointerException { - - NextableInputStream stream = new NextableInputStream(in, - new NextableInputStreamStep('\n')); - - try { - if (in == null) { - throw new NullPointerException("InputStream is null"); - } - - boolean first = true; - while (stream.next()) { - if (stream.eof()) { - if (first) { - throw new NullPointerException( - "InputStream empty, normal termination"); - } - return this; - } - first = false; - - boolean zip = stream.startsWith("ZIP:"); - boolean b64 = stream.startsWith("B64:"); - - if (zip || b64) { - stream.skip("XXX:".length()); - - InputStream decoded = stream.open(); - if (zip) { - decoded = new GZIPInputStream(decoded); - } - decoded = new Base64InputStream(decoded, false); - - try { - read(decoded); - } finally { - decoded.close(); - } - } else { - processLine(stream); - } - } - } finally { - stream.close(false); - } - - return this; - } - - /** - * Read a single (whole) line of serialised data into this {@link Importer} - * and accumulate it with the already present data. - * - * @param in - * the line to parse - * - * @return TRUE if we are just done with one object or sub-object - * - * @throws NoSuchFieldException - * if the serialised data contains information about a field - * which does actually not exist in the class we know of - * @throws NoSuchMethodException - * if a class described in the serialised data cannot be created - * because it is not compatible with this code - * @throws ClassNotFoundException - * if a class described in the serialised data cannot be found - * @throws IOException - * if the content cannot be read (for instance, corrupt data) - */ - private boolean processLine(BufferedInputStream in) - throws NoSuchFieldException, NoSuchMethodException, - ClassNotFoundException, IOException { - - // Defer to latest child if any - if (child != null) { - if (child.processLine(in)) { - if (currentFieldName != null) { - setField(currentFieldName, child.getValue()); - currentFieldName = null; - } - child = null; - } - - return false; - } - - // Start/Stop object - if (in.is("{")) { // START: new child if needed - if (link != null) { - child = new Importer(map); - } - in.end(); - return false; - } else if (in.is("}")) { // STOP: report self to parent - in.end(); - return true; - } - - // Custom objects - if (CustomSerializer.isCustom(in)) { - // not a field value but a direct value - me = SerialUtils.decode(in); - return false; - } - - // REF: (object) - if (in.startsWith("REF ")) { // REF: create/link self - // here, line is REF type@999:xxx - // xxx is optional - - NextableInputStream stream = new NextableInputStream(in, - new NextableInputStreamStep(':')); - try { - stream.next(); - - stream.skip("REF ".length()); - String header = IOUtils.readSmallStream(stream); - - String[] tab = header.split("@"); - if (tab.length != 2) { - throw new IOException("Bad import header line: " + header); - } - String type = tab[0]; - String ref = tab[1]; - - stream.nextAll(); - - link = map.containsKey(ref); - if (link) { - me = map.get(ref); - stream.end(); - } else { - if (stream.eof()) { - // construct - me = SerialUtils.createObject(type); - } else { - // direct value - me = SerialUtils.decode(stream); - } - map.put(ref, me); - } - } finally { - stream.close(false); - } - - return false; - } - - if (SerialUtils.isDirectValue(in)) { - // not a field value but a direct value - me = SerialUtils.decode(in); - return false; - } - - if (in.startsWith("^")) { - in.skip(1); - - NextableInputStream nameThenContent = new NextableInputStream(in, - new NextableInputStreamStep(':')); - - try { - nameThenContent.next(); - String fieldName = IOUtils.readSmallStream(nameThenContent); - - if (nameThenContent.nextAll() && !nameThenContent.eof()) { - // field value is direct or custom - Object value = null; - value = SerialUtils.decode(nameThenContent); - - // To support simple types directly: - if (me == null) { - me = value; - } else { - setField(fieldName, value); - } - } else { - // field value is compound - currentFieldName = fieldName; - } - } finally { - nameThenContent.close(false); - } - - return false; - } - - String line = IOUtils.readSmallStream(in); - throw new IOException("Line cannot be processed: <" + line + ">"); - } - - private void setField(String name, Object value) - throws NoSuchFieldException { - - try { - Field field = me.getClass().getDeclaredField(name); - - field.setAccessible(true); - field.set(me, value); - } catch (NoSuchFieldException e) { - throw new NoSuchFieldException(String.format( - "Field \"%s\" was not found in object of type \"%s\".", - name, me.getClass().getCanonicalName())); - } catch (Exception e) { - throw new NoSuchFieldException(String.format( - "Internal error when setting \"%s.%s\": %s", me.getClass() - .getCanonicalName(), name, e.getMessage())); - } - } - - /** - * Return the current deserialised value. - * - * @return the current value - */ - public Object getValue() { - return me; - } -} \ No newline at end of file