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

tools.dynamia.viewers.impl.YamlViewDescriptorReader Maven / Gradle / Ivy

/*
 * Copyright (C) 2023 Dynamia Soluciones IT S.A.S - NIT 900302344-1
 * Colombia / South America
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package tools.dynamia.viewers.impl;

import org.yaml.snakeyaml.Yaml;
import tools.dynamia.commons.BeanUtils;
import tools.dynamia.commons.logger.LoggingService;
import tools.dynamia.commons.logger.SLF4JLoggingService;
import tools.dynamia.integration.sterotypes.Provider;
import tools.dynamia.io.Resource;
import tools.dynamia.io.converters.Converters;
import tools.dynamia.viewers.*;
import tools.dynamia.viewers.util.Viewers;

import java.io.Reader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import static tools.dynamia.viewers.util.ViewersExpressionUtil.$s;

/**
 * The Class YamlViewDescriptorReader.
 *
 * @author Mario A. Serrano Leones
 */
@Provider
public class YamlViewDescriptorReader implements ViewDescriptorReader {

    private static final String SORT_FIELDS = "sortFields";
    private static final String FIELD_REQUIRED = "required";
    private static final String VD_LAYOUT = "layout";
    private static final String FIELD_ICON = "icon";
    private static final String FIELD_SHOW_ICON_ONLY = "showIconOnly";
    private static final String FIELD_PARAMS = "params";
    private static final String FIELD_VISIBLE = "visible";
    private static final String FIELD_FIELDCLASS = "fieldClass";
    private static final String FIELD_INDEX = "index";
    private static final String FIELD_COMPONENT_CUSTOMIZER = "componentCustomizer";
    private static final String FIELD_COMPONENT_CLASS = "componentClass";
    private static final String FIELD_COMPONENT = "component";
    private static final String FIELD_DESCRIPTION = "description";
    private static final String FIELD_LABEL = "label";
    private static final String FIELD_COLLAPSE = "collapse";
    private static final String FIELD_ACTION = "action";
    private static final String VD_FIELDS = "fields";
    private static final String FIELD_CLASS = "class";
    private static final String VD_HIDDEN = "hidden";
    private static final String VD_RENDERER = "renderer";
    private static final String VD_CUSTOMIZER = "customizer";
    private static final String VD_DEVICE = "device";
    private static final String VD_EXTENDS = "extends";
    private static final String VD_MESSAGES = "messages";
    private static final String VD_ID = "id";
    private static final String VD_AUTOFIELDS = "autofields";
    private static final String VD_BEAN_CLASS = "beanClass";
    private static final String DEBUG = "debug";
    private static final String VD_VIEW = "view";
    private static final String GROUPS = "groups";
    private static final String EQUAL_SYMBOL = "=";

    private static final String VD_ACTIONS = "actions";


    /**
     * The logger.
     */
    private final LoggingService logger = new SLF4JLoggingService(YamlViewDescriptorReader.class);

    /**
     * The Constant TYPE_MAP.
     */
    private static final Map> TYPE_MAP = new HashMap<>();

    static {
        TYPE_MAP.put("boolean", Boolean.class);
        TYPE_MAP.put("int", Integer.class);
        TYPE_MAP.put("float", Float.class);
        TYPE_MAP.put("double", Double.class);
        TYPE_MAP.put("date", Date.class);
        TYPE_MAP.put("long", Long.class);
        TYPE_MAP.put(FIELD_CLASS, Class.class);
        TYPE_MAP.put("string", String.class);
        TYPE_MAP.put("bigdecimal", BigDecimal.class);
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.viewers.ViewDescriptorReader#read(com.dynamia.tools
     * .io.Resource, java.io.Reader, java.util.List)
     */
    @Override
    public ViewDescriptor read(Resource descriptorResource, Reader reader,
                               List customizers) {
        try {
            Yaml yml = new Yaml();

            Map map = yml.load(reader);


            parseExpressions(map);

            return runViewDescriptorReaderCustomizer(map, customizers);
        } catch (Exception ex) {
            throw new ViewDescriptorReaderException(
                    "Error parsing YML ViewDescriptor " + descriptorResource.getFilename() + ": " + ex.getMessage(),
                    ex);
        }
    }

    /**
     * Run view descriptor reader customizers.
     *
     * @param map         the map
     * @param customizers the customizers
     * @return the view descriptor
     * @throws Exception the exception
     */
    protected ViewDescriptor runViewDescriptorReaderCustomizer(Map map,
                                                               List customizers) throws Exception {
        ViewDescriptor descriptor = buildViewDescriptor(map);
        for (ViewDescriptorReaderCustomizer c : customizers) {
            //noinspection unchecked
            c.customize(map, descriptor);
        }
        return descriptor;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.dynamia.tools.viewers.ViewDescriptorReader#getSupportedFileExtensions ()
     */
    @Override
    public String[] getSupportedFileExtensions() {
        return new String[]{"yml", "YML", "yaml"};
    }

    /**
     * Builds the view descriptor.
     *
     * @param map the map
     * @return the view descriptor
     */
    private ViewDescriptor buildViewDescriptor(Map map) {
        DefaultViewDescriptor descriptor = null;

        if (!map.containsKey(VD_VIEW)) {
            throw new ViewDescriptorReaderException("[view] is a mandatory property");
        }

        Class beanClass = null;

        if (get(map, VD_BEAN_CLASS) != null) {
            beanClass = Converters.convert(Class.class, get(map, VD_BEAN_CLASS).toString());
        }

        String view = (String) map.get(VD_VIEW);

        boolean autofields = false;
        if (isBoolean(get(map, VD_AUTOFIELDS))) {
            autofields = parseBoolean(get(map, VD_AUTOFIELDS));
        }
        descriptor = new DefaultViewDescriptor(beanClass, view, autofields);

        setValue(descriptor, VD_ID, String.class, map);
        setValue(descriptor, VD_MESSAGES, String.class, map);
        setValue(descriptor, VD_EXTENDS, String.class, map);
        setValue(descriptor, VD_DEVICE, String.class, map);
        setValue(descriptor, "viewCustomizerClass", VD_CUSTOMIZER, Class.class, map);
        setValue(descriptor, "customViewRenderer", VD_RENDERER, Class.class, map);

        parseHiddenFields(map, descriptor);
        parseFields(map, descriptor);
        parseParameters(map, descriptor);
        parseLayout(map, descriptor);
        parseGroups(map, descriptor);
        parseSortFields(map, descriptor);
        parseSortGroups(map, descriptor);
        parseActions(map, descriptor);
        return descriptor;
    }

    /**
     * Parses the boolean.
     *
     * @param value the value
     * @return true, if successful
     */
    protected boolean parseBoolean(Object value) {
        return Boolean.parseBoolean(value.toString());
    }

    /**
     * Checks if is boolean.
     *
     * @param value the value
     * @return true, if is boolean
     */
    private boolean isBoolean(Object value) {
        if (value == null) {
            return false;
        }

        String v = value.toString();
        return (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("false"));

    }

    /**
     * Parses the sort groups.
     *
     * @param map        the map
     * @param descriptor the descriptor
     */
    @SuppressWarnings("unchecked")
    protected void parseSortGroups(Map map, DefaultViewDescriptor descriptor) {
        if (get(map, "sortGroups") != null && get(map, "sortGroups") instanceof List) {
            descriptor.sortFieldGroups((List) get(map, "sortGroups"));
        }
    }

    /**
     * Parses the sort fields.
     *
     * @param map        the map
     * @param descriptor the descriptor
     */
    @SuppressWarnings("unchecked")
    protected void parseSortFields(Map map, DefaultViewDescriptor descriptor) {
        if (get(map, SORT_FIELDS) != null && get(map, SORT_FIELDS) instanceof List) {
            descriptor.sortFields((List) map.get(SORT_FIELDS));
        }
    }

    /**
     * Parses the groups.
     *
     * @param map        the map
     * @param descriptor the descriptor
     */
    protected void parseGroups(Map map, DefaultViewDescriptor descriptor) {
        // GROUPS
        if (map.containsKey(GROUPS) && map.get(GROUPS) instanceof Map groups) {
            for (Object object : groups.entrySet()) {
                Entry entry = (Entry) object;
                FieldGroup group = new FieldGroup((String) entry.getKey());
                group.setViewDescriptor(descriptor);
                if (entry.getValue() instanceof Map groupProps) {
                    setValue(group, FIELD_LABEL, String.class, groupProps);
                    setValue(group, FIELD_ICON, String.class, groupProps);
                    setValue(group, FIELD_DESCRIPTION, String.class, groupProps);
                    setValue(group, FIELD_INDEX, Integer.class, groupProps);
                    setValue(group, FIELD_COLLAPSE, Boolean.class, groupProps);

                    if (groupProps.containsKey(VD_FIELDS) && groupProps.get(VD_FIELDS) instanceof List fieldsNames) {
                        for (Object fn : fieldsNames) {
                            Field field = descriptor.getField(fn.toString());
                            if (field == null) {
                                logger.warn(fn + " is not a field. ViewDescriptor "
                                        + descriptor.getViewTypeName() + " - " + descriptor.getBeanClass());
                            } else {
                                group.addField(field);
                            }
                        }
                        groupProps.remove(VD_FIELDS);
                    } else {
                        logger.warn("Field Group [" + group.getName() + "] is empty. ViewDescriptor "
                                + descriptor.getViewTypeName() + " - " + descriptor.getBeanClass());
                    }

                    if (groupProps.get(FIELD_PARAMS) instanceof Map groupParams) {
                        //noinspection unchecked
                        group.getParams().putAll(groupParams);
                    }

                }
                descriptor.addFieldGroup(group);
            }
        }
    }

    /**
     * Parses the layout.
     *
     * @param map        the map
     * @param descriptor the descriptor
     */
    protected void parseLayout(Map map, DefaultViewDescriptor descriptor) {
        // LAYOUT
        if (map.containsKey(VD_LAYOUT) && map.get(VD_LAYOUT) instanceof Map layout) {
            for (Object object : layout.entrySet()) {
                Entry entry = (Entry) object;
                descriptor.getLayout().addParam(entry.getKey().toString(), entry.getValue());
            }
        }
    }

    /**
     * Parses the parameters.
     *
     * @param map        the map
     * @param descriptor the descriptor
     */
    protected void parseParameters(Map map, DefaultViewDescriptor descriptor) {
        // PARAMETERS
        if (map.containsKey(FIELD_PARAMS) && map.get(FIELD_PARAMS) instanceof Map params) {
            for (Object object : params.entrySet()) {
                Entry entry = (Entry) object;
                Object value = getEntryValue(entry);
                descriptor.addParam(entry.getKey().toString(), value);
            }
        }
    }

    /**
     * Parses the fields.
     *
     * @param map        the map
     * @param descriptor the descriptor
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    protected void parseFields(Map map, DefaultViewDescriptor descriptor) {
        // FIELDS
        if (map.containsKey(VD_FIELDS) && map.get(VD_FIELDS) instanceof Map fields) {
            for (Object obj : fields.entrySet()) {
                Entry entry = (Entry) obj;
                Field field = new Field();
                field.setName(entry.getKey());
                Map fieldProps = entry.getValue();

                setValue(field, FIELD_LABEL, String.class, fieldProps);
                setValue(field, FIELD_DESCRIPTION, String.class, fieldProps);
                setValue(field, FIELD_COMPONENT, String.class, fieldProps);
                setValue(field, FIELD_COMPONENT_CLASS, Class.class, fieldProps);
                setValue(field, FIELD_COMPONENT_CUSTOMIZER, String.class, fieldProps);
                setValue(field, FIELD_INDEX, Integer.class, fieldProps);
                setValue(field, FIELD_FIELDCLASS, Class.class, fieldProps);
                setValue(field, FIELD_VISIBLE, Boolean.class, fieldProps);
                setValue(field, FIELD_REQUIRED, Boolean.class, fieldProps);
                setValue(field, FIELD_ACTION, String.class, fieldProps);
                setValue(field, FIELD_ICON, String.class, fieldProps);
                setValue(field, FIELD_SHOW_ICON_ONLY, Boolean.class, fieldProps);

                parseFieldClassAlias(fieldProps, field);

                if (fieldProps != null && fieldProps.containsKey(FIELD_PARAMS)
                        && fieldProps.get(FIELD_PARAMS) instanceof Map fieldParams) {
                    for (Object object : fieldParams.entrySet()) {
                        Entry entry2 = (Entry) object;
                        Object value = getEntryValue(entry2);
                        field.addParam(entry2.getKey().toString(), value);
                    }
                }
                descriptor.addField(field);
            }
        } else {
            map.remove(VD_FIELDS);
        }
    }

    private Object getEntryValue(Entry entry) {
        Object value = entry.getValue();
        if (hasConverter(value)) {
            value = convertToObject(value.toString());
        } else if (isBoolean(value)) {
            value = parseBoolean(value);
        }
        return value;
    }

    /**
     * Parses the field class alias.
     *
     * @param fieldProps the field props
     * @param field      the field
     */
    protected void parseFieldClassAlias(Map fieldProps, Field field) {
        if (fieldProps != null && fieldProps.get(FIELD_CLASS) != null
                && fieldProps.get(FIELD_CLASS) instanceof String) {
            try {
                String className = fieldProps.get(FIELD_CLASS).toString();
                field.setFieldClass(Class.forName(className.trim()));
            } catch (Exception e) {
                logger.warn("Cannot parse Class name for field " + field.getName() + ". Exception: " + e.getMessage());
            }
        }
    }

    /**
     * Checks for converter.
     *
     * @param value the value
     * @return true, if successful
     */
    private boolean hasConverter(Object value) {
        return value instanceof String && value.toString().contains(EQUAL_SYMBOL);
    }

    /**
     * Parses the hidden fields.
     *
     * @param map        the map
     * @param descriptor the descriptor
     */
    protected void parseHiddenFields(Map map, DefaultViewDescriptor descriptor) {
        // HIDDEN FIELDS
        Collection hidden = (Collection) map.get(VD_HIDDEN);
        if (hidden != null) {
            List fieldNames = new ArrayList<>();
            for (Object object : hidden) {
                fieldNames.add(object.toString());
            }
            descriptor.hideFields(fieldNames.toArray(new String[0]));
        }
        map.remove(VD_HIDDEN);
    }

    /**
     * Sets the value.
     *
     * @param obj             the obj
     * @param name            the name
     * @param clazz           the clazz
     * @param valueRepository the value repository
     */
    @SuppressWarnings("rawtypes")
    private void setValue(Object obj, String name, Class clazz, Map valueRepository) {
        setValue(obj, name, name, clazz, valueRepository);
    }

    @SuppressWarnings("rawtypes")
    private void setValue(Object obj, String property, String name, Class clazz, Map valueRepository) {
        if (valueRepository != null && valueRepository.containsKey(name) && valueRepository.get(name) != null) {

            Object value = valueRepository.get(name);
            if (value != null) {
                if (clazz != String.class) {
                    value = Converters.convert(clazz, value.toString());
                }
                try {
                    BeanUtils.invokeSetMethod(obj, property, value);
                } catch (Exception e) {
                    throw new ViewDescriptorReaderException(e.getClass().getName() + " : " + e.getMessage());
                }
            }
        }
    }

    /**
     * Convert to object.
     *
     * @param string the string
     * @return the object
     */
    private Object convertToObject(String string) {
        try {
            string = string.trim();
            String value = string.substring(0, string.indexOf(EQUAL_SYMBOL)).trim();
            String type = string.substring(string.indexOf(EQUAL_SYMBOL) + 1).trim();

            Class clazz = TYPE_MAP.get(type.toLowerCase());
            return Converters.convert(clazz, value);

        } catch (Exception e) {
            return string;
        }
    }

    /**
     * Parses the expressions.
     *
     * @param map the map
     */
    protected void parseExpressions(Map map) {
        try {
            for (Object object : map.entrySet()) {
                Map.Entry entry = (Map.Entry) object;
                if (entry.getValue() instanceof String) {
                    String parsedString = $s((String) entry.getValue());
                    //noinspection unchecked
                    entry.setValue(parsedString);
                } else if (entry.getValue() instanceof Map) {
                    parseExpressions((Map) entry.getValue());
                }
            }
        } catch (Exception e) {
            logger.warn("Cannot parse ${...} expressions: " + e.getMessage());
        }
    }

    /**
     * Gets the.
     *
     * @param map the map
     * @param key the key
     * @return the object
     */
    public Object get(Map map, String key) {
        Object value = map.get(key);
        if (value == null) {
            value = map.get(key.toLowerCase());
        }
        return value;
    }

    protected void parseActions(Map map, DefaultViewDescriptor descriptor) {
        if (map.containsKey(VD_ACTIONS) && map.get(VD_ACTIONS) instanceof Map fields) {
            for (Object obj : fields.entrySet()) {
                Entry entry = (Entry) obj;
                Map actionsProps = entry.getValue();

                if (actionsProps != null) {
                    ActionRef action = new ActionRef();
                    action.setId(entry.getKey());
                    setValue(action, Viewers.PARAM_WIDTH, String.class, actionsProps);
                    setValue(action, Viewers.PARAM_VISIBLE, Boolean.class, actionsProps);
                    setValue(action, Viewers.PARAM_WIDTH, String.class, actionsProps);
                    setValue(action, FIELD_LABEL, String.class, actionsProps);
                    setValue(action, FIELD_DESCRIPTION, String.class, actionsProps);
                    setValue(action, FIELD_ICON, String.class, actionsProps);

                    if (actionsProps.containsKey(FIELD_PARAMS) && actionsProps.get(FIELD_PARAMS) instanceof Map actionParams) {
                        for (Object object : actionParams.entrySet()) {
                            Entry entry2 = (Entry) object;
                            Object value = getEntryValue(entry2);
                            action.addParam(entry2.getKey().toString(), value);
                        }
                    }
                    descriptor.addAction(action);
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy