001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate.loader;
018
019import static java.util.Objects.requireNonNull;
020
021import org.checkerframework.checker.nullness.qual.NonNull;
022import org.spongepowered.configurate.ConfigurationNode;
023import org.spongepowered.configurate.ScopedConfigurationNode;
024import org.spongepowered.configurate.util.UnmodifiableCollections;
025
026import java.net.URL;
027import java.nio.file.Path;
028import java.util.ServiceLoader;
029import java.util.Set;
030import java.util.function.Supplier;
031
032/**
033 * An implementation of {@link ConfigurationFormat} designed to work
034 * with {@link AbstractConfigurationLoader}.
035 *
036 * <p>This reduces the boilerplate that would otherwise be required to implement
037 * a configuration format service.</p>
038 *
039 * @param <N> the node type
040 * @param <L> the loader type
041 * @param <B> the builder type
042 * @since 4.2.0
043 */
044public abstract class AbstractConfigurationFormat<
045    N extends ScopedConfigurationNode<N>,
046    L extends AbstractConfigurationLoader<N>,
047    B extends AbstractConfigurationLoader.Builder<B, L>
048    > implements ConfigurationFormat {
049
050    private final String id;
051    private final Supplier<B> builderMaker;
052    private final Set<String> supportedExtensions;
053
054    /**
055     * Create a new configuration format.
056     *
057     * <p>Subclasses should have a zero-argument constructor to fulfil the
058     * requirements of {@link ServiceLoader}.</p>
059     *
060     * @param builderMaker a factory creating a new builder
061     * @param supportedExtensions the file extensions associated with
062     *     this format
063     * @since 4.2.0
064     */
065    protected AbstractConfigurationFormat(final String id, final Supplier<B> builderMaker, final Set<String> supportedExtensions) {
066        this.id = requireNonNull(id, "id");
067        this.builderMaker = requireNonNull(builderMaker, "builderMaker");
068        this.supportedExtensions = UnmodifiableCollections.copyOf(requireNonNull(supportedExtensions, "supportedExtensions"));
069    }
070
071    @Override
072    public String id() {
073        return this.id;
074    }
075
076    @Override
077    public Set<String> supportedExtensions() {
078        return this.supportedExtensions;
079    }
080
081    @Override
082    public ConfigurationLoader<? extends @NonNull Object> create(final Path file) {
083        return this.builderMaker.get()
084            .path(file)
085            .build();
086    }
087
088    @Override
089    public ConfigurationLoader<? extends @NonNull Object> create(final Path file, final ConfigurationNode options) {
090        return this.builderMaker.get()
091            .from(LoaderOptionSource.node(options))
092            .path(file)
093            .build();
094    }
095
096    @Override
097    public ConfigurationLoader<? extends @NonNull Object> create(final URL url) {
098        return this.builderMaker.get()
099            .url(url)
100            .build();
101    }
102
103    @Override
104    public ConfigurationLoader<? extends @NonNull Object> create(final URL url, final ConfigurationNode options) {
105        return this.builderMaker.get()
106            .from(LoaderOptionSource.node(options))
107            .url(url)
108            .build();
109    }
110
111}