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

org.onetwo.dbm.mapping.MutilMappedEntryManager Maven / Gradle / Ivy

The newest version!
package org.onetwo.dbm.mapping;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import org.onetwo.common.annotation.AnnotationInfo;
import org.onetwo.common.log.JFishLoggerFactory;
import org.onetwo.common.reflect.ReflectUtils;
import org.onetwo.common.spring.SpringUtils;
import org.onetwo.common.spring.utils.ResourcesScanner;
import org.onetwo.common.spring.utils.ScanResourcesCallback;
import org.onetwo.common.utils.Assert;
import org.onetwo.common.utils.LangUtils;
import org.onetwo.common.utils.StringUtils;
import org.onetwo.common.utils.list.JFishList;
import org.onetwo.dbm.core.spi.DbmInnerServiceRegistry;
import org.onetwo.dbm.exception.DbmException;
import org.onetwo.dbm.exception.NoMappedEntryException;
import org.slf4j.Logger;
import org.springframework.core.io.Resource;
import org.springframework.core.type.classreading.MetadataReader;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;

public class MutilMappedEntryManager implements MappedEntryBuilder, MappedEntryManager {
	
	protected final Logger logger = JFishLoggerFactory.getLogger(this.getClass());

//	private Map entryCache = new ConcurrentHashMap();
	private List mappedEntryBuilders;
//	private MappedEntryListenerManager mappedEntryListenerManager;

	private ResourcesScanner scanner = ResourcesScanner.CLASS_CANNER;
//	private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	private Map nameEntryMapping = Maps.newConcurrentMap();
	private Cache entryCaches = CacheBuilder.newBuilder().build();
	private Cache readOnlyEntryCaches = CacheBuilder.newBuilder().build();
//	final private SimpleInnserServiceRegistry serviceRegistry;
//	private DBDialect dialet;
	private MappedEntryManagerListener mappedEntryManagerListener;
	private DbmInnerServiceRegistry serviceRegistry;


	public MutilMappedEntryManager(DbmInnerServiceRegistry serviceRegistry) {
		this.serviceRegistry = serviceRegistry;
	}
	
	
	public void setMappedEntryManagerListener(MappedEntryManagerListener mappedEntryManagerListener) {
		this.mappedEntryManagerListener = mappedEntryManagerListener;
	}


	/***
	 * first
	 */
	@Override
	public void initialize() {
	}


	/***
	 * second
	 */
	@Override
	public void scanPackages(String... packagesToScan) {
		CompletableFuture.runAsync(() -> {
			scanPackages0(packagesToScan);
		});
	}
	
	private void scanPackages0(String... packagesToScan) {
		Assert.notEmpty(mappedEntryBuilders, "no mapped entry builders ...");
		
		StringBuilder log = new StringBuilder();
		if (!LangUtils.isEmpty(packagesToScan)) {
			log.append("scan model package: ").append(Arrays.asList(packagesToScan)).append("\n");
			
			Collection entryClassNameList = scanner.scan(new ScanResourcesCallback() {

				@Override
				public ScanedClassContext doWithCandidate(MetadataReader metadataReader, Resource resource, int count) {
					if(!isSupported(metadataReader))
						return null;
					return new ScanedClassContext(metadataReader);
				}

			}, packagesToScan);
			

			if(mappedEntryManagerListener!=null){
				mappedEntryManagerListener.beforeBuild(this, entryClassNameList);
			}
			
			JFishList entryList = JFishList.create();
			int count = 0;
			for(ScanedClassContext ctx : entryClassNameList){
				String clsName = ctx.getClassName();
				Class clazz = ReflectUtils.loadClass(clsName);
				
				DbmMappedEntry entry = buildMappedEntry(clazz);
//				if(entry==null)
//					throw new DbmException("can not build the entity : " + clazz);
//				buildEntry(entry);
				log.append("build entity entry[").append(count++).append("]: ").append(entry.getEntityName()).append("\n");
				entryList.add(entry);
				
				String key = getCacheKey(entry.getEntityClass());
				if(StringUtils.isNotBlank(key))
					putInCache(key, entry);
				
			}

			//锁定
			for(DbmMappedEntry entry : entryList){
				entry.freezing();
			}
			
			if(logger.isInfoEnabled()){
				logger.info(log.toString());
			}
		}

	}
	
	/***
	 * 检查缓存
	 * @author weishao zeng
	 * @param entry
	 */
	private void buildEntry(DbmMappedEntry entry){
		buildEntry(entry, true);
	}
	
	private void buildEntry(DbmMappedEntry entry, boolean putToNameCache){
		if (putToNameCache && nameEntryMapping.containsKey(entry.getEntityName())) {
			throw new DbmException("duplicate entity name: " + entry.getEntityName())
						.put("exist entity", nameEntryMapping.get(entry.getEntityName()).getEntityClass())
						.put("conflicted entity", entry.getEntityClass());
		}
		try {
			entry.buildEntry();
		} catch (Exception e) {
			throw new DbmException("build entry["+entry.getEntityName()+"] error: "+e.getMessage(), e);
		}
		if (putToNameCache) {
			nameEntryMapping.put(entry.getEntityName(), entry);
		}
	}

	private void putInCache(String key, DbmMappedEntry entry) {
		this.entryCaches.put(key, entry);
	}

	@Override
	public boolean isSupported(Object entity) {
		for (MappedEntryBuilder em : mappedEntryBuilders) {
			if (em.isSupported(entity))
				return true;
		}
		return false;
	}

	@Override
	public DbmMappedEntry findEntry(Object object) {
		try {
			return getEntry(object);
		} catch (NoMappedEntryException e) {
			//ignore
		} catch (DbmException e) {
			throw e;
		} catch (Exception e) {
//			throw new DbmException("find entry error: " + e.getMessage(), e);
			logger.error("find entry error: " + e.getMessage());
		}
		return null;
	}

	@Override
	public DbmMappedEntry getEntry(Object objects) {
		Assert.notNull(objects, "the object arg can not be null!");
		DbmMappedEntry entry = null;
		
		Object object = LangUtils.getFirst(objects);
		if(object==null)
			throw new NoMappedEntryException("object can not null or emtpty, objects:"+objects);
		
		if(String.class.isInstance(object) && object.toString().indexOf('.')!=-1){
			object = ReflectUtils.loadClass(object.toString());
		}
		
		String key = getCacheKey(object);
		
		if (StringUtils.isBlank(key)) {
			//for map
			entry = buildMappedEntry(object);
//			mappedEntryListenerManager.fireAfterBuildEvents(entry);
//			buildEntry(entry);
//			mappedEntryListenerManager.fireAfterBuildEvents(entry);
			entry.freezing();
			return entry;
		}
		
		try {
			final Object entityObject = object;
			entry = entryCaches.get(key, ()->{
				DbmMappedEntry value = buildMappedEntry(entityObject);

//				if (value == null)
//					throw new NoMappedEntryException("can find build entry for this object, may be no mapping : " + entityObject.getClass());

//				buildEntry(value);
				value.freezing();
				return value;
			});
		} catch (ExecutionException e) {
			throw new DbmException("create entry error for entity: " + object, e);
		}
		return entry;
		
	}

	@Override
	public DbmMappedEntry buildMappedEntry(Object object) {
		DbmMappedEntry entry = null;
		for (MappedEntryBuilder em : mappedEntryBuilders) {
			if (!em.isSupported(object))
				continue;
			entry = em.buildMappedEntry(object);
			if (entry != null){
				buildEntry(entry);
				return entry;
			}
		}
		throw new NoMappedEntryException("the class["+ReflectUtils.getObjectClass(object)+"] is not a dbm entity, please use @DbmEntity or @Entity!");
//		return entry;
	}
	
	
	/***
	 * 
	 */
	@Override
	public DbmMappedEntry getReadOnlyEntry(final Class clazz) {
		Assert.notNull(clazz, "the class arg can not be null!");
		DbmMappedEntry entry = null;
		String key = getCacheKey(clazz);
		try {
			entry = readOnlyEntryCaches.get(key, ()->{
//				AnnotationInfo annotationInfo = new AnnotationInfo(clazz);
				AnnotationInfo annotationInfo = SpringUtils.createAnnotationInfo(clazz);
				JdbcRowEntryImpl rowEntry = new JdbcRowEntryImpl(annotationInfo, serviceRegistry);
				DbmMappedEntry value = buildMappedFields(rowEntry);

				if (value == null)
					throw new NoMappedEntryException("can find build entry for class : " + clazz);

				buildEntry(value, false);
				value.freezing();
				return value;
			});
		} catch (ExecutionException e) {
			throw new DbmException("create entry error for class: " + clazz, e);
		}
		return entry;
	}


	@Override
	public DbmMappedEntry buildMappedFields(DbmMappedEntry entry) {
		for (MappedEntryBuilder em : mappedEntryBuilders) {
			entry = em.buildMappedFields(entry);
			if (entry != null){
				return entry;
			}
		}
		return entry;
	}


	public boolean isSupportedMappedEntry(Object entity){
		if(mappedEntryBuilders.isEmpty())
			return false;
		return mappedEntryBuilders.stream().filter(b->b.isSupported(entity))
											.findAny()
											.isPresent();
	}


	public String getCacheKey(Object object) {
		String key = null;
		if (Map.class.isInstance(object)) {
			//no cache
		} else {
			Class entityClass = ReflectUtils.getObjectClass(LangUtils.getFirst(object));
			key = entityClass.getName()+"#"+entityClass.hashCode();
		}
		return key;
	}

	public void setMappedEntryBuilder(List managers) {
		this.mappedEntryBuilders = managers;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy