All Downloads are FREE. Search and download functionalities are using the official Maven repository.

host.anzo.core.startup.StartupManager Maven / Gradle / Ivy

There is a newer version: 1.29
Show newest version
package host.anzo.core.startup;

import host.anzo.commons.enums.ConsoleColors;
import host.anzo.commons.utils.ClassUtils;
import host.anzo.commons.utils.ConsoleUtils;
import host.anzo.commons.utils.SystemdUtils;
import host.anzo.commons.versioning.Version;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import host.anzo.classindex.ClassIndex;
import org.fusesource.jansi.AnsiConsole;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author ANZO
 * @since 27.12.2016
 */
@Slf4j
@StartupComponent("BeforeStart")
public class StartupManager {
	@Getter(lazy=true)
	private final static StartupManager instance = new StartupManager();

	private @Getter long loadStartTime;
	private @Getter long loadEndTime;
	
	private boolean isStartupCompleted = false;
	private final AtomicBoolean isShutDowning = new AtomicBoolean(false);

	private StartupManager() {
		System.setProperty("org.jooq.no-tips", "true");
		System.setProperty("org.jooq.no-logo", "true");

		AnsiConsole.systemInstall();
		new File("./log/").mkdir();

		try {
			Version.getInstance().init(Class.forName(Thread.currentThread().getStackTrace()[4].getClassName()));
		} catch (ClassNotFoundException ignored) {
		}

		ConsoleUtils.printSection("System Information");
		log.info("Operating System: {} Build: {}, Arch: {}", System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch"));
		log.info("Available CPU(s): {}", Runtime.getRuntime().availableProcessors());
		log.info("CPU Identifier: {}", System.getenv("PROCESSOR_IDENTIFIER"));
		log.info("JVM: {} Build: {}", System.getProperty("java.vm.name"), System.getProperty("java.runtime.version"));
	}

	public > void startup(@NotNull Class sl) {
		loadStartTime = System.currentTimeMillis();
		
		final StartupInstance startup = new StartupInstance<>();

		for(Class clazz : ClassIndex.getAnnotated(StartupComponent.class)) {
			final StartupComponent startupAnnotation = clazz.getAnnotation(StartupComponent.class);

			SL key = null;
			try {
				key = Enum.valueOf(sl, startupAnnotation.value());
			}
			catch (Exception ignored) {
			}

			if (key != null) {
				try {
					final StartModule module = new StartModule<>(key, clazz);
					startup.put(key, module);
				}
				catch (Exception e) {
					log.error("Error while loading class [{}] with [{}] StartupLevel", clazz.getSimpleName(), startupAnnotation.value(), e);
				}
			}
		}

		// Assign before/after methods to proper startup modules
		for (SL startupLevel : sl.getEnumConstants()) {
			final List> modules = startup.get(startupLevel);
			if (modules != null) {
				for (StartModule module : modules) {
					for (Map.Entry> entry : module.getBeforeMethods().entrySet()) {
						final IStartupLevel otherStartupLevel = (IStartupLevel)Enum.valueOf(sl, entry.getKey());
						for (StartupMethodInfo method : entry.getValue()) {
							otherStartupLevel.addBefore(method);
						}
					}
					for (Map.Entry> entry : module.getAfterMethods().entrySet()) {
						final IStartupLevel otherStartupLevel = (IStartupLevel)Enum.valueOf(sl, entry.getKey());
						for (StartupMethodInfo method : entry.getValue()) {
							otherStartupLevel.addAfter(method);
						}
					}
				}
			}
		}

		for(Map.Entry>> entry : startup.getAll()) {
			final List> invalidModules = new ArrayList<>();
			final List> modules = entry.getValue();
			for(StartModule module : modules) {
				final Class clazz = module.getClazz();
				final Class[] dependency = clazz.getAnnotation(StartupComponent.class).dependency();
				for(Class dep : dependency) {
					final Optional> dependencyModule = modules.stream()
							.filter(m -> m.getClazz().getCanonicalName().equals(dep.getCanonicalName()))
							.findAny();

					if(dependencyModule.isPresent()) {
						module.addDependency(dependencyModule.get());
					} else {
						invalidModules.add(module);
						log.warn("Not found dependency ({}) for {} on {} start level.", dep.getCanonicalName(), clazz.getCanonicalName(), module.getStartLevel().name());
					}
				}
			}

			modules.removeAll(invalidModules);
		}

		// Run registered components
		for (SL startupLevel : sl.getEnumConstants()) {
			ConsoleUtils.printSection(startupLevel.name(), ConsoleColors.Cyan);

			final IStartupLevel startupInterface = ((IStartupLevel)startupLevel);

			startupInterface.runBeforeMethods();
			startupInterface.before();

			if(startup.levelExists(startupLevel)) {
				startup.runLevel(startupLevel);
			}
			else {
				log.warn("No services found with level [{}] in current server instance! Consider to remove it from StartupLevel routine.", startupLevel);
			}

			startupInterface.runAfterMethods();
			startupInterface.after();
		}

		isStartupCompleted = true;
		loadEndTime = System.currentTimeMillis();
		
		SystemdUtils.notifyReady();
		
		log.info("{}Server loaded in [{}] second(s){}", ConsoleColors.Cyan.color(), getStartupTime(TimeUnit.SECONDS), ConsoleColors.Normal.color());
	}

	public void shutdown() {
		if (this.isShutDowning.compareAndSet(false, true)) {
			final Map>> classes = ClassIndex.getAnnotated(StartupComponent.class).stream()
					.filter(IShutdownable.class::isAssignableFrom).collect(Collectors.groupingBy(item -> {
						final StartupComponent component = item.getAnnotation(StartupComponent.class);
						if (component != null) {
							return component.shutdownPriority();
						}
						// TODO: Can happen for abstract methods (example: NetworkManager)
						return EShutdownPriority.ORDINAL;
					}));
			for (EShutdownPriority shutdownPriority : EShutdownPriority.values()) {
				final List> classesByPriority = classes.get(shutdownPriority);
				if (classesByPriority != null) {
					for (Class clazz : classesByPriority) {
						final Object singletonObject = ClassUtils.singletonInstance(clazz);
						if (singletonObject != null) {
							final IShutdownable shutdownable = (IShutdownable)singletonObject;
							try {
								log.info("Invoking [{}] onShutdown...", shutdownable.getClass().getSimpleName());
								shutdownable.onShutdown();
							}
							catch (Exception e) {
								log.error("Error while invoking [{}] onShutdown",shutdownable.getClass().getSimpleName(), e);
							}
						}
						else {
							log.error("Can't find singleton for IShutdownable=[{}]", clazz.getSimpleName());
						}
					}
				}
			}
			log.info("Server shutdown routine complete!");
		}
	}

	/**
	 * @return {@code true} if server startup routine completed, {@code false} otherwise
	 */
	public boolean isStartupCompleted() {
		return isStartupCompleted;
	}

	/**
	 * @return {@code true} if server doing shutdown routine at this moment, {@code false} otherwise
	 */
	public boolean isShutDowning() {
		return isShutDowning.get();
	}

	/**
	 * @param timeUnit time unit
	 * @return application loading time
	 */
	public long getStartupTime(@NotNull TimeUnit timeUnit) {
		return timeUnit.convert(loadEndTime - loadStartTime, TimeUnit.MILLISECONDS);
	}
	
	/**
	 * @param timeUnit time unit
	 * @return application uptime
	 */
	public int getUptime(@NotNull TimeUnit timeUnit) {
		return (int)timeUnit.convert(System.currentTimeMillis() - loadStartTime, TimeUnit.MILLISECONDS);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy