All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.document.serialization.XmlDocumentWriter Maven / Gradle / Ivy

There is a newer version: 8.498.26
Show newest version
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.document.serialization;

import com.yahoo.document.Document;
import com.yahoo.document.DocumentId;
import com.yahoo.document.DocumentType;
import com.yahoo.document.Field;
import com.yahoo.document.annotation.AnnotationReference;
import com.yahoo.document.datatypes.Array;
import com.yahoo.document.datatypes.BoolFieldValue;
import com.yahoo.document.datatypes.ByteFieldValue;
import com.yahoo.document.datatypes.CollectionFieldValue;
import com.yahoo.document.datatypes.DoubleFieldValue;
import com.yahoo.document.datatypes.FieldValue;
import com.yahoo.document.datatypes.FloatFieldValue;
import com.yahoo.document.datatypes.IntegerFieldValue;
import com.yahoo.document.datatypes.LongFieldValue;
import com.yahoo.document.datatypes.MapFieldValue;
import com.yahoo.document.datatypes.PredicateFieldValue;
import com.yahoo.document.datatypes.Raw;
import com.yahoo.document.datatypes.ReferenceFieldValue;
import com.yahoo.document.datatypes.StringFieldValue;
import com.yahoo.document.datatypes.Struct;
import com.yahoo.document.datatypes.StructuredFieldValue;
import com.yahoo.document.datatypes.TensorFieldValue;
import com.yahoo.document.datatypes.WeightedSet;
import com.yahoo.vespa.objects.FieldBase;
import com.yahoo.vespa.objects.Serializer;

import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;

// TODO: Just inline all use of XmlSerializationHelper when the toXml methods in FieldValue subclasses are to be removed
// TODO: More cleanup, the put() methods generate a lot of superfluous objects (write should call put, not the other way around)
// TODO: remove pingpong between XmlSerializationHelper and FieldValue, this will go away when the toXml methods go away
/**
 * Render a Document instance as XML.
 *
 * @author Steinar Knutsen
 */
public final class XmlDocumentWriter implements DocumentWriter {

    private final String indent;
    private XmlStream buffer;
    private final Deque optionalWrapperMarker = new ArrayDeque<>();

    public static XmlDocumentWriter createWriter(String indent) {
        return new XmlDocumentWriter(indent);
    }

    public XmlDocumentWriter() {
        this("  ");
    }

    private XmlDocumentWriter(String indent) {
        this.indent = indent;
    }

    // this method is silly, what is the intended way of doing this?
    @Override
    public void write(FieldBase field, FieldValue value) {
        Class valueType = value.getClass();
        if (valueType == AnnotationReference.class) {
            write(field, (AnnotationReference) value);
        } else if (valueType == Array.class) {
            write(field, (Array) value);
        } else if (valueType == WeightedSet.class) {
            write(field, (WeightedSet) value);
        } else if (valueType == Document.class) {
            write(field, (Document) value);
        } else if (valueType == Struct.class) {
            write(field, (Struct) value);
        } else if (valueType == ByteFieldValue.class) {
            write(field, (ByteFieldValue) value);
        } else if (valueType == DoubleFieldValue.class) {
            write(field, (DoubleFieldValue) value);
        } else if (valueType == FloatFieldValue.class) {
            write(field, (FloatFieldValue) value);
        } else if (valueType == IntegerFieldValue.class) {
            write(field, (IntegerFieldValue) value);
        } else if (valueType == LongFieldValue.class) {
            write(field, (LongFieldValue) value);
        } else if (valueType == Raw.class) {
            write(field, (Raw) value);
        } else if (valueType == PredicateFieldValue.class) {
            write(field, (PredicateFieldValue) value);
        } else if (valueType == StringFieldValue.class) {
            write(field, (StringFieldValue) value);
        } else {
            throw new UnsupportedOperationException("Cannot serialize a "
                    + valueType.getName());
        }
    }

    @Override
    public void write(FieldBase field, Document value) {
        buffer.beginTag("document");
        buffer.addAttribute("documenttype", value.getDataType().getName());
        buffer.addAttribute("documentid", value.getId());
        final java.lang.Long lastModified = value.getLastModified();
        if (lastModified != null) {
            buffer.addAttribute("lastmodifiedtime", lastModified);
        }
        StructuredFieldValue asStructured = value;
        write(null, asStructured);

        buffer.endTag();
    }

    @Override
    public  void write(FieldBase field, Array value) {
        buffer.beginTag(field.getName());
        XmlSerializationHelper.printArrayXml(value, buffer);
        buffer.endTag();
    }

    private void singleValueTag(FieldBase field, FieldValue value) {
        buffer.beginTag(field.getName());
        value.printXml(buffer);
        buffer.endTag();
    }

    @Override
    public  void write(FieldBase field, MapFieldValue map) {
        // TODO Auto-generated method stub
        buffer.beginTag(field.getName());
        XmlSerializationHelper.printMapXml(map, buffer);
        buffer.endTag();
    }

    @Override
    public void write(FieldBase field, ByteFieldValue value) {
        singleValueTag(field, value);
    }

    @Override
    public void write(FieldBase field, BoolFieldValue value) {
        singleValueTag(field, value);
    }

    @Override
    public  void write(FieldBase field,
            CollectionFieldValue value) {
        buffer.beginTag(field.getName());
        for (@SuppressWarnings("unchecked")
        Iterator i = (Iterator) value.iterator();
                i.hasNext();) {
            buffer.beginTag("item");
            i.next().printXml(buffer);
            buffer.endTag();
        }
        buffer.endTag();
    }

    @Override
    public void write(FieldBase field, DoubleFieldValue value) {
        singleValueTag(field, value);
    }

    @Override
    public void write(FieldBase field, FloatFieldValue value) {
        singleValueTag(field, value);
    }

    @Override
    public void write(FieldBase field, IntegerFieldValue value) {
        singleValueTag(field, value);
    }

    @Override
    public void write(FieldBase field, LongFieldValue value) {
        singleValueTag(field, value);
    }

    @Override
    public void write(FieldBase field, Raw value) {
        buffer.beginTag(field.getName());
        XmlSerializationHelper.printRawXml(value, buffer);
        buffer.endTag();
    }

    @Override
    public void write(FieldBase field, PredicateFieldValue value) {
        singleValueTag(field, value);
    }

    @Override
    public void write(FieldBase field, StringFieldValue value) {
        buffer.beginTag(field.getName());
        XmlSerializationHelper.printStringXml(value, buffer);
        buffer.endTag();
    }

    @Override
    public void write(FieldBase field, TensorFieldValue value) {
        throw new IllegalArgumentException("write() for tensor field value not implemented yet");
    }

    @Override
    public void write(FieldBase field, ReferenceFieldValue value) {
        throw new IllegalArgumentException("write() for reference field value not implemented yet");
    }

    private void optionalWrapperStart(FieldBase field) {
        if (field == null) {
            return;
        }

        optionalWrapperMarker.addFirst(field);

        buffer.beginTag(field.getName());
    }

    private void optionalWrapperEnd(FieldBase field) {
        if (field == null) {
            return;
        }

        if (optionalWrapperMarker.removeFirst() != field) {
            throw new IllegalStateException("Unbalanced optional wrapper tags.");
        }

        buffer.endTag();
    }

    @Override
    public void write(FieldBase field, Struct value) {
        StructuredFieldValue asStructured = value;
        write(field, asStructured);
    }

    @Override
    public void write(FieldBase field, StructuredFieldValue value) {
        optionalWrapperStart(field);
        Iterator> i = value.iterator();
        while (i.hasNext()) {
            Map.Entry v = i.next();
            buffer.beginTag(v.getKey().getName());
            v.getValue().printXml(buffer);
            buffer.endTag();
        }
        optionalWrapperEnd(field);
    }

    @Override
    public  void write(FieldBase field,
            WeightedSet value) {
        buffer.beginTag(field.getName());
        XmlSerializationHelper.printWeightedSetXml(value, buffer);
        buffer.endTag();
    }

    @Override
    public void write(FieldBase field, AnnotationReference value) {
        // TODO Auto-generated method stub

    }

    @Override
    public Serializer putByte(FieldBase field, byte value) {
        singleValueTag(field, new ByteFieldValue(value));
        return this;
    }

    @Override
    public Serializer putShort(FieldBase field, short value) {
        singleValueTag(field, new IntegerFieldValue(value));
        return this;
    }

    @Override
    public Serializer putInt(FieldBase field, int value) {
        singleValueTag(field, new IntegerFieldValue(value));
        return this;
    }

    @Override
    public Serializer putLong(FieldBase field, long value) {
        singleValueTag(field, new LongFieldValue(value));
        return this;
    }

    @Override
    public Serializer putFloat(FieldBase field, float value) {
        singleValueTag(field, new FloatFieldValue(value));
        return this;
    }

    @Override
    public Serializer putDouble(FieldBase field, double value) {
        singleValueTag(field, new DoubleFieldValue(value));
        return this;
    }

    @Override
    public Serializer put(FieldBase field, byte[] value) {
        write(field, new Raw(value));
        return this;
    }

    @Override
    public Serializer put(FieldBase field, ByteBuffer value) {
        write(field, new Raw(value));
        return this;
    }

    @Override
    public Serializer put(FieldBase field, String value) {
        write(field, new StringFieldValue(value));
        return this;
    }

    @Override
    public void write(Document document) {
        buffer = new XmlStream();
        buffer.setIndent(indent);
        optionalWrapperMarker.clear();
        write(new Field(document.getDataType().getName(), 0, document.getDataType()), document);
    }

    @Override
    public void write(DocumentId id) {
        throw new UnsupportedOperationException("Writing a DocumentId as XML is not implemented.");
    }

    @Override
    public void write(DocumentType type) {
        throw new UnsupportedOperationException("Writing a DocumentId as XML is not implemented.");

    }

    public String lastRendered() {
        return buffer.toString();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy