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

com.github.phantomthief.model.builder.context.impl.SimpleBuildContext Maven / Gradle / Ivy

The newest version!
package com.github.phantomthief.model.builder.context.impl;

import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString;
import static org.apache.commons.lang3.builder.ToStringStyle.SHORT_PREFIX_STYLE;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;

import com.github.phantomthief.model.builder.context.BuildContext;
import com.github.phantomthief.model.builder.util.MergeUtils;

/**
 * 
 * @author w.vela
 */
@SuppressWarnings("unchecked")
public class SimpleBuildContext implements BuildContext {

    private final ConcurrentMap> datas;
    private final ConcurrentMap> lazyDatas = new ConcurrentHashMap<>();
    private final ConcurrentMap>> lazyBuilders = new ConcurrentHashMap<>();

    public SimpleBuildContext() {
        this(new ConcurrentHashMap<>());
    }

    // for test case
    public SimpleBuildContext(ConcurrentMap> datas) {
        this.datas = datas;
    }

    @Override
    public  Map getData(Object namespace) {
        Function> lazyBuilder = lazyBuilders.get(namespace);
        if (lazyBuilder != null) {
            return computeIfAbsent(lazyDatas, namespace, ns -> lazyBuilder.apply(this));
        } else {
            return computeIfAbsent(datas, namespace, ns -> new ConcurrentHashMap<>());
        }
    }

    /**
     * Workaround to fix ConcurrentHashMap stuck bug when call {@link ConcurrentHashMap#computeIfAbsent} recursively.
     * see https://bugs.openjdk.java.net/browse/JDK-8062841.
     */
    private static  Map computeIfAbsent(ConcurrentMap> map, Object key,
                                                    Function> function) {
        Map value = map.get(key);
        if (value == null) {
            value = function.apply(key);
            map.put(key, value);
        }
        return (Map) value;
    }

    public void setupLazyNodeData(Object namespace,
            Function> lazyBuildFunction) {
        lazyBuilders.put(namespace, lazyBuildFunction);
    }

    @Override
    public void merge(BuildContext buildContext) {
        if (buildContext instanceof SimpleBuildContext) {
            SimpleBuildContext other = (SimpleBuildContext) buildContext;
            other.datas.forEach(
                    (namespace, values) -> datas.merge(namespace, values, MergeUtils::merge));
            other.lazyBuilders.forEach(lazyBuilders::putIfAbsent);
            lazyBuilders.keySet().forEach(key -> {
                datas.remove(key);
                lazyDatas.remove(key);
            });
        } else {
            throw new UnsupportedOperationException();
        }
    }

    @Override
    public String toString() {
        return reflectionToString(this, SHORT_PREFIX_STYLE);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy