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

org.apache.camel.dsl.yaml.common.YamlDeserializationContext Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.camel.dsl.yaml.common;

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;

import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.Ordered;
import org.apache.camel.Service;
import org.apache.camel.dsl.yaml.common.exception.DuplicateKeyException;
import org.apache.camel.dsl.yaml.common.exception.UnknownNodeIdException;
import org.apache.camel.dsl.yaml.common.exception.YamlDeserializationException;
import org.apache.camel.spi.Resource;
import org.apache.camel.util.ObjectHelper;
import org.snakeyaml.engine.v2.api.ConstructNode;
import org.snakeyaml.engine.v2.api.LoadSettings;
import org.snakeyaml.engine.v2.constructor.StandardConstructor;
import org.snakeyaml.engine.v2.nodes.MappingNode;
import org.snakeyaml.engine.v2.nodes.Node;
import org.snakeyaml.engine.v2.nodes.NodeType;
import org.snakeyaml.engine.v2.nodes.ScalarNode;

public class YamlDeserializationContext extends StandardConstructor implements CamelContextAware, Service {

    private final Set resolvers;
    private final Map constructors;
    private CamelContext camelContext;
    private Resource resource;

    public YamlDeserializationContext(LoadSettings settings) {
        super(settings);
        this.resolvers = new TreeSet<>(Comparator.comparing(Ordered::getOrder));
        this.constructors = new HashMap<>();
    }

    public void addResolver(YamlDeserializerResolver resolver) {
        this.resolvers.add(resolver);
    }

    public void addResolvers(YamlDeserializerResolver... resolvers) {
        addResolvers(Arrays.asList(resolvers));
    }

    public void addResolvers(Collection resolvers) {
        this.resolvers.addAll(resolvers);
    }

    public Resource getResource() {
        return resource;
    }

    public void setResource(Resource resource) {
        this.resource = resource;
    }

    @Override
    public CamelContext getCamelContext() {
        return camelContext;
    }

    @Override
    public void setCamelContext(CamelContext camelContext) {
        this.camelContext = camelContext;
    }

    @Override
    protected Optional findConstructorFor(Node node) {
        ConstructNode ctor = resolve(node);
        if (ctor != null) {
            return Optional.of(ctor);
        }

        return super.findConstructorFor(node);
    }

    @Override
    public void start() {
        ObjectHelper.notNull(camelContext, "camel context");

        this.resolvers.addAll(getCamelContext().getRegistry().findByType(YamlDeserializerResolver.class));
    }

    @Override
    public void stop() {
        this.constructors.clear();
    }

    // *********************************
    //
    // Construct
    //
    // *********************************

    public Object construct(Node key, Node val) {
        return mandatoryResolve(key).construct(val);
    }

    public  T construct(Node key, Node val, Class type) {
        Object result = construct(key, val);
        if (result == null) {
            return null;
        }

        return type.cast(result);
    }

    public  T construct(Node node, Class type) {
        ConstructNode constructor = resolve(type);
        if (constructor == null) {
            throw new YamlDeserializationException(node, "Unable to find constructor for node");
        }
        Object result = constructor.construct(node);
        if (result == null) {
            return null;
        }

        return type.cast(result);
    }

    // *********************************
    //
    // Resolve
    //
    // *********************************

    public ConstructNode resolve(Class type) {
        return CamelContextAware.trySetCamelContext(
                (Node n) -> {
                    Node newNode = YamlSupport.setProperty(
                            n,
                            YamlDeserializationContext.class.getName(),
                            YamlDeserializationContext.this);

                    final ConstructNode answer = resolve(n, type.getName());
                    return answer.construct(newNode);
                },
                camelContext);
    }

    public ConstructNode mandatoryResolve(Node node) {
        ConstructNode constructor = resolve(node);
        if (constructor == null) {
            throw new YamlDeserializationException(node, "Unable to find constructor for node");
        }

        return constructor;
    }

    public ConstructNode resolve(Node node) {
        if (node.getNodeType() != NodeType.MAPPING) {
            return null;
        }

        MappingNode mn = (MappingNode) node;
        if (mn.getValue().size() > 1) {
            throw new DuplicateKeyException(node, mn.getValue());
        } else if (mn.getValue().size() != 1) {
            return null;
        }

        Node key = mn.getValue().get(0).getKeyNode();
        if (key.getNodeType() != NodeType.SCALAR) {
            return null;
        }

        final String id = ((ScalarNode) key).getValue();
        final ConstructNode answer = resolve(node, id);

        return CamelContextAware.trySetCamelContext(
                (Node n) -> {
                    YamlSupport.setProperty(
                            n,
                            YamlDeserializationContext.class.getName(),
                            YamlDeserializationContext.this);

                    return answer.construct(
                            ((MappingNode) n).getValue().get(0).getValueNode());
                },
                camelContext);
    }

    public ConstructNode resolve(Node node, String id) {
        return constructors.computeIfAbsent(id, (String s) -> {
            ConstructNode answer = null;

            for (YamlDeserializerResolver resolver : resolvers) {
                answer = resolver.resolve(id);
                if (answer != null) {
                    break;
                }
            }

            if (answer == null) {
                throw new UnknownNodeIdException(node, id);
            }

            return answer;
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy