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

com.atlassian.bamboo.specs.util.Yamlizator Maven / Gradle / Ivy

There is a newer version: 10.1.0
Show newest version
package com.atlassian.bamboo.specs.util;

import com.atlassian.bamboo.specs.api.model.AtlassianModuleProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.introspector.BeanAccess;
import org.yaml.snakeyaml.introspector.FieldProperty;
import org.yaml.snakeyaml.introspector.Property;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;

import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;

public final class Yamlizator {
    public static final String BAMBOO_SPECS_MAX_ALIASES_FOR_COLLECTIONS_PROPERTY = "bamboo.specs.max.aliases.for.collections";
    public static final String BAMBOO_SPECS_CODE_POINTS_LIMIT_PROPERTY = "bamboo.specs.code.point.limit";
    private static final DumperOptions BLOCK_STYLE_DUMPER;

    private static final Field FIELD_FIELD;
    private static final Comparator CLASS_SCOPED_ORDER = (o1, o2) -> {
        final FieldProperty fp1 = asFieldProperty(o1);
        final FieldProperty fp2 = asFieldProperty(o2);

        if (fp1 == null && fp2 != null) {
            return -1;
        }
        if (fp1 != null && fp2 == null) {
            return 1;
        }
        if (fp1 == null) {
            return 0;
        }

        final Class class1 = getDeclaringClass(fp1);
        final Class class2 = getDeclaringClass(fp2);

        if (!class1.equals(class2)) { //fields from parent class first
            if (class2.isAssignableFrom(class1)) {
                return 1;
            } else if (class1.isAssignableFrom(class2)) {
                return -1;
            }
        }

        final int classCompare = class1.getName().compareTo(class2.getName());
        if (classCompare != 0) {
            return classCompare;
        }
        return fp1.getName().compareTo(fp2.getName());
    };

    static {
        BLOCK_STYLE_DUMPER = new DumperOptions();
        BLOCK_STYLE_DUMPER.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        BLOCK_STYLE_DUMPER.setExplicitStart(true);
        BLOCK_STYLE_DUMPER.setExplicitEnd(true);
        BLOCK_STYLE_DUMPER.setAllowReadOnlyProperties(true);

        try {
            FIELD_FIELD = FieldProperty.class.getDeclaredField("field");
            FIELD_FIELD.setAccessible(true);

        } catch (final NoSuchFieldException | SecurityException e) {
            throw new RuntimeException(e);
        }
    }

    private Yamlizator() {
    }

    public static Yaml getYaml() {
        LoaderOptions loadingConfig = getLoaderOptions();
        return getYamlInternal(new BambooYamlConstructor(loadingConfig), loadingConfig);
    }

    public static Yaml getYamlWithRepositoryIncludes(int maxDepth, final Path yamlDirectory) {
        return getYamlWithRepositoryIncludes(maxDepth, 0, yamlDirectory);
    }

    static Yaml getYamlWithRepositoryIncludes(int maxDepth, int depth, final Path yamlDirectory) {
        LoaderOptions loadingConfig = getLoaderOptions();
        return getYamlInternal(getConstructorWithIncludes(maxDepth, depth, yamlDirectory, loadingConfig), loadingConfig);
    }

    @NotNull
    private static Yaml getYamlInternal(@NotNull SafeConstructor constructor, LoaderOptions loadingConfig) {
        final Yaml yaml = new Yaml(constructor, getRepresenter(), BLOCK_STYLE_DUMPER, loadingConfig);
        yaml.setBeanAccess(BeanAccess.FIELD);
        return yaml;
    }

    @NotNull
    private static LoaderOptions getLoaderOptions() {
        LoaderOptions loadingConfig = new LoaderOptions();
        final int maxAliasesForCollections = Integer.parseInt(System.getProperty(BAMBOO_SPECS_MAX_ALIASES_FOR_COLLECTIONS_PROPERTY, "1500"));
        loadingConfig.setMaxAliasesForCollections(maxAliasesForCollections);
        loadingConfig.setAllowDuplicateKeys(false);
        final int maxCodePointLimit = Integer.parseInt(System.getProperty(BAMBOO_SPECS_CODE_POINTS_LIMIT_PROPERTY, "6291456" /*twice bigger then default*/));
        loadingConfig.setCodePointLimit(maxCodePointLimit);
        loadingConfig.setTagInspector(new BambooSpecsTagInspector());
        return loadingConfig;
    }

    private static SafeConstructor getConstructorWithIncludes(final int maxDepth, final int depth, final Path yamlDirectory, LoaderOptions loadingConfig) {
        return new BambooYamlWithIncludesConstructor(maxDepth, depth, yamlDirectory, loadingConfig);
    }

    @NotNull
    private static Representer getRepresenter() {
        return new Representer(BLOCK_STYLE_DUMPER) {
            {
                for (final CustomYamlers.CustomYamler customYamler : CustomYamlers.YAMLERS) {
                    this.representers.put(customYamler.getYamledClass(), customYamler.getRepresenter());
                }
            }

            @Override
            protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {
                Object newPropertyValue = propertyValue;
                if (Collections.emptyList().equals(propertyValue)) {
                    newPropertyValue = new ArrayList<>(0);
                } else if (propertyValue instanceof AtlassianModuleProperties) {
                    AtlassianModuleProperties atlassianModuleProperties = (AtlassianModuleProperties) propertyValue;
                    newPropertyValue = new AtlassianModuleProperties(atlassianModuleProperties.getCompleteModuleKey());
                }
                return super.representJavaBeanProperty(javaBean, property, newPropertyValue, customTag);
            }

            @Override
            protected Set getProperties(final Class type) {
                final Set properties = getPropertyUtils().getProperties(type);

                return properties.stream()
                        .sorted(CLASS_SCOPED_ORDER)
                        .collect(Collectors.toCollection(LinkedHashSet::new));
            }
        };
    }

    @Nullable
    private static FieldProperty asFieldProperty(final Property property) {
        if (property instanceof FieldProperty) {
            return (FieldProperty) property;
        }
        return null;
    }

    @NotNull
    private static Class getDeclaringClass(final FieldProperty fieldProperty) {
        try {
            return ((Field) FIELD_FIELD.get(fieldProperty)).getDeclaringClass();
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy