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

pro.jk.ejoker.common.context.dev2.EjokerRootDefinationStore Maven / Gradle / Ivy

There is a newer version: 3.0.7.1
Show newest version
package pro.jk.ejoker.common.context.dev2;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pro.jk.ejoker.common.context.ContextRuntimeException;
import pro.jk.ejoker.common.context.annotation.context.Dependence;
import pro.jk.ejoker.common.context.annotation.context.EInitialize;
import pro.jk.ejoker.common.context.annotation.context.EService;
import pro.jk.ejoker.common.system.enhance.EachUtilx;
import pro.jk.ejoker.common.system.functional.IVoidFunction2;
import pro.jk.ejoker.common.utils.ClassNamesScanner;
import pro.jk.ejoker.common.utils.genericity.GenericDefinedField;
import pro.jk.ejoker.common.utils.genericity.GenericExpression;
import pro.jk.ejoker.common.utils.genericity.GenericExpressionFactory;

public class EjokerRootDefinationStore implements IEJokerClazzScanner{
	
	private final static Logger logger = LoggerFactory.getLogger(EjokerRootDefinationStore.class);
	
	public static final String SELF_PACKAGE_NAME = "pro.jk.ejoker";

	/**
	 * EService类里面有等待被注入的属性
	 */
	private final Map, Map> eDependenceMapper = new HashMap<>();

	/**
	 * EInitialize类里面有声明要初始化执行的方法
	 */
	private final Map, Map> eInitializeMapper = new HashMap<>();

	/**
	 * 记录已经分析过的middleExpression
	 */
	private final Map, GenericExpression> eServiceMiddleExpressions = new HashMap<>();
	
	/**
	 * 记录已经经过采集定义信息的类
	 */
	private final Set> hasBeenAnalyzeClass = new HashSet<>();

	private Map, IEjokerClazzScannerHook> hookMap = new LinkedHashMap<>();
	
//	/**
//	 * 放入扫描过的包得路径的字符串
//	 */
//	private final Set hasScanPackage = new HashSet<>();
	private AtomicBoolean rootSkeletonScanFlag = new AtomicBoolean(false);
	
	/**********public method*********/
	
	public Map getEDependenceRecord(Class clazz) {
		return eDependenceMapper.get(clazz);
	}
	
	public Map getEInitializeRecord(Class clazz) {
		return eInitializeMapper.get(clazz);
	}
	
	public void annotationScan(String specificPackage) {
		if ( specificPackage.lastIndexOf('.') == (specificPackage.length()-1) )
			specificPackage = specificPackage.substring(0, specificPackage.length()-1);
		// ## 此段导致不同jar中的同名包会被忽略,产生意料之外的错误
//		for ( String key : hasScanPackage )
//			if(specificPackage.startsWith(key)) return;// 传入的包是某个已经被分析的包的子包或就是已存在的包,则不再分析
		if ( SELF_PACKAGE_NAME.equals(specificPackage) ) {
			if( !rootSkeletonScanFlag.compareAndSet(false, true) ) {
				throw new ContextRuntimeException("Unsupport your owner package is same with " + SELF_PACKAGE_NAME + " or scan it twice!!!");
			}
		} else if ( specificPackage.startsWith(SELF_PACKAGE_NAME) ) {
			if( !specificPackage.endsWith("defaultMemoryImpl") )
				logger.warn(" !!! YOUR owner package's name sequence in \"" + SELF_PACKAGE_NAME + "\" maybe result is some unexcepted status!");
		}
		
		List> clazzInSpecificPackage;
		try {
			clazzInSpecificPackage = ClassNamesScanner.scanClass(specificPackage);
		} catch (ClassNotFoundException ex) {
			throw new ContextRuntimeException(String.format("Exception occur whild scanning package [%s]!!!", specificPackage), ex);
		}
//		hasScanPackage.add(specificPackage + ".");

		for (Class clazz:clazzInSpecificPackage) {
			// skip Throwable \ Abstract \ Interface class
			if(
					Throwable.class.isAssignableFrom(clazz)
					|| Modifier.isAbstract(clazz.getModifiers())
					|| clazz.isInterface())
				continue;
			process(clazz);

			EachUtilx.forEach(hookMap, (hookType, hook) -> hook.process(clazz));
		}
	}
	
	private void process(Class clazz) {

		// 已经分析过的类就跳过
		if(hasBeenAnalyzeClass.contains(clazz))
			return;
		else
			hasBeenAnalyzeClass.add(clazz);
		

		// 只关注被标记EService的类
		if(!clazz.isAnnotationPresent(EService.class))
			return;
		
		GenericExpression middleExpression = GenericExpressionFactory.getMiddleStatementGenericExpression(clazz);
		eServiceMiddleExpressions.put(clazz, middleExpression);
		
		// 同名方法在在不同的对象中的反射Method是不一样的,用方法名作唯一控制会更好
		// 分析会从子类到父类方向延伸,如果子类中出现过此方法,则会被跳过
		Map reflectInitializeMethodStore = new LinkedHashMap<>();
		// 同名属性在在不同的对象中的反射Field是不一样的,用属性名作唯一控制会更好
		// 分析会从子类到父类方向延伸,如果子类中出现过此方法,则会被跳过
		Map reflectDependenceGenericDefinedFieldStore = new LinkedHashMap<>();
		
		for(
				GenericExpression currentExpression = middleExpression;
				null != currentExpression && !Object.class.equals(currentExpression.getDeclarePrototype());
				currentExpression = currentExpression.getParent()
						) {
			Class declaredClazz = currentExpression.getDeclarePrototype();
			
			currentExpression.forEachFieldExpressions((fieldName, genericDefinedField) -> {
				Field field = genericDefinedField.field;
				if ( field.isAnnotationPresent(Dependence.class) ) {
					reflectDependenceGenericDefinedFieldStore.putIfAbsent(fieldName, genericDefinedField);
				}
			});
			
			Method[] declaredMethods = declaredClazz.getDeclaredMethods();
			if(null != declaredMethods) {
				for(Method method : declaredMethods) {

					// 已经添加过的方法
					if ( reflectInitializeMethodStore.containsKey(method.getName()) )
						continue;
					if ( !method.isAnnotationPresent(EInitialize.class) )
						continue;

					// 默认规则: 初始化函数不传参
					/// * 带上参数后存在大量分析拆解以及上下文匹配工作,参数完全可以通过其他方法传入
					if (method.getParameterCount() > 0) {
						logger.error("Unsupport pass parameters to @Initialize method now!!! Found at {}#{}()",
								clazz.getName(), method.getName());
						throw new ContextRuntimeException("Unsupport pass parameters to @Initialize method now!!!");
					}
					method.setAccessible(true);
					reflectInitializeMethodStore.put(method.getName(), method);
				}
			}
		}
		
		eDependenceMapper.put(clazz, reflectDependenceGenericDefinedFieldStore);
		eInitializeMapper.put(clazz, reflectInitializeMethodStore);
		
	}

	@Override
	public void scanPackage(String javaPackage) {
		annotationScan(javaPackage);
	}

	@Override
	public void registeScannerHook(IEjokerClazzScannerHook hook) {
		if(null != hookMap.putIfAbsent(hook.getClass(), hook)) {
			logger.warn("Context Hook has regist before! It will ignore this invokation. [hookType: {}] ", hook.getClass().getName());
		};
	}
	
	public void forEachEServiceExpressions(IVoidFunction2, GenericExpression> vf) {
		EachUtilx.forEach(eServiceMiddleExpressions, vf);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy