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

ninja.leaping.configurate.loader.AbstractConfigurationLoader Maven / Gradle / Ivy

/**
 * Configurate
 * Copyright (C) zml and Configurate contributors
 *
 * 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 ninja.leaping.configurate.loader;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.io.CharSink;
import com.google.common.io.CharSource;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.ConfigurationOptions;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.Charset;

/**
 * Base class for many stream-based configuration loaders. This class provides conversion from a variety of input
 * sources to CharSource/Sink objects, providing a consistent API for loaders to read from and write to.
 *
 * Either the source or sink may be null. If this is true, this loader may not support either loading or saving. In
 * this case, implementing classes are expected to throw an IOException.
 */
public abstract class AbstractConfigurationLoader implements ConfigurationLoader {
    protected static final Splitter LINE_SPLITTER = Splitter.on('\n');
    protected static final String LINE_SEPARATOR = System.getProperty("line.separator");
    public static final Charset UTF8_CHARSET = Charset.forName("utf-8");
    static {
        assert UTF8_CHARSET != null; // If it is, there is a serious problem w/ this user's jdk installation
    }
    protected final CharSource source;
    private final CharSink sink;
    private final CommentHandler[] commentHandlers;
    private final boolean preservesHeader;

    protected static abstract class Builder {
        protected boolean preserveHeader = true;
        protected CharSource source;
        protected CharSink sink;

        public Builder setFile(File file) {
            this.source = Files.asCharSource(file, UTF8_CHARSET);
            this.sink = AtomicFiles.asCharSink(file, UTF8_CHARSET);
            return this;
        }

        public Builder setURL(URL url) {
            this.source = Resources.asCharSource(url, UTF8_CHARSET);
            return this;
        }

        public Builder setSource(CharSource source) {
            this.source = source;
            return this;
        }

        public Builder setSink(CharSink sink) {
            this.sink = sink;
            return this;
        }

        public Builder setPreservesHeader(boolean preservesHeader) {
            this.preserveHeader = preservesHeader;
            return this;
        }

        public abstract AbstractConfigurationLoader build();
    }

    protected AbstractConfigurationLoader(CharSource source, CharSink sink, CommentHandler[] commentHandlers, boolean
            preservesHeader) {
        this.source = source;
        this.sink = sink;
        this.commentHandlers = commentHandlers;
        this.preservesHeader = preservesHeader;
    }

    public CommentHandler getDefaultCommentHandler() {
        return this.commentHandlers[0];
    }

    @Override
    public NodeType load() throws IOException {
        return load(ConfigurationOptions.defaults());
    }

    @Override
    public NodeType load(ConfigurationOptions options) throws IOException {
        if (!canLoad()) {
            throw new IOException("No source present to read from!");
        }
        try (BufferedReader reader = source.openBufferedStream()) {
            NodeType node;
            if (preservesHeader) {
                String comment = CommentHandlers.extractComment(reader, commentHandlers);
                if (comment != null && comment.length() > 0) {
                    options = options.setHeader(comment);
                }
            }
            node = createEmptyNode(options);
            loadInternal(node, reader);
            return node;
        } catch (FileNotFoundException e) {
            // Squash -- there's nothing to read
        }
        return createEmptyNode(options);
    }

    protected abstract void loadInternal(NodeType node, BufferedReader reader) throws IOException;

    @Override
    public void save(ConfigurationNode node) throws IOException {
        if (!canSave()) {
            throw new IOException("No sink present to write to!");
        }
        try (Writer writer = sink.openBufferedStream()) {
            String header = node.getOptions().getHeader();
            if (header != null && !header.isEmpty()) {
                for (String line : getDefaultCommentHandler().toComment(ImmutableList.copyOf(LINE_SPLITTER.split(header)))) {
                    writer.write(line);
                    writer.write(LINE_SEPARATOR);
                }
                writer.write(LINE_SEPARATOR);
            }
            saveInternal(node, writer);
        }
    }

    protected abstract void saveInternal(ConfigurationNode node, Writer writer) throws IOException;

    public boolean canLoad() {
        return this.source != null;
    }

    public boolean canSave() {
        return this.sink != null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy