ConfigLoader.java
/*
* Copyright 2016,2017 Providence Authors
*
* 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 net.morimekta.providence.config;
import net.morimekta.providence.PMessage;
import net.morimekta.providence.config.impl.ProvidenceConfigSupplier;
import net.morimekta.providence.config.impl.ResourceConfigSupplier;
import net.morimekta.providence.config.parser.ConfigException;
import net.morimekta.providence.config.parser.ConfigParser;
import net.morimekta.providence.config.parser.ConfigWarning;
import net.morimekta.providence.config.util.FileContentResolver;
import net.morimekta.providence.config.util.ResourceContentResolver;
import net.morimekta.providence.types.TypeRegistry;
import net.morimekta.util.FileWatcher;
import javax.annotation.Nonnull;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Clock;
import java.util.function.Consumer;
/**
* Providence config loader. This loads providence configs.
*/
public class ConfigLoader implements AutoCloseable {
/**
* Make a non-strict config instance.
*
* @param registry The type registry used to find message and enum types.
*/
public ConfigLoader(@Nonnull TypeRegistry registry) {
this(registry,
warning -> System.err.println(warning.displayString()));
}
/**
* Make a non-strict config instance.
*
* @param registry The type registry used to find message and enum types.
* @param warningHandler Handle parse warnings.
*/
public ConfigLoader(@Nonnull TypeRegistry registry,
@Nonnull Consumer<ConfigWarning> warningHandler) {
this(registry, new FileWatcher(), warningHandler, false);
}
/**
* Make a config instance.
*
* @param registry The type registry used to find message and enum types.
* @param watcher File watcher used to detect config file updates.
* @param warningHandler Handle parse warnings.
* @param strict If the config should be parsed and verified strictly.
*/
public ConfigLoader(@Nonnull TypeRegistry registry,
@Nonnull FileWatcher watcher,
@Nonnull Consumer<ConfigWarning> warningHandler,
boolean strict) {
this(registry, watcher, warningHandler, strict, Clock.systemUTC());
}
/**
* Make a config instance.
*
* @param registry The type registry used to find message and enum types.
* @param watcher File watcher used to detect config file updates.
* @param warningHandler Handle parse warnings.
* @param strict If the config should be parsed strictly.
* @param clock The clock to use in timing config loads.
*/
public ConfigLoader(@Nonnull TypeRegistry registry,
@Nonnull FileWatcher watcher,
@Nonnull Consumer<ConfigWarning> warningHandler,
boolean strict,
@Nonnull Clock clock) {
this.watcher = watcher;
this.clock = clock;
this.resourceParser = new ConfigParser(registry, new ResourceContentResolver(), warningHandler, strict);
this.fileParser = new ConfigParser(registry, new FileContentResolver(), warningHandler, strict);
}
/**
* Load a config file overlaying another config.
*
* @param configFile The file to resolve.
* @param parentConfig The parent config supplier if any.
* @param <M> The message type.
* @return The resolved config.
* @throws ConfigException If parsing of config failed.
*/
@Nonnull
public <M extends PMessage<M>>
ConfigSupplier<M> loadFile(@Nonnull Path configFile,
@Nonnull ConfigSupplier<M> parentConfig)
throws ConfigException {
return new ProvidenceConfigSupplier<>(
configFile, parentConfig, watcher, fileParser, clock);
}
/**
* Load a config file without parent config like on config file includes.
*
* @param configFile The file to resolve.
* @param <M> The message type.
* @return The resolved config.
* @throws ConfigException If parsing of config failed.
*/
@Nonnull
public <M extends PMessage<M>>
ConfigSupplier<M> loadFile(@Nonnull Path configFile)
throws ConfigException {
return new ProvidenceConfigSupplier<>(
configFile, null, watcher, fileParser, clock);
}
/**
* Load a config resource without parent config like on config file includes.
*
* @param resourcePath The file to resolve.
* @param <M> The message type.
* @return The resolved config.
* @throws ConfigException If parsing of config failed.
*/
public <M extends PMessage<M>>
ConfigSupplier<M> loadResource(@Nonnull String resourcePath)
throws ConfigException {
return new ResourceConfigSupplier<>(
Paths.get(resourcePath), resourceParser, clock);
}
/**
* Get config for the given file.
*
* @param configFile The file to read config for.
* @param <M> The config message type.
* @return The config message.
* @throws ConfigException On config load failure.
*/
@Nonnull
public <M extends PMessage<M>>
M getConfig(@Nonnull Path configFile) throws ConfigException {
return fileParser.<M>parseConfig(configFile, null).first;
}
/**
* Get config for the given with parent.
*
* @param configFile The file to read config for.
* @param parent The designated parent config.
* @param <M> The config message type.
* @return The config message.
* @throws ConfigException On config load failure.
*/
@Nonnull
public <M extends PMessage<M>>
M getConfig(@Nonnull Path configFile, @Nonnull M parent) throws ConfigException {
return fileParser.parseConfig(configFile, parent).first;
}
@Override
public void close() {
watcher.close();
}
private final FileWatcher watcher;
private final Clock clock;
private final ConfigParser resourceParser;
private final ConfigParser fileParser;
}