/**
* Copyright (c) 2013-2016, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.core.internal.init;
import io.nuun.kernel.api.Kernel;
import io.nuun.kernel.api.Plugin;
import io.nuun.kernel.api.config.KernelConfiguration;
import io.nuun.kernel.core.NuunCore;
import io.nuun.kernel.core.internal.scanner.AbstractClasspathScanner;
import org.reflections.vfs.Vfs;
import org.seedstack.seed.core.SeedRuntime;
import org.seedstack.seed.core.internal.configuration.ConfigurationPlugin;
import org.seedstack.seed.core.internal.scan.ClasspathScanHandler;
import org.seedstack.seed.core.internal.scan.FallbackUrlType;
import org.seedstack.seed.diagnostic.DiagnosticManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
public class KernelManager {
private static final Logger LOGGER = LoggerFactory.getLogger(KernelManager.class);
private final List<Vfs.UrlType> savedUrlTypes;
private final List<Vfs.UrlType> detectedUrlTypes;
private static class Holder {
private static final KernelManager INSTANCE = new KernelManager();
}
public static KernelManager get() {
return Holder.INSTANCE;
}
private KernelManager() {
// Load Nuun and Reflections classes to force initialization of Vfs url types
try {
Class.forName(Vfs.class.getCanonicalName());
Class.forName(AbstractClasspathScanner.class.getCanonicalName());
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot initialize the classpath scanning infrastructure", e);
}
// Save existing url types
savedUrlTypes = Vfs.getDefaultUrlTypes();
// Find all classpath scan handlers and add their Vfs url types
List<Vfs.UrlType> urlTypes = new ArrayList<>();
for (ClasspathScanHandler classpathScanHandler : ServiceLoader.load(ClasspathScanHandler.class)) {
LOGGER.trace("Detected classpath handler {}", classpathScanHandler.getClass().getCanonicalName());
urlTypes.addAll(classpathScanHandler.urlTypes());
}
LOGGER.debug("URL types for scanning: {}", urlTypes);
detectedUrlTypes = urlTypes;
}
public Kernel createKernel(SeedRuntime seedRuntime, @Nullable KernelConfiguration kernelConfiguration, boolean autoStart) {
long startTime = System.currentTimeMillis();
if (kernelConfiguration == null) {
kernelConfiguration = NuunCore.newKernelConfiguration();
}
kernelConfiguration.containerContext(seedRuntime);
Kernel kernel = createKernel(kernelConfiguration, seedRuntime.getDiagnosticManager());
if (autoStart) {
kernel.start();
LOGGER.info("{} started in {} second(s)", getApplicationName(kernel), (System.currentTimeMillis() - startTime) / 1000d);
}
return kernel;
}
public void disposeKernel(Kernel kernel) {
if (kernel != null && kernel.isStarted()) {
String applicationName = getApplicationName(kernel);
kernel.stop();
LOGGER.info("{} stopped", applicationName);
}
}
private synchronized Kernel createKernel(KernelConfiguration kernelConfiguration, DiagnosticManager diagnosticManager) {
// Kernel instantiation
Kernel kernel = NuunCore.createKernel(kernelConfiguration);
FallbackUrlType fallbackUrlType = new FallbackUrlType();
List<Vfs.UrlType> urlTypes = new ArrayList<>(detectedUrlTypes);
urlTypes.add(fallbackUrlType);
LOGGER.debug("Registered URL types for classpath scan: " + urlTypes);
// Kernel initialization (it is assumed that only this class alter Vfs default url types)
Vfs.setDefaultURLTypes(urlTypes);
kernel.init();
Vfs.setDefaultURLTypes(savedUrlTypes);
// Log if any URL were not scanned
int failedUrlCount = fallbackUrlType.getFailedUrls().size();
if (failedUrlCount > 0) {
LOGGER.info("{} URL(s) were not scanned, enable debug logging to see them", failedUrlCount);
if (LOGGER.isTraceEnabled()) {
for (URL failedUrl : fallbackUrlType.getFailedUrls()) {
LOGGER.debug("URL not scanned: {}", failedUrl);
}
}
}
diagnosticManager.registerDiagnosticInfoCollector("kernel", () -> {
Map<String, Object> result = new HashMap<>();
result.put("scannedUrls", kernel.scannedURLs());
result.put("failedUrls", fallbackUrlType.getFailedUrls());
return result;
});
return kernel;
}
private String getApplicationName(Kernel kernel) {
Plugin plugin = kernel.plugins().get(ConfigurationPlugin.NAME);
if (plugin instanceof ConfigurationPlugin) {
return ((ConfigurationPlugin) plugin).getApplication().getName();
} else {
return "Seed";
}
}
}