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

com.yahoo.vespaxmlparser.VespaXMLUpdateReader Maven / Gradle / Ivy

There is a newer version: 8.441.21
Show newest version
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespaxmlparser;

import com.yahoo.document.ArrayDataType;
import com.yahoo.document.DataType;
import com.yahoo.document.DocumentId;
import com.yahoo.document.DocumentType;
import com.yahoo.document.DocumentTypeManager;
import com.yahoo.document.DocumentUpdate;
import com.yahoo.document.Field;
import com.yahoo.document.FieldPath;
import com.yahoo.document.MapDataType;
import com.yahoo.document.NumericDataType;
import com.yahoo.document.WeightedSetDataType;
import com.yahoo.document.datatypes.Array;
import com.yahoo.document.datatypes.FieldValue;
import com.yahoo.document.datatypes.IntegerFieldValue;
import com.yahoo.document.datatypes.WeightedSet;
import com.yahoo.document.fieldpathupdate.AddFieldPathUpdate;
import com.yahoo.document.fieldpathupdate.AssignFieldPathUpdate;
import com.yahoo.document.fieldpathupdate.FieldPathUpdate;
import com.yahoo.document.fieldpathupdate.RemoveFieldPathUpdate;
import com.yahoo.document.select.parser.ParseException;
import com.yahoo.document.serialization.DocumentUpdateReader;
import com.yahoo.document.update.FieldUpdate;
import com.yahoo.document.update.ValueUpdate;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.InputStream;
import java.util.List;
import java.util.Optional;

public class VespaXMLUpdateReader extends VespaXMLFieldReader implements DocumentUpdateReader {
    public VespaXMLUpdateReader(String fileName, DocumentTypeManager docTypeManager) throws Exception {
        super(fileName, docTypeManager);
    }

    public VespaXMLUpdateReader(InputStream stream, DocumentTypeManager docTypeManager) throws Exception {
        super(stream, docTypeManager);
    }

    public VespaXMLUpdateReader(XMLStreamReader reader, DocumentTypeManager docTypeManager) {
        super(reader, docTypeManager);
    }

    private Optional condition = Optional.empty();

    public Optional getCondition() {
        return condition;
    }

    public boolean hasFieldPath() {
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if (reader.getAttributeName(i).toString().equals("fieldpath")) {
                return true;
            }
        }

        return false;
    }

    public void read(DocumentUpdate update) {
       try {
           // First fetch attributes.
           DocumentType doctype = null;

           for (int i = 0; i < reader.getAttributeCount(); i++) {
               final String attributeName = reader.getAttributeName(i).toString();
               final String attributeValue = reader.getAttributeValue(i);

               if ("documentid".equals(attributeName) || "id".equals(attributeName)) {
                   update.setId(new DocumentId(attributeValue));
               } else if ("documenttype".equals(attributeName) || "type".equals(attributeName)) {
                   doctype = docTypeManager.getDocumentType(attributeValue);
                   update.setDocumentType(doctype);
               } else if ("create-if-non-existent".equals(attributeName)) {
                   if ("true".equals(attributeValue)) {
                       update.setCreateIfNonExistent(true);
                   } else if ("false".equals(attributeValue)) {
                       update.setCreateIfNonExistent(false);
                   } else {
                       throw newDeserializeException("'create-if-non-existent' must be either 'true' or 'false', was '" + attributeValue +"'");
                   }
               } else if ("condition".equals(attributeName)) {
                   condition = Optional.of(attributeValue);
               }
           }

           if (doctype == null) {
               throw newDeserializeException("Must specify document type. " + reader.getLocation());
           }

           // Then fetch fields
           while (reader.hasNext()) {
               int type = reader.next();

               if (type == XMLStreamReader.START_ELEMENT) {
                   final String currentName = reader.getName().toString();
                   if (hasFieldPath()) {
                       if ("assign".equals(currentName)) {
                           update.addFieldPathUpdate(new AssignFieldPathUpdate(doctype, this));
                           skipToEnd("assign");
                       } else if ("add".equals(currentName)) {
                           update.addFieldPathUpdate(new AddFieldPathUpdate(doctype, this));
                           skipToEnd("add");
                       } else if ("remove".equals(currentName)) {
                           update.addFieldPathUpdate(new RemoveFieldPathUpdate(doctype, this));
                           skipToEnd("remove");
                       } else {
                           throw newDeserializeException("Unknown field path update operation " + reader.getName());
                       }
                   } else {
                       if ("assign".equals(currentName)) {
                           update.addFieldUpdate(readAssign(update));
                           skipToEnd("assign");
                       } else if ("add".equals(currentName)) {
                           update.addFieldUpdate(readAdd(update));
                           skipToEnd("add");
                       } else if ("remove".equals(currentName)) {
                           update.addFieldUpdate(readRemove(update));
                           skipToEnd("remove");
                       } else if ("alter".equals(currentName)) {
                           update.addFieldUpdate(readAlter(update));
                           skipToEnd("alter");
                       } else if ("increment".equals(currentName) ||
                               "decrement".equals(currentName) ||
                               "multiply".equals(currentName) ||
                               "divide".equals(currentName)) {
                           update.addFieldUpdate(readArithmeticField(update, currentName));
                           skipToEnd(currentName);
                       } else {
                           throw newDeserializeException("Unknown update operation " + reader.getName());
                       }
                   }
               } else if (type == XMLStreamReader.END_ELEMENT) {
                   return;
               }
           }
       } catch (XMLStreamException e) {
           throw newException(e);
       }
    }

    FieldUpdate readAdd(DocumentUpdate update) throws XMLStreamException {
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if ("field".equals(reader.getAttributeName(i).toString())) {
                Field f = update.getDocumentType().getField(reader.getAttributeValue(i));

                FieldValue value = f.getDataType().createFieldValue();
                value.deserialize(f, this);

                if (value instanceof Array) {
                    List l = ((Array)value).getValues();
                    return FieldUpdate.createAddAll(f, l);
                } else if (value instanceof WeightedSet) {
                    return FieldUpdate.createAddAll(f, ((WeightedSet) value));
                } else {
                    throw newDeserializeException("Add operation only applicable to multivalue lists");
                }

            }
        }
        throw newDeserializeException("Add update without field attribute");
    }


    FieldUpdate readRemove(DocumentUpdate update) throws XMLStreamException {
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if ("field".equals(reader.getAttributeName(i).toString())) {
                Field f = update.getDocumentType().getField(reader.getAttributeValue(i));

                FieldValue value = f.getDataType().createFieldValue();
                value.deserialize(f, this);

                if (value instanceof Array) {
                    List l = ((Array)value).getValues();
                    return FieldUpdate.createRemoveAll(f, l);
                } else if (value instanceof WeightedSet) {
                    return FieldUpdate.createRemoveAll(f, ((WeightedSet)value));
                } else {
                    throw newDeserializeException("Remove operation only applicable to multivalue lists");
                }

            }
        }
        throw newDeserializeException("Remove update without field attribute");
    }

    FieldUpdate readAssign(DocumentUpdate update) throws XMLStreamException {
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if ("field".equals(reader.getAttributeName(i).toString())) {
                Field f = update.getDocumentType().getField(reader.getAttributeValue(i));

                if (f == null) {
                    throw newDeserializeException("Field " + reader.getAttributeValue(i) + " not found.");
                }

                FieldValue value = f.getDataType().createFieldValue();
                value.deserialize(f, this);
                return FieldUpdate.createAssign(f, value);
            }
        }
        throw newDeserializeException("Assignment update without field attribute");
    }


    FieldUpdate readAlter(DocumentUpdate update) throws XMLStreamException {
        Field f = null;
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if ("field".equals(reader.getAttributeName(i).toString())) {
                f = update.getDocumentType().getField(reader.getAttributeValue(i));
            }
        }

        if (f == null) {
            throw newDeserializeException("Alter update without \"field\" attribute");
        }

        FieldUpdate fu = FieldUpdate.create(f);

        while (reader.hasNext()) {
            int type = reader.next();
            if (type == XMLStreamReader.START_ELEMENT) {
                if ("increment".equals(reader.getName().toString()) ||
                    "decrement".equals(reader.getName().toString()) ||
                    "multiply".equals(reader.getName().toString()) ||
                    "divide".equals(reader.getName().toString())) {
                    update.addFieldUpdate(readArithmetic(update, reader.getName().toString(), f, fu));
                    skipToEnd(reader.getName().toString());
                } else {
                    throw newDeserializeException("Element \"" + reader.getName() + "\" not appropriate within alter element");
                }
            } else if (type == XMLStreamReader.END_ELEMENT) {
                break;
            }
        }

        return fu;
    }

    FieldUpdate readArithmeticField(DocumentUpdate update, String type) throws XMLStreamException {
        Field f = null;
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if ("field".equals(reader.getAttributeName(i).toString())) {
                f = update.getDocumentType().getField(reader.getAttributeValue(i));
            }
        }

        if (f == null) {
            throw newDeserializeException("Assignment update without \"field\" attribute");
        }

        FieldUpdate fu = FieldUpdate.create(f);
        readArithmetic(update, type, f, fu);
        return fu;
    }

    FieldUpdate readArithmetic(DocumentUpdate update, String type, Field f, FieldUpdate fu) throws XMLStreamException {
        Double by = null;

        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if ("by".equals(reader.getAttributeName(i).toString())) {
                by = Double.parseDouble(reader.getAttributeValue(i));
            }
        }

        if (by == null) {
            throw newDeserializeException("Assignment update without \"by\" attribute");
        }

        FieldValue key = null;
        do {
            reader.next();
            if (reader.getEventType() == XMLStreamReader.START_ELEMENT) {
                if ("key".equals(reader.getName().toString())) {
                    if (f.getDataType() instanceof WeightedSetDataType) {
                        DataType nestedType = ((WeightedSetDataType)f.getDataType()).getNestedType();
                        key = nestedType.createFieldValue();
                        key.deserialize(this);
                    } else if (f.getDataType() instanceof MapDataType) {
                        key = ((MapDataType)f.getDataType()).getKeyType().createFieldValue();
                        key.deserialize(this);
                    } else if (f.getDataType() instanceof ArrayDataType) {
                        key = new IntegerFieldValue(Integer.parseInt(reader.getElementText()));
                    } else {
                        throw newDeserializeException("Key tag only applicable for weighted sets and maps");
                    }
                    skipToEnd("key");
                } else {
                    throw newDeserializeException("\"" + reader.getName() + "\" not appropriate within " + type + " element.");
                }
            }
        } while (reader.getEventType() != XMLStreamReader.END_ELEMENT);

        if (key != null) {
            if ("increment".equals(type)) { fu.addValueUpdate(ValueUpdate.createIncrement(key, by)); }
            if ("decrement".equals(type)) { fu.addValueUpdate(ValueUpdate.createDecrement(key, by)); }
            if ("multiply".equals(type)) { fu.addValueUpdate(ValueUpdate.createMultiply(key, by)); }
            if ("divide".equals(type)) { fu.addValueUpdate(ValueUpdate.createDivide(key, by)); }
        } else {
            if ("increment".equals(type)) { fu.addValueUpdate(ValueUpdate.createIncrement(by)); }
            if ("decrement".equals(type)) { fu.addValueUpdate(ValueUpdate.createDecrement(by)); }
            if ("multiply".equals(type)) { fu.addValueUpdate(ValueUpdate.createMultiply(by)); }
            if ("divide".equals(type)) { fu.addValueUpdate(ValueUpdate.createDivide(by)); }
        }

        return fu;
    }

    public void read(FieldUpdate update) {
    }

    public void read(FieldPathUpdate update) {
        String whereClause = null;
        String fieldPath = null;

        for (int i = 0; i < reader.getAttributeCount(); i++) {
            if (reader.getAttributeName(i).toString().equals("where")) {
                whereClause = reader.getAttributeValue(i);
            } else if (reader.getAttributeName(i).toString().equals("fieldpath")) {
                fieldPath = reader.getAttributeValue(i);
            }
        }

        if (fieldPath != null) {
            update.setFieldPath(fieldPath);
        } else {
            throw newDeserializeException("Field path is required for document updates.");
        }

        if (whereClause != null) {
            try {
                update.setWhereClause(whereClause);
            } catch (ParseException e) {
                throw newException(e);
            }
        }
    }

    public void read(AssignFieldPathUpdate update) {
        try {
            for (int i = 0; i < reader.getAttributeCount(); i++) {
                if (reader.getAttributeName(i).toString().equals("removeifzero")) {
                    update.setRemoveIfZero(Boolean.parseBoolean(reader.getAttributeValue(i)));
                } else if (reader.getAttributeName(i).toString().equals("createmissingpath")) {
                    update.setCreateMissingPath(Boolean.parseBoolean(reader.getAttributeValue(i)));
                }
            }
            DataType dt = update.getFieldPath().getResultingDataType();

            if (dt instanceof NumericDataType) {
                update.setExpression(reader.getElementText());
            } else {
                FieldValue fv = dt.createFieldValue();
                fv.deserialize(resolveField(update), this);
                update.setNewValue(fv);
            }
        } catch (XMLStreamException e) {
            throw newException(e);
        }
    }

    public void read(AddFieldPathUpdate update) {
        DataType dt = update.getFieldPath().getResultingDataType();
        FieldValue fv = dt.createFieldValue();
        fv.deserialize(resolveField(update), this);
        update.setNewValues((Array)fv);
    }

    public void read(RemoveFieldPathUpdate update) {
    }

    private static Field resolveField(FieldPathUpdate update) {
        String orig = update.getOriginalFieldPath();
        if (orig == null) {
            return null;
        }
        FieldPath path = update.getFieldPath();
        if (path == null) {
            return null;
        }
        DataType type = path.getResultingDataType();
        if (type == null) {
            return null;
        }
        return new Field(orig, type);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy