BuilderOperatorProviderBack.java

package space.sunqian.fs.object.builder;

import space.sunqian.annotation.Nonnull;
import space.sunqian.annotation.Nullable;
import space.sunqian.annotation.RetainedParam;
import space.sunqian.fs.base.FsLoader;
import space.sunqian.fs.cache.SimpleCache;
import space.sunqian.fs.object.builder.handlers.CommonBuilderHandler;
import space.sunqian.fs.third.ThirdKit;

import java.lang.reflect.Type;
import java.util.List;

final class BuilderOperatorProviderBack {

    static @Nonnull BuilderOperatorProvider defaultProvider() {
        return BuilderOperatorProviderImpl.DEFAULT;
    }

    static @Nonnull BuilderOperatorProvider defaultCachedProvider() {
        return CachedBuilderOperatorProvider.DEFAULT;
    }

    static @Nonnull BuilderOperatorProvider newProvider(
        @Nonnull @RetainedParam List<BuilderOperatorProvider.@Nonnull Handler> handlers
    ) {
        return new BuilderOperatorProviderImpl(handlers);
    }

    static @Nonnull BuilderOperatorProviderBack.CachedBuilderOperatorProvider newCachedProvider(
        @Nonnull SimpleCache<@Nonnull Type, @Nonnull BuilderOperator> cache,
        @Nonnull BuilderOperatorProvider provider
    ) {
        return new CachedBuilderOperatorProvider(cache, provider);
    }

    static @Nullable BuilderOperator operatorForType(
        @Nonnull Type target,
        @Nonnull List<BuilderOperatorProvider.@Nonnull Handler> handlers
    ) throws Exception {
        for (BuilderOperatorProvider.Handler handler : handlers) {
            BuilderOperator operator = handler.newOperator(target);
            if (operator != null) {
                return operator;
            }
        }
        return null;
    }

    private static final class BuilderOperatorProviderImpl implements BuilderOperatorProvider, BuilderOperatorProvider.Handler {

        private static final @Nonnull BuilderOperatorProvider DEFAULT = new BuilderOperatorProviderImpl(
            FsLoader.loadInstances(
                FsLoader.loadClassByDependent(
                    ThirdKit.thirdClassName("protobuf", "ProtobufCreatorHandler"),
                    "com.google.protobuf.Message"
                ),
                CommonBuilderHandler.getInstance()
            )
        );

        private final @Nonnull List<@Nonnull Handler> handlers;

        private BuilderOperatorProviderImpl(
            @Nonnull @RetainedParam List<@Nonnull Handler> handlers
        ) {
            this.handlers = handlers;
        }

        @Override
        public @Nonnull List<@Nonnull Handler> handlers() {
            return handlers;
        }

        @Override
        public @Nonnull Handler asHandler() {
            return this;
        }

        @Override
        public @Nullable BuilderOperator newOperator(@Nonnull Type target) throws Exception {
            return BuilderOperatorProviderBack.operatorForType(target, handlers);
        }
    }

    private static final class CachedBuilderOperatorProvider implements BuilderOperatorProvider {

        private static final @Nonnull BuilderOperatorProviderBack.CachedBuilderOperatorProvider DEFAULT = newCachedProvider(
            SimpleCache.ofSoft(),
            BuilderOperatorProvider.defaultProvider()
        );

        private final @Nonnull SimpleCache<@Nonnull Type, @Nullable BuilderOperator> cache;
        private final @Nonnull BuilderOperatorProvider provider;

        private CachedBuilderOperatorProvider(
            @Nonnull SimpleCache<@Nonnull Type, @Nullable BuilderOperator> cache,
            @Nonnull BuilderOperatorProvider provider
        ) {
            this.cache = cache;
            this.provider = provider;
        }

        @Override
        public @Nullable BuilderOperator forType(@Nonnull Type target) throws ObjectBuilderException {
            return cache.get(target, provider::forType);
        }

        @Override
        public @Nonnull List<@Nonnull Handler> handlers() {
            return provider.handlers();
        }

        @Override
        public @Nonnull Handler asHandler() {
            return provider.asHandler();
        }
    }

    private BuilderOperatorProviderBack() {
    }
}