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

com.nu.art.modular.core.ModuleManager Maven / Gradle / Ivy

There is a newer version: 1.2.59
Show newest version
/*
 * The module-manager project, is THE infrastructure that all my frameworks
 *  are based on, it allows encapsulation of logic where needed, and allow
 *  modules to converse without other design patterns limitations.
 *
 * Copyright (C) 2017  Adam van der Kruk aka TacB0sS
 *
 * 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 com.nu.art.modular.core;

import com.nu.art.belog.Logger;
import com.nu.art.core.exceptions.runtime.BadImplementationException;
import com.nu.art.core.exceptions.runtime.ImplementationMissingException;
import com.nu.art.core.exceptions.runtime.WhoCalledThis;
import com.nu.art.core.generics.Processor;
import com.nu.art.core.tools.ArrayTools;
import com.nu.art.modular.core.EventDispatcher.ProcessorGenericParamExtractor;
import com.nu.art.modular.interfaces.ModuleManagerDelegator;
import com.nu.art.reflection.injector.Injector;
import com.nu.art.reflection.tools.ART_Tools;
import com.nu.art.reflection.tools.ReflectiveTools;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author TacB0sS
 */
@SuppressWarnings("rawtypes")
public class ModuleManager
		extends Logger
		implements ModuleManagerDelegator {

	public interface OnModuleInitializedListener {

		void onModuleInitialized(Module module);
	}

	public final class ModuleInjector
			extends Injector {

		private ModuleInjector() {}

		@Override
		@SuppressWarnings("unchecked")
		protected Object getValueForField(Object instance, Field field) {
			if (field.getType() == Module.class)
				return null;

			Module module = getModule((Class) field.getType(), false);
			if (module == null)
				throw new ImplementationMissingException("Cannot set module to field: " + field + "\n  MUST add the module of type: '" + field.getType() + "' to one of your ModulePacks");

			return module;
		}

		@Override
		protected Field[] extractFieldsFromInstance(Class injecteeType) {
			return ART_Tools.getFieldsWithAnnotationAndTypeFromClassHierarchy(injecteeType, Object.class, null, null, Module.class);
		}
	}

	private final ModuleInjector moduleInjector = new ModuleInjector();

	private OnModuleInitializedListener moduleInitializedListener;

	/**
	 * Holds a references to all the module types which have registered to this main module,
	 */
	private HashMap, Module> registeredModules = new HashMap<>();

	private EventDispatcher eventDispatcher;

	private Module[] orderedModules = {};

	public static ModuleManager ModuleManager;

	protected ModuleManager(ProcessorGenericParamExtractor paramExtractor) {
		if (ModuleManager != null)
			throw new BadImplementationException("THERE CAN ONLY BE ONE MODULE MANAGER IN A JVM!!");

		eventDispatcher = new EventDispatcher("ModulesEventDispatcher", paramExtractor);
		ModuleManager = this;
	}

	public final ModuleInjector getInjector() {
		return moduleInjector;
	}

	@SuppressWarnings("unchecked")
	public final  Type[] getModulesAssignableFrom(Class classType) {
		ArrayList modules = new ArrayList<>();
		for (Module orderedModule : orderedModules) {
			if (!classType.isAssignableFrom(orderedModule.getClass()))
				continue;

			modules.add((Type) orderedModule);
		}
		return ArrayTools.asArray(modules, classType);
	}

	@Override
	public final  ModuleType getModule(Class moduleType) {
		return getModule(moduleType, true);
	}

	final void setOrderedModules(Module[] orderedModules) {
		this.orderedModules = orderedModules;
		for (Module orderedModule : orderedModules) {
			eventDispatcher.addListener(orderedModule);
		}
	}

	protected final Module[] getOrderedModules() {
		return orderedModules;
	}

	public final void setModuleListener(OnModuleInitializedListener moduleInitializedListener) {
		this.moduleInitializedListener = moduleInitializedListener;
	}

	@SuppressWarnings("unchecked")
	private  ModuleType getModule(Class moduleType, boolean throwException) {
		ModuleType module = (ModuleType) registeredModules.get(moduleType);
		if (module == null && throwException) {
			throw new ImplementationMissingException("MUST add module of type: '" + moduleType.getName() + "' to one of your module packs");
		}
		return module;
	}

	final void init() {
		for (Module module : orderedModules) {
			module.assignToDefaultInterface();
		}

		for (Module module : orderedModules) {
			module.init();

			if (moduleInitializedListener == null)
				continue;

			moduleInitializedListener.onModuleInitialized(module);
		}
	}

	/**
	 * @param moduleType The module type to register with the Module Manager.
	 */
	@SuppressWarnings("unchecked")
	final <_Module extends Module> _Module registerModule(Class<_Module> moduleType) {
		_Module module = (_Module) registeredModules.get(moduleType);
		if (module != null)
			return null;

		module = ReflectiveTools.newInstance(moduleType);
		module.setMainManager(this);

		for (Class key : module.keys) {
			Module olderModule = registeredModules.put(key, module);
			if (olderModule != null)
				logWarning("Shared Module key " + key + " between modules: " + olderModule.getClass() + " and " + module.getClass());
		}

		return module;
	}

	protected void onBuildCompleted() {}

	@SuppressWarnings("unchecked")
	protected  void dispatchModuleEvent(String message, Processor processor) {
		eventDispatcher.dispatchEvent(new WhoCalledThis("dispatching: " + message), processor);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy