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

net.n2oapp.framework.config.io.IOProcessorImpl Maven / Gradle / Ivy

The newest version!
package net.n2oapp.framework.config.io;

import net.n2oapp.framework.api.N2oNamespace;
import net.n2oapp.framework.api.StringUtils;
import net.n2oapp.framework.api.data.DomainProcessor;
import net.n2oapp.framework.api.exception.N2oException;
import net.n2oapp.framework.api.metadata.aware.IdAware;
import net.n2oapp.framework.api.metadata.aware.NamespaceUriAware;
import net.n2oapp.framework.api.metadata.io.*;
import net.n2oapp.framework.api.metadata.persister.NamespacePersister;
import net.n2oapp.framework.api.metadata.persister.NamespacePersisterFactory;
import net.n2oapp.framework.api.metadata.persister.TypedElementPersister;
import net.n2oapp.framework.api.metadata.reader.NamespaceReader;
import net.n2oapp.framework.api.metadata.reader.NamespaceReaderFactory;
import net.n2oapp.framework.api.metadata.reader.TypedElementReader;
import org.apache.commons.lang3.ArrayUtils;
import org.jdom2.Attribute;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.core.env.PropertyResolver;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.springframework.util.StringUtils.hasText;

/**
 * Реализация процессора считывания и записи DOM элементов
 */
public final class IOProcessorImpl implements IOProcessor {

    /**
     * Если true, то чтение, false запись
     */
    private final boolean r;
    private NamespaceReaderFactory readerFactory;
    private NamespacePersisterFactory persisterFactory;
    private MessageSourceAccessor messageSourceAccessor;
    private PropertyResolver systemProperties;
    private boolean failFast = true;
    private final DomainProcessor domainProcessor = new DomainProcessor();

    public IOProcessorImpl(boolean read) {
        this.r = read;
    }

    public IOProcessorImpl(NamespaceReaderFactory readerFactory) {
        this.r = true;
        this.readerFactory = readerFactory;
        if (readerFactory instanceof IOProcessorAware)
            ((IOProcessorAware) readerFactory).setIOProcessor(this);
    }

    public IOProcessorImpl(NamespacePersisterFactory persisterFactory) {
        this.r = false;
        this.persisterFactory = persisterFactory;
        if (persisterFactory instanceof IOProcessorAware)
            ((IOProcessorAware) persisterFactory).setIOProcessor(this);
    }

    @Override
    public  void read(Element element, T entity, BiConsumer reader) {
        if (r) {
            reader.accept(element, entity);
        }
    }

    @Override
    public  void persist(T entity, Element element, BiConsumer persister) {
        if (!r) {
            persister.accept(entity, element);
        }
    }

    @Override
    public  void child(Element element, String sequences, String childName,
                          Supplier getter, Consumer setter,
                          TypedElementIO io) {
        if (r) {
            Element child;
            if (sequences != null) {
                child = element.getChild(sequences, element.getNamespace());
                if (child == null)
                    return;
            } else {
                child = element;
            }
            child = child.getChild(childName, element.getNamespace());
            if (child != null) {
                setter.accept(read(io, child));
            }
        } else {
            T entity = getter.get();
            if (entity != null) {
                Element seqE = element;
                if (sequences != null) {
                    seqE = initSequenceElement(element, sequences);
                }
                Element childE = persist(io, entity, element.getNamespace());
                installNamespace(childE, element.getNamespace());
                seqE.addContent(childE);
            }
        }
    }

    @Override
    public  void child(Element element, String sequences, String childName,
                          Supplier getter, Consumer setter,
                          Class elementClass, ElementIO io) {
        child(element, sequences, childName, getter, setter, new TypedElementIO() {
            @Override
            public Class getElementClass() {
                return elementClass;
            }

            @Override
            public void io(Element e, T t, IOProcessor p) {
                io.io(e, t, p);
            }

            @Override
            public String getElementName() {
                return childName;
            }
        });
    }

    @Override
    public  void child(Element element, String sequences, String childName,
                          Supplier getter, Consumer setter,
                          Supplier newInstance, ElementIO io) {
        child(element, sequences, childName, getter, setter, new TypedElementIO() {
            private Class elementClass;

            @Override
            public String getElementName() {
                return childName;
            }

            @Override
            public Class getElementClass() {
                if (elementClass == null)
                    throw new IllegalStateException("you shall first to call #newInstance(Element)");
                return elementClass;
            }

            @Override
            public T newInstance(Element element) {
                T entity = newInstance.get();
                if (elementClass == null)
                    elementClass = (Class) entity.getClass();
                return entity;
            }

            @Override
            public void io(Element e, T t, IOProcessor p) {
                io.io(e, t, p);
            }
        });
    }

    @Override
    public ,
            P extends TypedElementPersister> void anyChild(Element element, String sequences,
                                                                      Supplier getter, Consumer setter,
                                                                      ElementIOFactory factory) {
        if (r) {
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren()) {
                Element childE = (Element) child;
                setter.accept(read(factory, childE));
            }
        } else {
            T entity = getter.get();
            if (entity == null) return;
            Element seqE;
            if (sequences != null) {
                seqE = initSequenceElement(element, sequences);
            } else {
                seqE = element;
            }
            Element childE = persist(factory, entity, element.getNamespace());
            if (childE != null) {
                installNamespace(childE, element.getNamespace());
                seqE.addContent(childE);
            }
        }
    }

    @Override
    public ,
            P extends NamespacePersister> void anyChild(Element element, String sequences,
                                                                   Supplier getter, Consumer setter,
                                                                   NamespaceIOFactory factory,
                                                                   Namespace defaultNamespace) {
        if (r) {
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren()) {
                Element childE = (Element) child;
                T childT = read(factory, childE, seqE.getNamespace(), defaultNamespace);
                if (childT != null) {
                    setter.accept(childT);
                    return;
                }
            }
        } else {
            T entity = getter.get();
            if (entity == null) return;
            Element seqE;
            if (sequences != null) {
                seqE = initSequenceElement(element, sequences);
            } else {
                seqE = element;
            }
            Element childE = persist(factory, entity, seqE.getNamespace(), defaultNamespace);
            if (childE != null) {
                installNamespace(childE, element.getNamespace());
                seqE.addContent(childE);
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public  void children(Element element, String sequences, String childrenName,
                             Supplier getter, Consumer setter,
                             TypedElementIO io) {
        if (r) {
            List result = new ArrayList<>();
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren(childrenName, seqE.getNamespace())) {
                Element childE = (Element) child;
                T entity = read(io, childE);
                result.add(entity);
            }
            if (result.size() > 0) {
                T[] res = (T[]) Array.newInstance(io.getElementClass(), result.size());
                res = result.toArray(res);
                setter.accept(res);
            }
        } else {
            T[] entity = getter.get();
            if (entity == null) return;
            Element seqE;
            if (sequences != null) {
                seqE = initSequenceElement(element, sequences);
            } else {
                seqE = element;
            }
            for (T child : entity) {
                Element childE = persist(io, child, seqE.getNamespace());
                installNamespace(childE, seqE.getNamespace());
                seqE.addContent(childE);
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void childrenToMap(Element element, String sequences, String childrenName,
                              String keyName, String valueName,
                              Supplier> getter, Consumer> setter) {
        if (r) {
            Map result = new HashMap<>();
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren(childrenName, seqE.getNamespace())) {
                Element childE = (Element) child;
                String key = process(childE.getAttribute(keyName).getValue());
                String value = valueName == null ?
                        childE.getValue() :
                        childE.getAttribute(valueName).getValue();
                Object objValue = domainProcessor.deserialize(value, (String) null);
                result.put(key, objValue);
            }
            setter.accept(result);
        } else {
            persistChildrenMap(element, sequences, childrenName, keyName, valueName, getter);
        }
    }

    @Override
    public void childrenAttributesToMap(Element element, String sequences, String childrenName,
                                        Supplier> getter, Consumer> setter) {
        if (r) {
            Map result = new HashMap<>();
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren(childrenName, seqE.getNamespace())) {
                Element childE = (Element) child;
                Attribute attribute = childE.getAttributes().get(0);
                String key = attribute.getName();
                String value = attribute.getValue();
                Object objValue = domainProcessor.deserialize(value);
                result.put(key, objValue);
            }
            setter.accept(result);
        } else {
            Map values = getter.get();
            if (values == null) return;
            Element seqE;
            seqE = persistSequences(element, sequences);
            for (String k : values.keySet()) {
                Element childE = new Element(childrenName, element.getNamespace());
                childE.setAttribute(k, values.get(k).toString());
                seqE.addContent(childE);
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void childrenToStringMap(Element element, String sequences, String childrenName,
                                    String keyName, String valueName,
                                    Supplier> getter, Consumer> setter) {
        if (r) {
            Map result = new HashMap<>();
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren(childrenName, seqE.getNamespace())) {
                Element childE = (Element) child;
                String key = null;
                if (childE.getAttribute(keyName) != null)
                    key = process(childE.getAttribute(keyName).getValue());

                String value = valueName == null ?
                        childE.getValue() :
                        childE.getAttribute(valueName).getValue();
                result.put(key, value);
            }
            setter.accept(result);
        } else {
            persistChildrenMap(element, sequences, childrenName, keyName, valueName, getter);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void childrenToStringArray(Element element, String sequences, String childrenName,
                                      Supplier getter, Consumer setter) {
        if (r) {
            List result = new ArrayList<>();
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren(childrenName, seqE.getNamespace())) {
                Element childE = (Element) child;
                String value = process(childE.getValue());
                result.add(value);
            }
            if (!result.isEmpty()) {
                String[] res = new String[result.size()];
                setter.accept(result.toArray(res));
            }
        } else {
            String[] values = getter.get();
            if (values == null) return;
            Element seqE;
            seqE = persistSequences(element, sequences);
            for (String k : values) {
                Element childE = new Element(childrenName, element.getNamespace());
                childE.setText(k);
                seqE.addContent(childE);
            }
        }
    }

    private Element persistSequences(Element element, String sequences) {
        Element seqE;
        if (sequences != null) {
            seqE = initSequenceElement(element, sequences);
        } else {
            seqE = element;
        }
        return seqE;
    }

    private  void persistChildrenMap(Element element, String sequences, String childrenName,
                                        String keyName, String valueName,
                                        Supplier> getter) {
        Map values = getter.get();
        if (values == null) return;
        Element seqE;
        seqE = persistSequences(element, sequences);
        for (String k : values.keySet()) {
            Element childE = new Element(childrenName, element.getNamespace());
            childE.setAttribute(keyName, k);
            if (valueName == null) {
                childE.setText(values.get(k).toString());
            } else {
                if (values.get(k) != null) {
                    childE.setAttribute(valueName, values.get(k).toString());
                }
            }
            seqE.addContent(childE);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public  void children(Element element, String sequences, String childrenName,
                             Supplier getter, Consumer setter,
                             Class elementClass, ElementIO io) {
        children(element, sequences, childrenName, getter, setter, new TypedElementIO() {
            @Override
            public String getElementName() {
                return childrenName;
            }

            @Override
            public Class getElementClass() {
                return elementClass;
            }

            @Override
            public void io(Element e, T t, IOProcessor p) {
                io.io(e, t, p);
            }
        });

    }

    @Override
    @SuppressWarnings("unchecked")
    public  void children(Element element, String sequences, String childrenName,
                             Supplier getter, Consumer setter,
                             Supplier newInstance, ElementIO io) {
        children(element, sequences, childrenName, getter, setter, new TypedElementIO() {
            private Class elementClass;

            @Override
            public String getElementName() {
                return childrenName;
            }

            @Override
            public Class getElementClass() {
                if (elementClass == null)
                    throw new IllegalStateException("you shall first to call #newInstance(Element)");
                return elementClass;
            }

            @Override
            public T newInstance(Element element) {
                T entity = newInstance.get();
                if (elementClass == null)
                    elementClass = (Class) entity.getClass();
                return entity;
            }

            @Override
            public void io(Element e, T t, IOProcessor p) {
                io.io(e, t, p);
            }
        });

    }

    @Override
    public ,
            P extends TypedElementPersister> void anyChildren(Element element, String sequences,
                                                                         Supplier getter, Consumer setter,
                                                                         ElementIOFactory factory) {
        if (r) {
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            List result = new ArrayList<>();
            for (Object child : seqE.getChildren()) {
                Element childE = (Element) child;
                T childT = read(factory, childE);
                if (childT != null) {
                    result.add(childT);
                }
            }
            @SuppressWarnings("unchecked") T[] res = (T[]) Array.newInstance(factory.getBaseElementClass(), result.size());
            res = result.toArray(res);
            setter.accept(res);
        } else {
            T[] entities = getter.get();
            if (entities == null) return;
            Element seqE;
            if (sequences != null) {
                seqE = initSequenceElement(element, sequences);
            } else {
                seqE = element;
            }
            for (T child : entities) {
                Element childE = persist(factory, child, element.getNamespace());
                if (childE != null) {
                    installNamespace(childE, element.getNamespace());
                    seqE.addContent(childE);
                }
            }
        }
    }

    @Override
    public ,
            P extends NamespacePersister> void anyChildren(Element element, String sequences,
                                                                      Supplier getter, Consumer setter,
                                                                      NamespaceIOFactory factory,
                                                                      Namespace... defaultNamespace) {
        if (r) {
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            List result = new ArrayList<>();
            for (Object child : seqE.getChildren()) {
                Element childE = (Element) child;
                T childT = read(factory, childE, seqE.getNamespace(), defaultNamespace);
                if (childT != null) {
                    result.add(childT);
                }
            }
            if (result.size() > 0) {
                @SuppressWarnings("unchecked") T[] res;
                if (factory.getBaseElementClass() == null) {
                    res = (T[]) Array.newInstance(NamespaceUriAware.class, result.size());
                } else {
                    res = (T[]) Array.newInstance(factory.getBaseElementClass(), result.size());
                }
                res = result.toArray(res);
                setter.accept(res);
            }
        } else {
            T[] entities = getter.get();
            if (entities == null) return;
            Element seqE;
            if (sequences != null) {
                seqE = initSequenceElement(element, sequences);
            } else {
                seqE = element;
            }
            for (T child : entities) {
                Element childE = persist(factory, child, seqE.getNamespace(), defaultNamespace);
                if (childE != null) {
                    installNamespace(childE, element.getNamespace());
                    seqE.addContent(childE);
                }
            }
        }
    }

    @Override
    public > void childrenByEnum(Element element, String sequences,
                                                      Supplier getterList, Consumer setterList,
                                                      Class enumClass, Function getterEnum, BiConsumer setterEnum,
                                                      ClassedElementIO io) {
        if (r) {
            List result = new ArrayList<>();
            Element seqE;
            if (sequences != null) {
                seqE = element.getChild(sequences, element.getNamespace());
                if (seqE == null) return;
            } else {
                seqE = element;
            }
            for (Object child : seqE.getChildren()) {
                Element childE = (Element) child;
                E en = stringToEnum(childE.getName(), enumClass);
                if (en != null) {
                    T entity = read(io, childE);
                    setterEnum.accept(entity, en);
                    result.add(entity);
                }
            }
            if (result.size() > 0) {
                T[] res = (T[]) Array.newInstance(io.getElementClass(), result.size());
                res = result.toArray(res);
                setterList.accept(res);
            }
        } else {
            T[] entity = getterList.get();
            if (entity == null) return;
            Element seqE;
            if (sequences != null) {
                seqE = initSequenceElement(element, sequences);
            } else {
                seqE = element;
            }
            for (T child : entity) {
                final E en = getterEnum.apply(child);
                Element childE = null;
                if (en != null) {
                    childE = persist(new NamedElementIO() {
                        @Override
                        public String getElementName() {
                            return en.name();
                        }

                        @Override
                        public void io(Element e, T t, IOProcessor p) {
                            io.io(e, t, p);
                        }
                    }, child, seqE.getNamespace());
                    installNamespace(childE, element.getNamespace());
                    seqE.addContent(childE);
                }
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public > void childrenByEnum(Element element, String sequences,
                                                      Supplier getterList, Consumer setterList,
                                                      Function getterEnum, BiConsumer setterEnum,
                                                      Supplier newInstance, Class enumClass, ElementIO io) {
        childrenByEnum(element, sequences, getterList, setterList, enumClass, getterEnum, setterEnum,
                new ClassedElementIO() {
                    private Class elementClass;

                    @Override
                    public Class getElementClass() {
                        if (elementClass == null)
                            throw new IllegalStateException("you shall first to call #newInstance(Element)");
                        return elementClass;
                    }

                    @Override
                    public T newInstance(Element element) {
                        T entity = newInstance.get();
                        if (elementClass == null)
                            elementClass = (Class) entity.getClass();
                        return entity;
                    }

                    @Override
                    public void io(Element e, T t, IOProcessor p) {
                        io.io(e, t, p);
                    }

                });

    }

    @Override
    public void attribute(Element element, String name, Supplier getter, Consumer setter) {
        if (r) {
            Attribute attribute = element.getAttribute(name);
            if (attribute != null) {
                setter.accept(process(attribute.getValue()));
            }
        } else {
            if (getter.get() == null) return;
            element.setAttribute(new Attribute(name, getter.get()));
        }
    }

    @Override
    public void text(Element element, Supplier getter, Consumer setter) {
        if (r) {
            String text = element.getText();
            if (text != null && !text.isEmpty()) {
                setter.accept(process(text));
            }
        } else {
            if (getter.get() == null) return;
            element.setText(getter.get());
        }
    }

    @Override
    public void childrenText(Element element, String childName, Supplier getter, Consumer setter) {
        if (r) {
            Element child = element.getChild(childName, element.getNamespace());
            if (child == null) return;
            String text = child.getText();
            if (text != null && !text.isEmpty()) {
                setter.accept(process(text));
            }
        } else {
            if (getter.get() == null) return;
            Element childElement = element.getChild(childName, element.getNamespace());
            if (childElement == null) {
                childElement = new Element(childName, element.getNamespace());
                childElement.setText(getter.get());
                element.addContent(childElement);
            } else {
                childElement.setText(getter.get());
            }
        }
    }

    @Override
    public void childAttribute(Element element, String childName, String name, Supplier getter, Consumer setter) {
        if (r) {
            Element child = element.getChild(childName, element.getNamespace());
            if (child == null) return;
            Attribute attribute = child.getAttribute(name);
            if (attribute != null) {
                setter.accept(process(attribute.getValue()));
            }
        } else {
            if (getter.get() == null) return;
            Element childElement = element.getChild(childName, element.getNamespace());
            if (childElement == null) {
                childElement = new Element(childName, element.getNamespace());
                childElement.setAttribute(new Attribute(name, getter.get()));
                element.addContent(childElement);
            } else {
                childElement.setAttribute(new Attribute(name, getter.get()));
            }
        }
    }

    @Override
    public void childAttributeBoolean(Element element, String childName, String name, Supplier getter, Consumer setter) {
        if (r) {
            Element child = element.getChild(childName, element.getNamespace());
            if (child == null) return;
            Attribute attribute = child.getAttribute(name);
            if (attribute != null) {
                setter.accept(Boolean.valueOf(process(attribute.getValue())));
            }
        } else {
            if (getter.get() == null) return;
            Element childElement = element.getChild(childName, element.getNamespace());
            if (childElement == null) {
                childElement = new Element(childName, element.getNamespace());
                childElement.setAttribute(new Attribute(name, getter.get().toString()));
                element.addContent(childElement);
            } else {
                childElement.setAttribute(new Attribute(name, getter.get().toString()));
            }
        }
    }

    @Override
    public void childAttributeInteger(Element element, String childName, String name, Supplier getter, Consumer setter) {
        if (r) {
            Element child = element.getChild(childName, element.getNamespace());
            if (child == null) return;
            Attribute attribute = child.getAttribute(name);
            if (attribute != null) {
                setter.accept(Integer.parseInt(process(attribute.getValue())));
            }
        } else {
            if (getter.get() == null) return;
            Element childElement = element.getChild(childName, element.getNamespace());
            if (childElement == null) {
                childElement = new Element(childName, element.getNamespace());
                childElement.setAttribute(new Attribute(name, getter.get().toString()));
                element.addContent(childElement);
            } else {
                childElement.setAttribute(new Attribute(name, getter.get().toString()));
            }
        }
    }

    @Override
    public > void childAttributeEnum(Element element, String childName, String name, Supplier getter, Consumer setter, Class enumClass) {
        if (r) {
            Element child = element.getChild(childName, element.getNamespace());
            if (child == null) return;
            Attribute attribute = child.getAttribute(name);
            if (attribute != null) {
                setter.accept(stringToEnum(process(attribute.getValue()), enumClass));
            }
        } else {
            if (getter.get() == null) return;
            Element childElement = element.getChild(childName, element.getNamespace());
            if (childElement == null) {
                childElement = new Element(childName, element.getNamespace());
                element.addContent(childElement);
            }

            if (IdAware.class.isAssignableFrom(enumClass))
                childElement.setAttribute(new Attribute(name, ((IdAware) getter.get()).getId()));
            else
                childElement.setAttribute(new Attribute(name, getter.get().name()));
        }
    }

    /**
     * Считать атрибуты другой схемы
     *
     * @param element   элемент
     * @param namespace схема, атрибуты которой нужно считать
     * @param map       мапа, в которую считать атрибуты схемы
     */
    @Override
    public void otherAttributes(Element element, Namespace namespace, Map map) {
        if (r) {
            for (Object o : element.getAttributes()) {
                Attribute attribute = (Attribute) o;
                if (attribute.getNamespace().equals(namespace)) {
                    if (attribute.getValue() instanceof String) {
                        map.put(attribute.getName(), process(attribute.getValue()));
                    } else {
                        map.put(attribute.getName(), attribute.getValue());
                    }
                }
            }
        } else {
            for (Map.Entry entry : map.entrySet()) {
                element.setAttribute(new Attribute(entry.getKey(), entry.getValue(), namespace));
            }
        }
    }

    @Override
    public void childAnyAttributes(Element element, String childName, Supplier>> getter, Consumer>> setter) {
        if (r) {
            Element child = element.getChild(childName, element.getNamespace());
            if (child == null) return;
            anyAttributes(child, getter, setter);
        } else {
            if (getter.get() == null) return;
            Element childElement = element.getChild(childName, element.getNamespace());
            if (childElement == null) {
                childElement = new Element(childName, element.getNamespace());
                anyAttributes(childElement, getter, setter);
                element.addContent(childElement);
            } else {
                anyAttributes(childElement, getter, setter);
            }
        }
    }

    @Override
    public void anyAttributes(Element element, Supplier>> getter,
                              Consumer>> setter) {
        if (r) {
            N2oNamespace elementNamespace = new N2oNamespace(element.getNamespace());
            Map> extensions = new HashMap<>();
            for (Object o : element.getAttributes()) {
                Attribute attribute = (Attribute) o;
                if (elementNamespace.getUri().equals(attribute.getNamespaceURI()) || attribute.getNamespaceURI().isEmpty()) {
                    continue;
                } else {
                    N2oNamespace namespace = new N2oNamespace(attribute.getNamespace());
                    extensions.putIfAbsent(namespace, new HashMap<>());
                    extensions.get(namespace).put(attribute.getName(), process(attribute.getValue()));
                }
            }
            setter.accept(extensions);
        } else {
            Map> extensions = getter.get();
            if (extensions == null)
                return;
            for (Map.Entry> map : extensions.entrySet()) {
                for (Map.Entry entry : map.getValue().entrySet()) {
                    element.setAttribute(new Attribute(entry.getKey(), entry.getValue(), Namespace.getNamespace(map.getKey().getPrefix(), map.getKey().getUri())));
                }
            }
        }
    }

    @Override
    public void attributeBoolean(Element element, String name, Supplier getter, Consumer setter) {
        if (r) {
            Attribute attribute = element.getAttribute(name);
            if (attribute != null) {
                setter.accept(Boolean.valueOf(process(attribute.getValue())));
            }
        } else {
            if (getter.get() == null) return;
            element.setAttribute(new Attribute(name, getter.get().toString()));
        }
    }

    @Override
    public void attributeInteger(Element element, String name, Supplier getter, Consumer setter) {
        if (r) {
            Attribute attribute = element.getAttribute(name);
            if (attribute != null) {
                setter.accept(Integer.valueOf(process(attribute.getValue())));
            }
        } else {
            if (getter.get() == null) return;
            element.setAttribute(new Attribute(name, getter.get().toString()));
        }
    }

    @Override
    public void attributeArray(Element element, String name, String separator, Supplier getter, Consumer setter) {
        if (r) {
            Attribute attribute = element.getAttribute(name);
            if (attribute != null) {
                String value = process(attribute.getValue());
                setter.accept(value.trim().split("\\s*" + separator + "\\s*"));
            }
        } else {
            if (getter.get() == null) return;
            StringJoiner str = new StringJoiner(",");
            for (String s : getter.get())
                str.add(s);
            element.setAttribute(new Attribute(name, str.toString()));
        }
    }

    @Override
    public > void attributeEnum(Element element, String name, Supplier getter, Consumer setter, Class enumClass) {
        if (r) {
            Attribute attribute = element.getAttribute(name);
            if (attribute != null) {
                setter.accept(stringToEnum(process(attribute.getValue()), enumClass));
            }
        } else {
            if (getter.get() == null) return;
            if (IdAware.class.isAssignableFrom(enumClass)) {
                element.setAttribute(new Attribute(name, ((IdAware) getter.get()).getId()));
            } else {
                element.setAttribute(new Attribute(name, getter.get().name()));
            }
        }
    }

    @Override
    public void element(Element element, String name, Supplier getter, Consumer setter) {
        if (r) {
            Element child = element.getChild(name, element.getNamespace());
            if (child != null && child.getValue() != null && !child.getValue().isEmpty()) {
                setter.accept(process(child.getValue()));
            }
        } else {
            if (getter.get() == null || getter.get().isEmpty()) return;
            Element childElement = element.getChild(name, element.getNamespace());
            if (childElement == null) {
                childElement = new Element(name, element.getNamespace());
                childElement.setText(getter.get());
                element.addContent(childElement);
            } else {
                childElement.setText(getter.get());
            }
        }
    }

    @Override
    public void hasElement(Element element, String name, Supplier getter, Consumer setter) {
        if (r) {
            Element child = element.getChild(name, element.getNamespace());
            setter.accept(child != null);
        } else {
            if (getter.get() == null || !getter.get()) return;
            if (element.getChild(name, element.getNamespace()) == null) {
                Element childElement = new Element(name, element.getNamespace());
                element.addContent(childElement);
            }
        }
    }

    @Override
    public , P extends TypedElementPersister> ElementIOFactory oneOf(Class baseElementClass) {
        return new ElementIOFactoryByMap<>(baseElementClass);
    }

    @Override
    public , P extends NamespacePersister> NamespaceIOFactory anyOf(Class baseElementClass) {
        return new NamespaceIOFactoryByMap<>(baseElementClass, readerFactory, persisterFactory);
    }

    @Override
    public , P extends NamespacePersister> NamespaceIOFactory anyOf() {
        return new NamespaceIOFactoryByMap<>(null, readerFactory, persisterFactory);
    }


    /**
     * Установить схему всем дочерним элементам
     *
     * @param element   элемент
     * @param namespace схема
     */
    private void installNamespace(Element element, Namespace namespace) {
        if (element.getNamespace().equals(Namespace.NO_NAMESPACE)) {
            element.setNamespace(namespace);
            for (Object o : element.getChildren()) {
                Element child = (Element) o;
                installNamespace(child, namespace);
            }
        }
    }

    /**
     * Установить схему всем дочерним элементам
     *
     * @param element   элемент
     * @param namespace схема
     */
    private void installNamespace(Element element, Namespace namespace, Namespace oldNamespace) {
        if (element.getNamespace().equals(oldNamespace)) {
            element.setNamespace(namespace);
            for (Object o : element.getChildren()) {
                Element child = (Element) o;
                installNamespace(child, namespace, oldNamespace);
            }
        }
    }

    /**
     * Чтение настроек и локализации
     *
     * @param text текст с плейсхолдерами ${prop}
     * @return текст без плейсхолдеров, если они разрешились
     */
    private String process(String text) {
        if (text == null) {
            return null;
        }
        String resolved = StringUtils.resolveProperties(text, MetadataParamHolder.getParams());
        resolved = systemProperties == null ? resolved : StringUtils.resolveProperties(resolved, systemProperties::getProperty);
        resolved = messageSourceAccessor == null ? resolved : StringUtils.resolveProperties(resolved, (msg) -> messageSourceAccessor.getMessage(msg, msg));
        if (failFast && StringUtils.hasProperty(resolved))
            throw new N2oException("Cannot resolve property in '" + text + "'");
        return resolved;
    }

    /**
     * Конвертирует строку в enum
     *
     * @param value     строка
     * @param enumClass класс enum
     * @param 
     * @return
     */
    private static > T stringToEnum(String value, Class enumClass) {
        if (value == null) return null;
        T res = null;
        boolean idAware = IdAware.class.isAssignableFrom(enumClass);
        if (idAware) {
            for (Enum enumValue : enumClass.getEnumConstants()) {
                IdAware idEnum = (IdAware) enumValue;
                if (idEnum.getId().equalsIgnoreCase(value)) {
                    res = (T) enumValue;
                }
            }
        } else {
            for (Enum enumValue : enumClass.getEnumConstants()) {
                if (enumValue.name().equalsIgnoreCase(value)) {
                    res = (T) enumValue;
                }
            }
        }
        return res;
    }

    private  Element persist(NamedElementIO io, T entity, Namespace namespace) {
        Element element = new Element(io.getElementName(), namespace);
        io.io(element, entity, this);
        return element;
    }

    private  T read(ClassedElementIO io, Element element) {
        T entity = io.newInstance(element);
        io.io(element, entity, this);
        return entity;
    }

    private ,
            P extends TypedElementPersister> T read(ElementIOFactory factory, Element element) {
        R reader = factory.produce(element);
        if (reader != null) {
            if (reader instanceof IOProcessorAware)
                ((IOProcessorAware) reader).setIOProcessor(this);
            return reader.read(element);
        } else
            return null;
    }

    private ,
            P extends TypedElementPersister> Element persist(ElementIOFactory factory, T entity, Namespace namespace) {
        P persister = factory.produce(entity);
        if (persister != null) {
            if (persister instanceof IOProcessorAware)
                ((IOProcessorAware) persister).setIOProcessor(this);
            return persister.persist(entity, namespace);
        } else
            return null;
    }

    private ,
            P extends NamespacePersister> T read(NamespaceIOFactory factory, Element element,
                                                            Namespace parentNamespace, Namespace... defaultNamespaces) {
        R reader;
        if (defaultNamespaces != null && defaultNamespaces.length > 0 && defaultNamespaces[0] != null && (hasText(getParentNameSpacePrefix(element)) || parentNamespace.getURI().equals(element.getNamespaceURI()))) {
            reader = factory.produce(element, parentNamespace, ArrayUtils.add(defaultNamespaces, element.getNamespace()));
        } else {
            reader = factory.produce(element, parentNamespace, null);
        }
        if (reader != null) {
            if (reader instanceof IOProcessorAware)
                ((IOProcessorAware) reader).setIOProcessor(this);
            T model = reader.read(element);
            model.setNamespaceUri(element.getNamespaceURI());
            model.setNamespacePrefix(element.getNamespacePrefix());
            return model;
        } else
            return null;
    }

    private ,
            P extends NamespacePersister> Element persist(NamespaceIOFactory factory, T entity,
                                                                     Namespace parentNamespace, Namespace... defaultNamespaces) {
        P persister;
        if (defaultNamespaces != null && defaultNamespaces.length > 0 && defaultNamespaces[0] != null
                && (isEmpty(entity.getNamespacePrefix()) || entity.getNamespaceUri().equals(parentNamespace.getURI())))
            persister = factory.produce((Class) entity.getClass(), ArrayUtils.add(defaultNamespaces, entity.getNamespace()));
        else
            persister = factory.produce(entity);

        if (persister != null) {
            if (persister instanceof IOProcessorAware)
                ((IOProcessorAware) persister).setIOProcessor(this);
            Element element = persister.persist(entity, parentNamespace);
            installNamespace(element, entity.getNamespace(), element.getNamespace());
            return element;
        } else
            return null;
    }

    private String getParentNameSpacePrefix(Element element) {
        if (isNull(element))
            return null;
        return nonNull(element.getParentElement()) ? element.getParentElement().getNamespacePrefix() : null;
    }

    private Element initSequenceElement(Element parent, String seqName) {
        Element seqE = parent.getChild(seqName, parent.getNamespace());
        if (seqE == null) {
            seqE = new Element(seqName, parent.getNamespace());
            parent.addContent(seqE);
        }
        return seqE;
    }

    public void setMessageSourceAccessor(MessageSourceAccessor messageSourceAccessor) {
        this.messageSourceAccessor = messageSourceAccessor;
    }

    public void setSystemProperties(PropertyResolver systemProperties) {
        this.systemProperties = systemProperties;
    }

    public void setFailFast(boolean failFast) {
        this.failFast = failFast;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy