/*
* Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
*
* Licensed under the EUPL, Version 1.1 or – as soon they
* will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
*
* You may not use this work except in compliance with the Licence.
*
* You may obtain a copy of the Licence at:
*
* https://joinup.ec.europa.eu/community/eupl/og_page/eupl
*
* Unless required by applicable law or agreed to in
* writing, software distributed under the Licence is
* distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the Licence for the specific language governing
* permissions and limitations under the Licence.
*/
package no.difi.oxalis.commons.guice;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.util.Modules;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import no.difi.oxalis.api.lang.OxalisLoadingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
/**
* Implementation for loading of Guice modules on same principles discussed on
* <a href="http://stackoverflow.com/q/902639/135001">StackOverflow</a>, however this implementation uses
* <a href="https://github.com/typesafehub/config">Typesafe Config</a> instead of Java ServiceLoader to allow for
* further configuration than only "detected".
*
* @author erlend
*/
public class GuiceModuleLoader extends AbstractModule {
private static Logger logger = LoggerFactory.getLogger(GuiceModuleLoader.class);
private static String PREFIX = "oxalis.module";
private static String CLS = "class";
private static String ENABLED = "enabled";
private static String OVERRIDE = "override";
private static String DEPENDENCY = "dependency";
public static Injector initiate(Module... modules) {
List<Module> moduleList = new ArrayList<>();
moduleList.addAll(getModules());
moduleList.addAll(Arrays.asList(modules));
return Guice.createInjector(moduleList);
}
@Override
protected void configure() {
getModules().forEach(binder()::install);
}
protected static List<Module> getModules() {
// Initial loading of configuration.
Config config = ConfigFactory.defaultReference();
// List to gather configurations for modules.
Map<String, Config> moduleConfigs = new HashMap<>();
// Go through the two levels of identifiers for module configurations.
for (String group : config.getObject(PREFIX).keySet()) {
for (String module : config.getObject(String.format("%s.%s", PREFIX, group)).keySet()) {
// Fetch configuration for the combination of group and module identifiers.
Config moduleConfig = config.getConfig(String.format("%s.%s.%s", PREFIX, group, module));
// Do not include disabled modules.
if (!moduleConfig.hasPath(ENABLED) || moduleConfig.getBoolean(ENABLED))
moduleConfigs.put(String.format("%s.%s", group, module), moduleConfig);
}
}
return moduleConfigs.values().stream()
// Verify depending module is enabled.
.filter(mc -> !mc.hasPath(DEPENDENCY) || moduleConfigs.containsKey(mc.getString(DEPENDENCY)))
// Create Module instances from configuration.
.map(GuiceModuleLoader::load)
// Collect into list.
.collect(Collectors.toList());
}
protected static Module load(Config config) {
// Loading with override.
if (config.hasPath(OVERRIDE)) {
logger.debug("Loading module '{}' with override.", config.getString(CLS));
return Modules.override(loadModule(config.getString(CLS)))
.with(loadModule(config.getString(OVERRIDE)));
}
// Loading without override.
logger.debug("Loading module '{}'.", config.getString(CLS));
return loadModule(config.getString(CLS));
}
protected static Module loadModule(String className) {
try {
return (Module) Class.forName(className).newInstance();
} catch (Exception e) {
throw new OxalisLoadingException(e.getMessage(), e);
}
}
}