All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
gu.sql2java.BaseFieldSearcher Maven / Gradle / Ivy
package gu.sql2java;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Preconditions.checkArgument;
import static gu.sql2java.Managers.baseManagerOf;
import static gu.sql2java.Managers.getBaseTableManager;
import static com.google.common.base.MoreObjects.firstNonNull;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.MapBuilder;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import gu.sql2java.IFuzzyMatchFilter.MatchErrorHandler;
import gu.sql2java.TableManager.Action;
import gu.sql2java.exception.RuntimeDaoException;
/**
* 对表字段实现模糊搜索的基类
* @author guyadong
*
* @param 数据库表记录类型
* @param 搜索键类型
*/
public abstract class BaseFieldSearcher {
protected final RowMetaData metaData;
protected final BaseTableManager manager;
private final int[] keyIds;
private final int[] effectColumnIds;
/**
* 主键--搜索键映射
*/
protected final ConcurrentMap pks;
protected final ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
private Collection effectedBeans;
private BaseRow beforeUpdatedBean;
private final Listener listener;
private IFuzzyMatchFilter defaultMatchFilter;
private MatchErrorHandler errorHandler;
public BaseFieldSearcher(RowMetaData metaData,int ...effectColumnIds) {
this.metaData = checkNotNull(metaData,"metaData is null");
this.manager = getBaseTableManager(metaData.tablename);
this.keyIds = metaData.primaryKeyIds;
this.effectColumnIds = checkEffectIds(effectColumnIds);
this.pks = MapBuilder.newConcurrentMap();
this.listener = new Listener();
this.defaultMatchFilter = new BaseFuzzyMatchFilter.DefaultFuzzyFilter<>();
}
public BaseFieldSearcher(RowMetaData metaData,String ...effectColumnNames) {
this(metaData, checkNotNull(metaData,"metaData is null").columnIDsOf(effectColumnNames));
}
public >BaseFieldSearcher(ClassinterfaceClass,int[] effectColumnId) {
this(baseManagerOf(interfaceClass).metaData, effectColumnId);
}
public >BaseFieldSearcher(ClassinterfaceClass,String ... effectColumnNames) {
this(baseManagerOf(interfaceClass).metaData, effectColumnNames);
}
public String getTablename(){
return metaData.tablename;
}
private int[] checkEffectIds(int[] effectColumnIds){
checkArgument(effectColumnIds != null && effectColumnIds.length > 0,"effectColumnIds is null or empty");
for(int columnId:checkNotNull(effectColumnIds,"effectColumnIds is null")){
checkArgument(columnId>=0 && columnId getDefaultMatchFilter(){
return defaultMatchFilter;
}
public BaseFieldSearcher setDefaultMatchFilter(IFuzzyMatchFilter defaultMatchFilter) {
if(defaultMatchFilter != null){
this.defaultMatchFilter = defaultMatchFilter;
}
return this;
}
public BaseFieldSearcher setErrorHandler(MatchErrorHandler errorHandler) {
this.errorHandler = errorHandler;
return this;
}
/**
* 返回当记录更新时受影响的其他记录,如果没有返回空集合,
* 子类可根据需要重写此方法
* @param beforeUpdateBean
* @return 受影响的记录集合
*/
protected Collection getEffectedBeansOnUpdate(B beforeUpdateBean){
return Collections.emptyList();
}
public BaseFieldSearcher init(){
WriteLock lock = rwlock.writeLock();
lock.lock();
try{
pks.clear();
manager.loadAll(new Action(){
@Override
public void call(B bean) {
add(bean);
}});
manager.registerListener(listener);
} finally {
lock.unlock();
}
return this;
}
public BaseFieldSearcher uninit(){
WriteLock lock = rwlock.writeLock();
lock.lock();
try{
pks.clear();
manager.unregisterListener(listener);
} finally {
lock.unlock();
}
return this;
}
protected void add(B bean) {
if(bean != null){
K key = keyOf(bean);
if(key != null){
Object[] pk = bean.primaryValues();
pks.put(pk,key);
}
}
}
protected void update(B bean) {
if(bean != null){
K newKey = keyOf(bean);
Object[] pk = bean.primaryValues();
if(newKey != null){
// 增加新的key
pks.put(pk, newKey);
}
}
}
/**
* @param key 请求匹配的key
* @param matchFlags 匹配标志
* @param matchFilter 模糊匹配过滤器
* @param pkFilter 主键过滤器,用于根据主键过滤表记录
* @return 返回匹配的记录
*/
public final Multimap searchPk(K key, int matchFlags,IFuzzyMatchFilter matchFilter, Predicate pkFilter){
SetMultimap mm = MultimapBuilder.hashKeys().hashSetValues().build();
if(key == null){
return mm;
}
ReadLock lock = rwlock.readLock();
lock.lock();
try {
Map matched = Maps.filterEntries(pks, new EntryMatchFilter(key,matchFlags,matchFilter, pkFilter));
for( Entry entry:matched.entrySet()){
mm.put(entry.getValue(), entry.getKey());
}
return mm;
} finally {
lock.unlock();
}
}
private static final Function onePk = new Function(){
@Override
public Object apply(Object[] input) {
return input[0];
}
};
/**
* 单主键模糊匹配
* @param key 请求匹配的key
* @param matchFlags 匹配标志
* @param matchFilter 模糊匹配过滤器
* @param pkFilter 主键过滤器,用于根据主键过滤表记录
* @return 返回匹配的记录
*/
@SuppressWarnings("unchecked")
public final Multimap search(K key, int matchFlags, IFuzzyMatchFilter matchFilter, Predicate pkFilter){
checkState(keyIds.length == 1,"Unsupported Operation caused by the primary count > 1");
Predicate objsPkFilters = null;
if(pkFilter != null){
objsPkFilters = Predicates.compose(pkFilter, (Function)onePk);
}
Multimap pk = searchPk(key, matchFlags, matchFilter, objsPkFilters);
return Multimaps.transformValues(pk, (Function)onePk);
}
public K getPk(Object[] pk){
if(pk == null){
return null;
}
ReadLock lock = rwlock.readLock();
lock.lock();
try {
return pks.get(pk);
} finally {
lock.unlock();
}
}
public int[] getEffectColumnIds() {
return effectColumnIds;
}
/**
* @return first column id of effectColumnIds
*/
public int getEffectColumnId() {
return effectColumnIds[0];
}
/**
* @return first column name of effectColumnIds
*/
public String getEffectColumnName() {
return metaData.columnNameOf(effectColumnIds[0]);
}
private class Listener extends TableListener.Adapter{
@Override
public void afterInsert(B bean) throws RuntimeDaoException {
WriteLock lock = rwlock.writeLock();
lock.lock();
try{
add(bean);
} finally {
lock.unlock();
}
}
private boolean isModified(B bean){
for(int columnId:effectColumnIds){
if(bean.isModified(columnId)){
return true;
}
}
return false;
}
@Override
public void beforeUpdate(B bean) throws RuntimeDaoException {
// 保留更新前的数据
beforeUpdatedBean = ((BaseRow)bean).clone();
if(isModified(bean)){
// 如果指定的字段被更新保留受影响的数据
effectedBeans = getEffectedBeansOnUpdate(bean);
}else{
effectedBeans = Collections.emptyList();
}
}
@Override
public void afterUpdate(B bean) throws RuntimeDaoException {
// effectedBeans 为 null,只可能因为侦听器是被异步调用的
checkState(beforeUpdatedBean != null,"beforeUpdatedBean must not be null");
WriteLock lock = rwlock.writeLock();
lock.lock();
try{
for(B effectedBean:effectedBeans){
update(effectedBean);
}
update(bean);
} finally {
lock.unlock();
beforeUpdatedBean = null;
}
}
@Override
public void afterDelete(B bean) throws RuntimeDaoException {
WriteLock lock = rwlock.writeLock();
lock.lock();
try {
Object[] pk = bean.primaryValues();
pks.remove(pk);
} finally {
lock.unlock();
}
}
}
class EntryMatchFilter implements Predicate>{
private final IFuzzyMatchFilter matchFilter;
private final Predicate pkFilter;
EntryMatchFilter(K key,int matchFlags,IFuzzyMatchFilter matchFilter, Predicate pkFilter) {
this.matchFilter = firstNonNull(matchFilter,getDefaultMatchFilter()).withErrorHandler(errorHandler)
.withPattern(key, matchFlags);
this.pkFilter = firstNonNull(pkFilter, Predicates.alwaysTrue());
}
@Override
public boolean apply(Entry input) {
return matchFilter.apply(input.getValue()) && pkFilter.apply(input.getKey());
}
}
}