summaryrefslogtreecommitdiffstats
path: root/infra/minimal-distribution/src/main/java/io/fd
diff options
context:
space:
mode:
authorJan Srnicek <jsrnicek@cisco.com>2016-10-13 13:56:47 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-10-13 13:28:56 +0000
commit6c3f614edb18bdb8cc6e7b87627f240d97a258c3 (patch)
tree52b9e116e7984d72a94ddee1c4b70b363e05c6ac /infra/minimal-distribution/src/main/java/io/fd
parent9d69639d39bd55628cadc445e816fcccf23c1361 (diff)
HONEYCOMB-207 : Configurable modules list for distributions
Export list of modules for built distribution on compile time according to distribution.modules property to ***module-config.txt Load aggregated set of modules on start from all descriptors in /modules folder Change-Id: Icdeb23536aee3a243a221d3f2ec5f340d387764e Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'infra/minimal-distribution/src/main/java/io/fd')
-rw-r--r--infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/ActiveModuleProvider.java154
-rw-r--r--infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java36
2 files changed, 165 insertions, 25 deletions
diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/ActiveModuleProvider.java b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/ActiveModuleProvider.java
new file mode 100644
index 000000000..03c56969d
--- /dev/null
+++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/ActiveModuleProvider.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.infra.distro;
+
+import com.google.common.collect.ImmutableList;
+import com.google.inject.Module;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides list of active modules for distribution
+ */
+public class ActiveModuleProvider {
+
+ public static final String STANDARD_MODULES_RELATIVE_PATH = "../modules/";
+ private static final Logger LOG = LoggerFactory.getLogger(ActiveModuleProvider.class);
+
+ /**
+ * Provide unique set of active modules filtered from provided resources
+ */
+ public static Set<Module> loadActiveModules(@Nonnull final List<String> moduleNames) {
+ final ClassLoader classLoader = ActiveModuleProvider.class.getClassLoader();
+ LOG.info("Reading active modules configuration for distribution");
+
+ // process resources to resource modules
+ return moduleNames.stream()
+ .map(String::trim)
+ .filter(trimmedLine -> trimmedLine.length() != 0)
+ // filter out commented lines
+ .filter(nonEmptyLine -> !nonEmptyLine.startsWith("//"))
+ // filter duplicates
+ .distinct()
+ .map(validLine -> nameToClass(validLine, classLoader))
+ // filters out classes that are not modules
+ .filter(ActiveModuleProvider::filterNonModules)
+ .map(ActiveModuleProvider::classToInstance)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Aggregate all resources from provided relative path into a {@code List<String>}
+ */
+ public static List<String> aggregateResources(final String relativePath, final ClassLoader classLoader) {
+ try {
+ return Collections.list(classLoader.getResources(relativePath)).stream()
+ .map(ActiveModuleProvider::toURI)
+ .flatMap(ActiveModuleProvider::folderToFile)
+ .map(File::toURI)
+ .map(Paths::get)
+ // readAll lines and add them to iteration
+ .flatMap(ActiveModuleProvider::readLines)
+ .collect(Collectors.toList());
+ } catch (IOException e) {
+ LOG.error("Unable to load resources from relative path {}", relativePath, e);
+ throw new IllegalStateException("Unable to load resources from relative path " + relativePath, e);
+ }
+ }
+
+ private static Stream<File> folderToFile(final URI uri) {
+ final File[] files = new File(uri).listFiles(File::isFile);
+
+ return files != null
+ ? ImmutableList.copyOf(files).stream()
+ : Collections.<File>emptyList().stream();
+ }
+
+ private static boolean filterNonModules(final Class<?> clazz) {
+ final boolean isModule = Module.class.isAssignableFrom(clazz);
+ if (!isModule) {
+ LOG.warn("Class {} is provided in modules configuration, but is not a Module and will be ignored", clazz);
+ }
+ return isModule;
+ }
+
+ /**
+ * Read lines from {@code Path}
+ */
+ private static Stream<String> readLines(final Path path) {
+ try {
+ return Files.readAllLines(path).stream();
+ } catch (IOException e) {
+ LOG.error("Unable to read content of {}", path, e);
+ throw new IllegalStateException("Unable to read content of " + path, e);
+ }
+ }
+
+ /**
+ * Converts {@code URL} to {@code URI}
+ */
+ private static URI toURI(final URL url) {
+ try {
+ return url.toURI();
+ } catch (URISyntaxException e) {
+ LOG.error("Unable to convert {} to uri", url);
+ throw new IllegalStateException("Unable to convert " + url + " to uri", e);
+ }
+ }
+
+ /**
+ * Loads class by provided name
+ */
+ private static Class<?> nameToClass(final String name,
+ final ClassLoader classLoader) {
+ try {
+ LOG.info("Loading module class {}", name);
+ return classLoader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ LOG.error("Unable to convert {} to class, make sure you've provided sources to classpath", name);
+ throw new IllegalStateException(
+ "Unable to convert " + name + " to class, make sure you've provided sources to classpath", e);
+ }
+ }
+
+ /**
+ * Creates instance of module class
+ */
+ private static Module classToInstance(final Class<?> moduleClass) {
+ try {
+ LOG.info("Creating instance for module {}", moduleClass);
+ return Module.class.cast(moduleClass.newInstance());
+ } catch (InstantiationException | IllegalAccessException e) {
+ LOG.error("Unable to create instance for class {}", moduleClass, e);
+ throw new IllegalStateException("Unable to create instance for class" + moduleClass, e);
+ }
+ }
+}
diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java
index d3a562d3a..3c62382c2 100644
--- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java
+++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java
@@ -16,8 +16,11 @@
package io.fd.honeycomb.infra.distro;
+import static io.fd.honeycomb.infra.distro.ActiveModuleProvider.STANDARD_MODULES_RELATIVE_PATH;
+import static io.fd.honeycomb.infra.distro.ActiveModuleProvider.aggregateResources;
+import static io.fd.honeycomb.infra.distro.ActiveModuleProvider.loadActiveModules;
+
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
import com.google.inject.ConfigurationException;
import com.google.inject.CreationException;
import com.google.inject.Guice;
@@ -28,20 +31,14 @@ import com.google.inject.ProvisionException;
import com.google.inject.name.Names;
import io.fd.honeycomb.data.init.DataTreeInitializer;
import io.fd.honeycomb.data.init.InitializerRegistry;
-import io.fd.honeycomb.infra.distro.cfgattrs.CfgAttrsModule;
import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
-import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
-import io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule;
import io.fd.honeycomb.infra.distro.initializer.InitializerPipelineModule;
import io.fd.honeycomb.infra.distro.netconf.HoneycombNotification2NetconfProvider;
import io.fd.honeycomb.infra.distro.netconf.NetconfModule;
-import io.fd.honeycomb.infra.distro.netconf.NetconfReadersModule;
import io.fd.honeycomb.infra.distro.netconf.NetconfSshServerProvider;
import io.fd.honeycomb.infra.distro.netconf.NetconfTcpServerProvider;
import io.fd.honeycomb.infra.distro.restconf.RestconfModule;
-import io.fd.honeycomb.infra.distro.schema.SchemaModule;
-import io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule;
-import java.util.List;
+import java.util.Set;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory;
@@ -53,29 +50,18 @@ public final class Main {
private static final Logger LOG = LoggerFactory.getLogger(Main.class);
- public static final List<Module> BASE_MODULES = ImmutableList.of(
- // Infra
- new YangBindingProviderModule(),
- new SchemaModule(),
- new ConfigAndOperationalPipelineModule(),
- new ContextPipelineModule(),
- new InitializerPipelineModule(),
- new NetconfModule(),
- new NetconfReadersModule(),
- new RestconfModule(),
- // Json config attributes
- new CfgAttrsModule());
-
- private Main() {}
+ private Main() {
+ }
public static void main(String[] args) {
- init(BASE_MODULES);
+ final ClassLoader classLoader = Main.class.getClassLoader();
+ init(loadActiveModules(aggregateResources(STANDARD_MODULES_RELATIVE_PATH, classLoader)));
}
/**
- * Initialize the Honeycomb infrastructure + all wired plugins.
+ * Initialize the Honeycomb with provided modules
*/
- public static Injector init(final List<? extends Module> modules) {
+ public static Injector init(final Set<? extends Module> modules) {
try {
LOG.info("Starting honeycomb");
Injector injector = Guice.createInjector(modules);