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

com.predic8.membrane.core.kubernetes.GenericYamlParser Maven / Gradle / Ivy

/* Copyright 2022 predic8 GmbH, www.predic8.com

   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 com.predic8.membrane.core.kubernetes;

import com.google.common.collect.ImmutableMap;
import com.predic8.membrane.annot.MCAttribute;
import com.predic8.membrane.annot.MCElement;
import com.predic8.membrane.annot.MCOtherAttributes;
import com.predic8.membrane.core.config.spring.K8sHelperGeneratorAutoGenerated;
import org.yaml.snakeyaml.events.*;

import java.lang.reflect.Method;
import java.util.*;

import static com.predic8.membrane.core.config.spring.k8s.YamlLoader.readString;
import static com.predic8.membrane.core.kubernetes.ParserHelper.*;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;

public class GenericYamlParser {
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static  T parse(String context, Class clazz, Iterator events, BeanRegistry registry) {
        T obj = null;
        try {
            obj = clazz.newInstance();
            Event event = events.next();
            if (!(event instanceof MappingStartEvent)) {
                throw new IllegalStateException("Expected start-of-map in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
            }
            while(true) {
                event = events.next();
                String key;
                if (event instanceof ScalarEvent) {
                    key = ((ScalarEvent)event).getValue();
                } else if (event instanceof MappingEndEvent) {
                    break;
                } else {
                    throw new IllegalStateException("Expected scalar or end-of-map in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
                }
                if ("$ref".equals(key)) {
                    event = events.next();
                    if (!(event instanceof ScalarEvent))
                        throw new IllegalStateException("Expected a string after the '$ref' key.");
                    Object o = registry.resolveReference(((ScalarEvent) event).getValue());
                    Method setter = getChildSetter(clazz, o.getClass());
                    setSetter(obj, setter, o);
                    continue;
                }
                Method setter = getSetter(clazz, key);
                Class clazz2 = null;
                if (setter == null) {
                    try {
                        clazz2 = K8sHelperGeneratorAutoGenerated.getLocal(context, key);
                        if (clazz2 == null)
                            clazz2 = K8sHelperGeneratorAutoGenerated.elementMapping.get(key);
                        if (clazz2 != null)
                            setter = getChildSetter(clazz, clazz2);
                    } catch (Exception e) {
                        throw new RuntimeException("Can't find method or bean for key: " + key + " in " + clazz.getName(), e);
                    }
                    if (setter == null)
                        setter = getAnySetter(clazz);
                    if (clazz2 == null && setter == null)
                        throw new RuntimeException("Can't find method or bean for key: " + key + " in " + clazz.getName());
                }

                Class wanted = setter.getParameterTypes()[0];
                // TODO: handle enums
                if (wanted.equals(List.class)) {
                    setSetter(obj, setter, parseList(context, events, registry));
                } else if (wanted.equals(String.class)) {
                    setSetter(obj, setter, readString(events));
                } else if (wanted.equals(Integer.TYPE)) {
                    setSetter(obj, setter, Integer.parseInt(readString(events)));
                } else if (wanted.equals(Long.TYPE)) {
                    setSetter(obj, setter, Long.parseLong(readString(events)));
                } else if (wanted.equals(Boolean.TYPE)) {
                    setSetter(obj, setter, Boolean.parseBoolean(readString(events)));
                } else if (wanted.equals(Map.class) && findAnnotation(setter, MCOtherAttributes.class) != null) {
                    setSetter(obj, setter, ImmutableMap.of(key, readString(events)));
                } else if (isStructured(setter)) {
                    if (clazz2 != null)
                        setSetter(obj, setter, parseMapToObj(context, events, event, registry));
                    else
                        setSetter(obj, setter, parse(context, wanted, events, registry));
                } else if (findAnnotation(setter, MCAttribute.class) != null && findAnnotation(setter.getParameterTypes()[0], MCElement.class) != null) {
                    setSetter(obj, setter, registry.resolveReference(readString(events)));
                } else {
                    throw new RuntimeException("Not implemented setter type " + wanted);
                }
            }
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        return obj;
    }

    private static List parseList(String context, Iterator events, BeanRegistry registry) {
        Event event = events.next();
        if (!(event instanceof SequenceStartEvent)) {
            throw new IllegalStateException("Expected start-of-sequence in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
        }
        ArrayList res = new ArrayList();
        while (true) {
            event = events.next();
            if (event instanceof SequenceEndEvent)
                break;
            else if (!(event instanceof MappingStartEvent))
                throw new IllegalStateException("Expected end-of-sequence or begin-of-map in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
            Object o = parseMapToObj(context, events, registry);
            res.add(o);
        }

        return res;
    }

    private static Object parseMapToObj(String context, Iterator events, BeanRegistry registry) {
        Event event = events.next();
        if (!(event instanceof ScalarEvent))
            throw new IllegalStateException("Expected scalar in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
        Object o = parseMapToObj(context, events, event, registry);
        event = events.next();
        if (!(event instanceof MappingEndEvent))
            throw new IllegalStateException("Expected end-of-map or begin-of-map in line " + event.getStartMark().getLine() + " column " + event.getStartMark().getColumn());
        return o;
    }

    private static Object parseMapToObj(String context, Iterator events, Event event, BeanRegistry registry) {
        String key = ((ScalarEvent) event).getValue();
        if ("$ref".equals(key)) {
            event = events.next();
            if (!(event instanceof ScalarEvent))
                throw new IllegalStateException("Expected a string after the '$ref' key.");
            return registry.resolveReference(((ScalarEvent)event).getValue());
        }
        Class clazz = K8sHelperGeneratorAutoGenerated.getLocal(context, key);
        if (clazz == null)
            clazz = K8sHelperGeneratorAutoGenerated.elementMapping.get(key);
        if (clazz == null)
            throw new RuntimeException("Did not find java class for key '" + key + "'.");
        return GenericYamlParser.parse(key, clazz, events, registry);
    }

    private static  Method getSetter(Class clazz, String key) {
        return Arrays.stream(clazz.getMethods())
                .filter(ParserHelper::isSetter)
                .filter(method -> matchesJsonKey(method, key))
                .findFirst()
                .orElse(null);
    }

    private static  Method getAnySetter(Class clazz) {
        return Arrays.stream(clazz.getMethods())
                .filter(ParserHelper::isSetter)
                .filter(method -> findAnnotation(method, MCOtherAttributes.class) != null)
                .findFirst()
                .orElse(null);
    }

    private static  Method getChildSetter(Class clazz, Class valueClass) {
        return Arrays.stream(clazz.getMethods())
                .filter(ParserHelper::isSetter)
                .filter(method -> method.getParameterTypes().length == 1)
                .filter(method -> method.getParameterTypes()[0].isAssignableFrom(valueClass))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("Could not find child setter on " + clazz.getName() + " for value of type " + valueClass.getName()));
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy