com.cyc.session.internal.ConfigurationLoaderManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cyc-session-client Show documentation
Show all versions of cyc-session-client Show documentation
Session API implementation for managing configurations and connections to Cyc servers.
package com.cyc.session.internal;
/*
* #%L
* File: ConfigurationLoaderManager.java
* Project: Session Client
* %%
* Copyright (C) 2013 - 2017 Cycorp, Inc.
* %%
* 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.
* #L%
*/
import com.cyc.session.CycSessionConfiguration;
import com.cyc.session.EnvironmentConfiguration;
import com.cyc.session.configuration.ConfigurationValidator;
import com.cyc.session.exception.SessionConfigurationException;
import com.cyc.session.services.EnvironmentConfigurationLoader;
import com.cyc.session.services.PropertiesConfigurationLoader;
import com.cyc.session.services.SimpleInteractiveLoader;
import com.cyc.session.spi.SessionConfigurationLoader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The ConfigurationLoaderManager is responsible for loading
* {@link SessionConfigurationLoader} services, and calling them to load
* configurations.
*
* @author nwinant
*/
public class ConfigurationLoaderManager {
// Fields
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationLoaderManager.class);
final private Map configLoaders = new HashMap<>();
// Constructor
public ConfigurationLoaderManager() throws SessionConfigurationException {
reloadConfigurationLoaders();
}
// Public
public CycSessionConfiguration getConfiguration(EnvironmentConfiguration environment) throws SessionConfigurationException {
final CycSessionConfiguration config = expandConfiguration(environment, environment);
final ConfigurationValidator configUtils = new ConfigurationValidator(config);
if (!configUtils.isValid()) {
throw new SessionConfigurationException("Configuration " + config + "is not valid; could not retrieve a valid configuration from " + config.getLoaderClass().getName());
}
return config;
}
/**
* Recurses over CycSessionConfiguration if it specifies another configuration.
*
* CycSessionConfigurations can specify other CycSessionConfigurations. For
* example, an EnvironmentConfiguration could specify to load a configuration
* from a particular properties file, which in turn says to interactively
* prompt the user for configuration data. Typically you wouldn't want to
* chain beyond two levels -- an environmental configuration specifying
* another configuration method -- but there are cases where you might, and
* this allows that flexibility.
*
* Order of precedence:
*
* - If the CycSessionConfiguration is sufficiently configured, use it.
* - Load a configuration file, if specified.
* - Use a {@link SessionConfigurationLoader}, if one is specified.
* - Poll the user interactively via a GUI prompt, if allowed and if in a graphical environment.
* - Otherwise, return the original (presumably insufficient) configuration to be dealt with somehow.
*
*
* @param config
* @param environment
* @return the configuration
* @throws SessionConfigurationException
*/
public CycSessionConfiguration expandConfiguration(CycSessionConfiguration config, EnvironmentConfiguration environment) throws SessionConfigurationException {
// TODO: add an enforced max depth param.
// TODO: add loop checking.
final ConfigurationValidator configUtils = new ConfigurationValidator(config);
if (configUtils.isSufficient()) {
LOGGER.debug("Found a sufficient configuration: {}", config);
return config;
}
if (config.getConfigurationFileName() != null) {
return expandConfiguration(loadConfigurationViaConfigFileName(config.getConfigurationLoaderName(), environment), environment);
}
if (config.getConfigurationLoaderName() != null) {
return expandConfiguration(loadConfigurationViaConfigLoaderName(config.getConfigurationLoaderName(), environment), environment);
}
if (isGuiAllowed(environment)) {
return expandConfiguration(loadConfigurationViaGUI(environment), environment);
}
LOGGER.warn("Configuration is not sufficient, but cannot be expanded: {}", config);
// TODO: should we throw an exception when a configuration can't be expanded and isn't sufficient?
return config;
}
public CycSessionConfiguration loadConfiguration(SessionConfigurationLoader loader, EnvironmentConfiguration environment) throws SessionConfigurationException {
LOGGER.debug("Retrieving configuration from {}.", loader.getClass());
loader.setEnvironment(environment);
if (!loader.isCapableOfSuccess()) {
throw new SessionConfigurationException("Loader " + loader.getClass() + " was selected, but is not capable of success.");
}
return loader.getConfiguration();
}
public CycSessionConfiguration loadConfigurationViaConfigLoaderName(String configLoaderName, EnvironmentConfiguration environment) throws SessionConfigurationException {
LOGGER.debug("Attempting to load configuration named '{}'...", configLoaderName);
if (EnvironmentConfigurationLoader.NAME.equals(configLoaderName)) {
// Internal EnvironmentConfigurationLoader always gets precedence
return loadConfiguration(new EnvironmentConfigurationLoader(), environment);
}
if (getConfigurationLoaders().containsKey(configLoaderName)) {
final SessionConfigurationLoader loader = getConfigurationLoaders().get(configLoaderName);
return loadConfiguration(loader, environment);
}
throw new SessionConfigurationException("SessionConfigurationLoader named '" + configLoaderName + "' was requested, but no such loader could be found.");
}
public CycSessionConfiguration loadConfigurationViaConfigFileName(String filename, EnvironmentConfiguration environment) throws SessionConfigurationException {
LOGGER.debug("Attempting to load configuration via config file {}...", filename);
return loadConfiguration(new PropertiesConfigurationLoader(), environment);
}
public CycSessionConfiguration loadConfigurationViaGUI(EnvironmentConfiguration environment) throws SessionConfigurationException {
LOGGER.debug("Attempting to load configuration interactively via GUI...");
return loadConfiguration(new SimpleInteractiveLoader(), environment);
}
// Protected
protected boolean isGuiAllowed(EnvironmentConfiguration environment) {
return environment.getManagerConfiguration().isGuiInteractionAllowed()
&& !EnvironmentConfigurationLoader.isHeadlessEnvironment();
}
protected Map getConfigurationLoaders() {
return Collections.unmodifiableMap(this.configLoaders);
}
final protected void reloadConfigurationLoaders() throws SessionConfigurationException {
// Note: The relevant service provider file in META-INF/services
// is generated by the serviceloader-maven-plugin, specified
// in the pom.xml file.
configLoaders.clear();
ServiceLoader loader
= ServiceLoader.load(SessionConfigurationLoader.class);
for (SessionConfigurationLoader configLoader : loader) {
final String name = configLoader.getName();
if (configLoaders.containsKey(name)) {
Class oldClass = configLoaders.get(name).getClass();
throw new SessionConfigurationException(
"Error attempting to add " + SessionConfigurationLoader.class.getSimpleName()
+ " named '" + name + "' (" + configLoader.getClass() + "):"
+ " Loader " + oldClass + " already registered under that name");
}
configLoaders.put(name, configLoader);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy