From bf75aaad963ff58429d44c0f78717d50c8430c54 Mon Sep 17 00:00:00 2001 From: kamhung <22250530@qq.com> Date: Fri, 4 Dec 2015 18:49:54 +0800 Subject: [PATCH] --- .../redkale/service/DataSourceService.java | 60 +-- .../redkale/source/DataDefaultSource.java | 97 ++--- .../wentch/redkale/source/EntityCache.java | 47 +-- .../wentch/redkale/source/FilterBeanNode.java | 387 ------------------ .../wentch/redkale/source/FilterJoinNode.java | 28 +- src/com/wentch/redkale/source/FilterNode.java | 115 +++--- .../wentch/redkale/source/FilterNodeBean.java | 351 ++++++++++++++++ 7 files changed, 492 insertions(+), 593 deletions(-) delete mode 100644 src/com/wentch/redkale/source/FilterBeanNode.java create mode 100644 src/com/wentch/redkale/source/FilterNodeBean.java diff --git a/src/com/wentch/redkale/service/DataSourceService.java b/src/com/wentch/redkale/service/DataSourceService.java index 85928d033..08af5ea97 100644 --- a/src/com/wentch/redkale/service/DataSourceService.java +++ b/src/com/wentch/redkale/service/DataSourceService.java @@ -142,8 +142,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public Number getNumberResult(Class entityClass, Reckon reckon, String column, FilterBean bean) { - return source.getNumberResult(entityClass, reckon, column, bean); + public final Number getNumberResult(Class entityClass, Reckon reckon, String column, FilterBean bean) { + return getNumberResult(entityClass, reckon, column, FilterNodeBean.createFilterNode(bean)); } @Override @@ -157,8 +157,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public Map getMapResult(Class entityClass, String keyColumn, Reckon reckon, String reckonColumn, FilterBean bean) { - return source.getMapResult(entityClass, keyColumn, reckon, reckonColumn, bean); + public final Map getMapResult(Class entityClass, String keyColumn, Reckon reckon, String reckonColumn, FilterBean bean) { + return getMapResult(entityClass, keyColumn, reckon, reckonColumn, FilterNodeBean.createFilterNode(bean)); } @Override @@ -187,8 +187,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public T find(Class clazz, FilterBean bean) { - return source.find(clazz, bean); + public final T find(Class clazz, FilterBean bean) { + return find(clazz, FilterNodeBean.createFilterNode(bean)); } @Override @@ -202,8 +202,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public boolean exists(Class clazz, FilterBean bean) { - return source.exists(clazz, bean); + public final boolean exists(Class clazz, FilterBean bean) { + return exists(clazz, FilterNodeBean.createFilterNode(bean)); } @Override @@ -217,8 +217,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public HashSet queryColumnSet(String selectedColumn, Class clazz, FilterBean bean) { - return source.queryColumnSet(selectedColumn, clazz, bean); + public final HashSet queryColumnSet(String selectedColumn, Class clazz, FilterBean bean) { + return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); } @Override @@ -232,8 +232,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public List queryColumnList(String selectedColumn, Class clazz, FilterBean bean) { - return source.queryColumnList(selectedColumn, clazz, bean); + public final List queryColumnList(String selectedColumn, Class clazz, FilterBean bean) { + return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); } @Override @@ -242,8 +242,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public Map queryMap(Class clazz, FilterBean bean) { - return source.queryMap(clazz, bean); + public final Map queryMap(Class clazz, FilterBean bean) { + return queryMap(clazz, FilterNodeBean.createFilterNode(bean)); } @Override @@ -252,8 +252,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public Map queryMap(Class clazz, SelectColumn selects, FilterBean bean) { - return source.queryMap(clazz, selects, bean); + public final Map queryMap(Class clazz, SelectColumn selects, FilterBean bean) { + return queryMap(clazz, selects, FilterNodeBean.createFilterNode(bean)); } @Override @@ -267,8 +267,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public List queryList(Class clazz, FilterBean bean) { - return source.queryList(clazz, bean); + public final List queryList(Class clazz, FilterBean bean) { + return queryList(clazz, FilterNodeBean.createFilterNode(bean)); } @Override @@ -277,8 +277,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public List queryList(Class clazz, SelectColumn selects, FilterBean bean) { - return source.queryList(clazz, bean); + public final List queryList(Class clazz, SelectColumn selects, FilterBean bean) { + return queryList(clazz, FilterNodeBean.createFilterNode(bean)); } @Override @@ -292,8 +292,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public List queryList(Class clazz, Flipper flipper, FilterBean bean) { - return source.queryList(clazz, flipper, bean); + public final List queryList(Class clazz, Flipper flipper, FilterBean bean) { + return queryList(clazz, flipper, FilterNodeBean.createFilterNode(bean)); } @Override @@ -302,13 +302,13 @@ public class DataSourceService implements DataSource, Service { } @Override - public List queryList(Class clazz, SelectColumn selects, Flipper flipper, FilterBean bean) { - return source.queryList(clazz, selects, flipper, bean); + public final List queryList(Class clazz, SelectColumn selects, Flipper flipper, FilterBean bean) { + return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); } @Override - public Sheet queryColumnSheet(String selectedColumn, Class clazz, Flipper flipper, FilterBean bean) { - return source.queryColumnSheet(selectedColumn, clazz, flipper, bean); + public final Sheet queryColumnSheet(String selectedColumn, Class clazz, Flipper flipper, FilterBean bean) { + return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); } @Override @@ -317,8 +317,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public Sheet querySheet(Class clazz, Flipper flipper, FilterBean bean) { - return source.querySheet(clazz, flipper, bean); + public final Sheet querySheet(Class clazz, Flipper flipper, FilterBean bean) { + return querySheet(clazz, flipper, FilterNodeBean.createFilterNode(bean)); } @Override @@ -327,8 +327,8 @@ public class DataSourceService implements DataSource, Service { } @Override - public Sheet querySheet(Class clazz, SelectColumn selects, Flipper flipper, FilterBean bean) { - return source.querySheet(clazz, selects, flipper, bean); + public final Sheet querySheet(Class clazz, SelectColumn selects, Flipper flipper, FilterBean bean) { + return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); } @Override diff --git a/src/com/wentch/redkale/source/DataDefaultSource.java b/src/com/wentch/redkale/source/DataDefaultSource.java index a52720966..9a7b1b5a0 100644 --- a/src/com/wentch/redkale/source/DataDefaultSource.java +++ b/src/com/wentch/redkale/source/DataDefaultSource.java @@ -110,7 +110,7 @@ public final class DataDefaultSource implements DataSource, Nameable, Function fullloader = (t) -> querySheet(false, false, t, null, null, (FilterNode) null, null).list(true); + private final Function fullloader = (t) -> querySheet(false, false, t, null, null, (FilterNode) null).list(true); public DataDefaultSource() throws IOException { this(""); @@ -339,10 +339,6 @@ public final class DataDefaultSource implements DataSource, Nameable, Function FilterBeanNode loadFilterBeanNode(Class clazz) { - return FilterBeanNode.load(clazz, this.nodeid, this.cacheForbidden, fullloader); - } - /** * 将entity的对象全部加载到Cache中去,如果clazz没有被@javax.persistence.Cacheable注解则不做任何事 *

@@ -651,7 +647,7 @@ public final class DataDefaultSource implements DataSource, Nameable, Function joinTabalis = node.getJoinTabalis(); CharSequence join = node.createSQLJoin(this, joinTabalis, info); - CharSequence where = node.createSQLExpress(info, joinTabalis, null); + CharSequence where = node.createSQLExpress(info, joinTabalis); String sql = "DELETE " + (mysql ? "a" : "") + " FROM " + info.getTable() + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); if (debug.get()) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql); final Statement stmt = conn.createStatement(); @@ -1062,7 +1058,7 @@ public final class DataDefaultSource implements DataSource, Nameable, Function sheet = querySheet(false, true, clazz, null, FLIPPER_ONE, FilterNode.create(column, id), null); + Sheet sheet = querySheet(false, true, clazz, null, FLIPPER_ONE, FilterNode.create(column, id)); T value = sheet.isEmpty() ? null : sheet.list().get(0); if (value != null) cache.update(value); } @@ -1071,33 +1067,28 @@ public final class DataDefaultSource implements DataSource, Nameable, Function Number getNumberResult(final Class entityClass, final Reckon reckon, final String column, FilterNode node, FilterBean bean) { + public Number getNumberResult(final Class entityClass, final Reckon reckon, final String column, final FilterNode node) { final Connection conn = createReadSQLConnection(); try { - final EntityInfo info = loadEntityInfo(entityClass); - if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass()); - final EntityCache cache = info.getCache(); + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) { if (node == null || node.isCacheUseable(this)) { - return cache.getNumberResult(reckon, column, node, bean); + return cache.getNumberResult(reckon, column, node); } } final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info); - final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis, bean); + final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis); final String sql = "SELECT " + reckon.getColumn((column == null || column.isEmpty() ? "*" : ("a." + column))) + " FROM " + info.getTable() + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql); @@ -1120,34 +1111,29 @@ public final class DataDefaultSource implements DataSource, Nameable, Function Map getMapResult(Class entityClass, final String keyColumn, Reckon reckon, final String reckonColumn) { - return getMapResult(entityClass, keyColumn, reckon, reckonColumn, null, null); + return getMapResult(entityClass, keyColumn, reckon, reckonColumn, (FilterNode) null); } @Override public Map getMapResult(Class entityClass, final String keyColumn, Reckon reckon, final String reckonColumn, FilterBean bean) { - return getMapResult(entityClass, keyColumn, reckon, reckonColumn, null, bean); + return getMapResult(entityClass, keyColumn, reckon, reckonColumn, FilterNodeBean.createFilterNode(bean)); } @Override - public Map getMapResult(Class entityClass, final String keyColumn, Reckon reckon, final String reckonColumn, FilterNode node) { - return getMapResult(entityClass, keyColumn, reckon, reckonColumn, node, null); - } - - private Map getMapResult(final Class entityClass, final String keyColumn, final Reckon reckon, final String reckonColumn, FilterNode node, FilterBean bean) { + public Map getMapResult(final Class entityClass, final String keyColumn, final Reckon reckon, final String reckonColumn, FilterNode node) { final Connection conn = createReadSQLConnection(); try { final EntityInfo info = loadEntityInfo(entityClass); - if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass()); final EntityCache cache = info.getCache(); if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) { if (node == null || node.isCacheUseable(this)) { - return cache.getMapResult(keyColumn, reckon, reckonColumn, node, bean); + return cache.getMapResult(keyColumn, reckon, reckonColumn, node); } } final String sqlkey = info.getSQLColumn(null, keyColumn); final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info); - final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis, bean); + final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis); final String sql = "SELECT a." + sqlkey + ", " + reckon.getColumn((reckonColumn == null || reckonColumn.isEmpty() ? "*" : ("a." + reckonColumn))) + " FROM " + info.getTable() + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + sqlkey; if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql); @@ -1209,31 +1195,30 @@ public final class DataDefaultSource implements DataSource, Nameable, Function T findByColumn(final Class clazz, final String column, final Serializable key) { - return find(clazz, null, FilterNode.create(column, key), null); + return find(clazz, null, FilterNode.create(column, key)); } @Override public T find(final Class clazz, final FilterBean bean) { - return find(clazz, null, null, bean); + return find(clazz, null, FilterNodeBean.createFilterNode(bean)); } @Override public T find(final Class clazz, final FilterNode node) { - return find(clazz, null, node, null); + return find(clazz, null, node); } - private T find(final Class clazz, final SelectColumn selects, FilterNode node, final FilterBean bean) { + public T find(final Class clazz, final SelectColumn selects, final FilterNode node) { final EntityInfo info = loadEntityInfo(clazz); final EntityCache cache = info.getCache(); - if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass()); - if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.find(selects, node, bean); + if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.find(selects, node); final Connection conn = createReadSQLConnection(); try { final SelectColumn sels = selects; final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info); - final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis, bean); + final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis); final String sql = "SELECT a.* FROM " + info.getTable() + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); @@ -1273,26 +1258,21 @@ public final class DataDefaultSource implements DataSource, Nameable, Function boolean exists(final Class clazz, final FilterNode node) { - return exists(clazz, node, null); + public boolean exists(final Class clazz, final FilterBean bean) { + return exists(clazz, FilterNodeBean.createFilterNode(bean)); } @Override - public boolean exists(final Class clazz, final FilterBean bean) { - return exists(clazz, null, bean); - } - - private boolean exists(final Class clazz, FilterNode node, final FilterBean bean) { + public boolean exists(final Class clazz, final FilterNode node) { final EntityInfo info = loadEntityInfo(clazz); final EntityCache cache = info.getCache(); - if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass()); - if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.exists(node, bean); + if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.exists(node); final Connection conn = createReadSQLConnection(); try { final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info); - final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis, bean); + final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis); final String sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + info.getTable() + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " exists sql=" + sql); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); @@ -1446,12 +1426,12 @@ public final class DataDefaultSource implements DataSource, Nameable, Function List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheet(true, false, clazz, selects, flipper, node, null).list(true); + return querySheet(true, false, clazz, selects, flipper, node).list(true); } @Override public List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySheet(true, false, clazz, selects, flipper, null, bean).list(true); + return querySheet(true, false, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)).list(true); } //-----------------------sheet---------------------------- @@ -1468,16 +1448,12 @@ public final class DataDefaultSource implements DataSource, Nameable, Function Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSheet(selectedColumn, clazz, flipper, null, bean); + return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); } @Override public Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterNode node) { - return queryColumnSheet(selectedColumn, clazz, flipper, node, null); - } - - private Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterNode node, final FilterBean bean) { - Sheet sheet = querySheet(true, true, clazz, SelectColumn.createIncludes(selectedColumn), flipper, node, bean); + Sheet sheet = querySheet(true, true, clazz, SelectColumn.createIncludes(selectedColumn), flipper, node); final Sheet rs = new Sheet<>(); if (sheet.isEmpty()) return rs; rs.setTotal(sheet.getTotal()); @@ -1522,22 +1498,21 @@ public final class DataDefaultSource implements DataSource, Nameable, Function Sheet querySheet(Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySheet(true, true, clazz, selects, flipper, null, bean); + return querySheet(true, true, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); } @Override public Sheet querySheet(Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheet(true, true, clazz, selects, flipper, node, null); + return querySheet(true, true, clazz, selects, flipper, node); } - private Sheet querySheet(boolean readcache, boolean needtotal, Class clazz, final SelectColumn selects, final Flipper flipper, FilterNode node, final FilterBean bean) { + private Sheet querySheet(boolean readcache, boolean needtotal, Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { final EntityInfo info = loadEntityInfo(clazz); final EntityCache cache = info.getCache(); - if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass()); if (readcache && cache != null) { if (node == null || node.isCacheUseable(this)) { - if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createPredicate(cache, bean))); - Sheet sheet = cache.querySheet(needtotal, selects, flipper, node, bean); + if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createPredicate(cache))); + Sheet sheet = cache.querySheet(needtotal, selects, flipper, node); if (!sheet.isEmpty() || info.isVirtualEntity() || cache.isFullLoaded()) return sheet; } } @@ -1547,7 +1522,7 @@ public final class DataDefaultSource implements DataSource, Nameable, Function list = new ArrayList(); final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info); - final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis, bean); + final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis); final String sql = "SELECT a.* FROM " + info.getTable() + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper); if (debug.get() && info.isLoggable(Level.FINEST)) diff --git a/src/com/wentch/redkale/source/EntityCache.java b/src/com/wentch/redkale/source/EntityCache.java index 8abcd6cea..9c17e45b5 100644 --- a/src/com/wentch/redkale/source/EntityCache.java +++ b/src/com/wentch/redkale/source/EntityCache.java @@ -104,12 +104,7 @@ public final class EntityCache { } public T find(final SelectColumn selects, FilterNode node) { - return find(selects, node, null); - } - - public T find(final SelectColumn selects, FilterNode node, final FilterBean bean) { - if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass()); - final Predicate filter = node == null ? null : node.createPredicate(this, bean); + final Predicate filter = node == null ? null : node.createPredicate(this); Stream stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); Optional opt = stream.findFirst(); @@ -144,9 +139,8 @@ public final class EntityCache { return this.map.containsKey(id); } - public boolean exists(FilterNode node, final FilterBean bean) { - if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass()); - final Predicate filter = node == null ? null : node.createPredicate(this, bean); + public boolean exists(FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); Stream stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); return stream.findFirst().isPresent(); @@ -156,14 +150,9 @@ public final class EntityCache { return (filter != null) && this.list.stream().filter(filter).findFirst().isPresent(); } - public Map getMapResult(final String keyColumn, final Reckon reckon, final String reckonColumn, final FilterNode node) { - return getMapResult(keyColumn, reckon, reckonColumn, node, null); - } - - public Map getMapResult(final String keyColumn, final Reckon reckon, final String reckonColumn, FilterNode node, final FilterBean bean) { - if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass()); + public Map getMapResult(final String keyColumn, final Reckon reckon, final String reckonColumn, FilterNode node) { final Attribute keyAttr = info.getAttribute(keyColumn); - final Predicate filter = node == null ? null : node.createPredicate(this, bean); + final Predicate filter = node == null ? null : node.createPredicate(this); final Attribute reckonAttr = reckonColumn == null ? null : info.getAttribute(reckonColumn); Stream stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); @@ -210,14 +199,9 @@ public final class EntityCache { return rs; } - public Number getNumberResult(final Reckon reckon, final String column, final FilterNode node) { - return getNumberResult(reckon, column, node, null); - } - - public Number getNumberResult(final Reckon reckon, final String column, FilterNode node, final FilterBean bean) { - if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass()); + public Number getNumberResult(final Reckon reckon, final String column, FilterNode node) { final Attribute attr = column == null ? null : info.getAttribute(column); - final Predicate filter = node == null ? null : node.createPredicate(this, bean); + final Predicate filter = node == null ? null : node.createPredicate(this); Stream stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); switch (reckon) { @@ -283,20 +267,11 @@ public final class EntityCache { } public Sheet querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheet(selects, flipper, node, null); + return querySheet(true, selects, flipper, node); } - public Sheet querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node, final FilterBean bean) { - return querySheet(true, selects, flipper, node, bean); - } - - public Sheet querySheet(final boolean needtotal, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheet(needtotal, selects, flipper, node, null); - } - - public Sheet querySheet(final boolean needtotal, final SelectColumn selects, final Flipper flipper, FilterNode node, final FilterBean bean) { - if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass()); - final Predicate filter = node == null ? null : node.createPredicate(this, bean); + public Sheet querySheet(final boolean needtotal, final SelectColumn selects, final Flipper flipper, FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); final Comparator comparator = createComparator(flipper); long total = 0; if (needtotal) { @@ -358,7 +333,7 @@ public final class EntityCache { public Serializable[] delete(final FilterNode node) { if (node == null || this.list.isEmpty()) return new Serializable[0]; - Object[] rms = this.list.stream().filter(node.createPredicate(this, null)).toArray(); + Object[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(); Serializable[] ids = new Serializable[rms.length]; int i = -1; for (Object o : rms) { diff --git a/src/com/wentch/redkale/source/FilterBeanNode.java b/src/com/wentch/redkale/source/FilterBeanNode.java deleted file mode 100644 index c6cf35db2..000000000 --- a/src/com/wentch/redkale/source/FilterBeanNode.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.wentch.redkale.source; - -import static com.wentch.redkale.source.FilterExpress.*; -import com.wentch.redkale.util.*; -import java.io.Serializable; -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.*; -import java.util.logging.Logger; -import javax.persistence.Transient; - -/** - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -final class FilterBeanNode extends FilterNode { - - private static final Logger logger = Logger.getLogger(FilterBeanNode.class.getSimpleName()); - - private static final ConcurrentHashMap beanodes = new ConcurrentHashMap<>(); - - public static FilterBeanNode load(Class clazz) { - return load(clazz, -1, true, null); - } - - public static FilterBeanNode load(Class clazz, final int nodeid, final boolean cacheForbidden, - Function fullloader) { - FilterBeanNode rs = beanodes.get(clazz); - if (rs != null) return rs; - synchronized (beanodes) { - rs = beanodes.get(clazz); - if (rs == null) { - rs = createNode(clazz, nodeid, cacheForbidden, fullloader); - beanodes.put(clazz, rs); - } - return rs; - } - } - - private static FilterBeanNode createNode(Class clazz, final int nodeid, final boolean cacheForbidden, - Function fullloader) { - Class cltmp = clazz; - Set fields = new HashSet<>(); - final Map joinTables = new HashMap<>(); - Map nodemap = new HashMap<>(); - boolean joinallcached = true; - final StringBuilder joinsb = new StringBuilder(); - do { - for (Field field : cltmp.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (fields.contains(field.getName())) continue; - if (field.getAnnotation(Ignore.class) != null) continue; - if (field.getAnnotation(Transient.class) != null) continue; - - final boolean pubmod = Modifier.isPublic(field.getModifiers()); - - char[] chars = field.getName().toCharArray(); - chars[0] = Character.toUpperCase(chars[0]); - final Class t = field.getType(); - Method getter = null; - try { - getter = cltmp.getMethod(((t == boolean.class || t == Boolean.class) ? "is" : "get") + new String(chars)); - } catch (Exception ex) { - if (!pubmod) continue; - } - fields.add(field.getName()); - FilterBeanNode newnode = new FilterBeanNode(field.getName(), true, pubmod ? Attribute.create(field) : Attribute.create(getter, null)); - newnode.setField(field); - //------------------------------------ - { - FilterJoinColumn joinCol = field.getAnnotation(FilterJoinColumn.class); - if (joinCol != null) { - boolean first = false; - final Class joinClass = joinCol.table(); - if (!joinTables.containsKey(joinClass)) { - first = true; - joinTables.put(joinClass, String.valueOf((char) ('b' + joinTables.size()))); - } - final String alias = joinTables.get(joinClass); - final EntityInfo secinfo = EntityInfo.load(joinClass, nodeid, cacheForbidden, fullloader); - if (secinfo.getCache() == null || !secinfo.getCache().isFullLoaded()) { - joinallcached = false; - } - final String jc = joinCol.column().isEmpty() ? secinfo.getPrimary().field() : joinCol.column(); - if (first) { - joinsb.append(" INNER JOIN ").append(secinfo.getTable()) - .append(" ").append(alias).append(" ON ").append(secinfo.getSQLColumn("a", jc)).append(" = ").append(secinfo.getSQLColumn(alias, jc)); - } - newnode.foreignCache = secinfo.getCache(); - newnode.tabalis = alias; - newnode.columnAttribute = secinfo.getAttribute(newnode.column); - newnode.byjoinColumn = jc; - newnode.foreignAttribute = secinfo.getAttribute(jc); - if (newnode.foreignCache != null && newnode.foreignAttribute == null) throw new RuntimeException(clazz.getName() + "." + field.getName() + " have illegal FilterJoinColumn " + joinCol); - } - } - //------------------------------------ - { - FilterGroup[] refs = field.getAnnotationsByType(FilterGroup.class); - String[] groups = new String[refs.length]; - for (int i = 0; i < refs.length; i++) { - groups[i] = refs[i].value(); - } - if (groups.length == 0) groups = new String[]{"[AND]"}; - for (String key : groups) { - if (!key.startsWith("[AND]") && !key.startsWith("[OR]")) { - throw new RuntimeException(field + "'s FilterGroup.value(" + key + ") illegal, must be [AND] or [OR] startsWith"); - } - FilterBeanNode node = nodemap.get(key); - if (node == null) { - nodemap.put(key, newnode); - } else { - node.any(newnode, key.contains("[OR]")); - } - } - } - } - } while ((cltmp = cltmp.getSuperclass()) != Object.class); - FilterBeanNode rs = null; - for (FilterBeanNode f : nodemap.values()) { - if (rs == null) { - rs = f; - } else { - rs.and(f); - } - } - if (rs != null) { - rs.joinallcached = joinallcached; - if (joinsb.length() > 0) rs.joinSQL = joinsb.toString(); - } - return rs; - } - - //--------------------------- only header ----------------------------------------------------- - private boolean joinallcached = true; - - private String joinSQL; - - //--------------------------------------------------------------------------------------------- - private Attribute beanAttribute; - - private EntityCache foreignCache; // join 表 - - private String byjoinColumn; //被join表的join字段 - - private Attribute foreignAttribute; //join表的join字段 - - private Attribute columnAttribute; - - private String tabalis; - - private long least; - - private boolean string; - - private boolean number; - - protected FilterBeanNode(String col, boolean sign, Attribute beanAttr) { - this.column = col; - this.or = sign; - this.beanAttribute = beanAttr; - } - - private void setField(Field field) { - final FilterColumn fc = field.getAnnotation(FilterColumn.class); - if (fc != null && !fc.name().isEmpty()) this.column = fc.name(); - final Class type = field.getType(); - this.least = fc == null ? 1L : fc.least(); - this.number = (type.isPrimitive() && type != boolean.class) || Number.class.isAssignableFrom(type); - this.string = CharSequence.class.isAssignableFrom(type); - - FilterExpress exp = fc == null ? null : fc.express(); - if (type.isArray() || Collection.class.isAssignableFrom(type)) { - if (Range.class.isAssignableFrom(type.getComponentType())) { - if (AND != exp) exp = OR; - } else if (NOTIN != exp) exp = IN; - } else if (Range.class.isAssignableFrom(type)) { - if (NOTBETWEEN != exp) exp = BETWEEN; - } - if (exp == null) exp = EQUAL; - this.express = exp; - this.tabalis = "a"; - } - - protected String getTabalis() { - return tabalis; - } - - @Override - protected void append(FilterNode node, boolean sign) { - FilterBeanNode newnode = new FilterBeanNode(this.column, this.or, this.beanAttribute); - newnode.express = this.express; - newnode.nodes = this.nodes; - newnode.foreignCache = this.foreignCache; - newnode.byjoinColumn = this.byjoinColumn; - newnode.foreignAttribute = this.foreignAttribute; - newnode.columnAttribute = this.columnAttribute; - newnode.least = this.least; - newnode.number = this.number; - newnode.string = this.string; - this.nodes = new FilterNode[]{newnode}; - this.column = node.column; - this.express = node.express; - this.or = sign; - this.setValue(node.getValue()); - if (node instanceof FilterBeanNode) { - FilterBeanNode beanNode = ((FilterBeanNode) node); - this.beanAttribute = beanNode.beanAttribute; - this.foreignCache = beanNode.foreignCache; - this.byjoinColumn = beanNode.byjoinColumn; - this.foreignAttribute = beanNode.foreignAttribute; - this.columnAttribute = beanNode.columnAttribute; - this.least = beanNode.least; - this.number = beanNode.number; - this.string = beanNode.string; - } - } - - @Override - protected CharSequence createSQLJoin(final Function func, final Map joinTabalis, final EntityInfo info) { - if (joinSQL == null) return null; - return joinSQL; - } - - @Override - protected Predicate createPredicate(final EntityCache cache, FilterBean bean) { - if (this.foreignCache == null) return super.createPredicate(cache, bean); - final Map foreign = new HashMap<>(); - Predicate result = null; - putForeignPredicate(cache, foreign, bean); - if (this.nodes != null) { - for (FilterNode n : this.nodes) { - FilterBeanNode node = (FilterBeanNode) n; - if (node.foreignCache == null) { - Predicate f = node.createPredicate(cache, bean); - if (f == null) continue; - final Predicate one = result; - final Predicate two = f; - result = (result == null) ? f : (or ? new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }); - } else { - putForeignPredicate(cache, foreign, bean); - } - } - } - if (foreign.isEmpty()) return result; - final String byjoinCol = this.byjoinColumn; - final Attribute foreignAttr = this.foreignAttribute; - for (final Map.Entry en : foreign.entrySet()) { - Attribute byjoinAttr = cache.getAttribute(byjoinCol); - final Predicate p = en.getValue(); - final EntityCache joinCache = en.getKey(); - Predicate f = new Predicate() { - - @Override - public boolean test(T t) { - Serializable key = byjoinAttr.get(t); - Predicate k = (e) -> key.equals(foreignAttr.get(e)); - return joinCache.exists(k.and(p)); - } - - @Override - public String toString() { - return "(" + byjoinAttr.field() + " = " + en.getKey().getType().getSimpleName() + "." + foreignAttr.field() + " AND " + p + ")"; - } - }; - final Predicate one = result; - final Predicate two = f; - result = (result == null) ? f : (or ? new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }); - } - return result; - } - - private void putForeignPredicate(final EntityCache cache, final Map foreign, FilterBean bean) { - if (this.foreignCache == null) return; - final Serializable val = getElementValue(bean); - Predicate filter = (val == null && express != ISNULL && express != ISNOTNULL) ? new Predicate() { - - @Override - public boolean test(T t) { - return or; - } - - @Override - public String toString() { - return "" + or; - } - } : super.createElementPredicate(cache, false, this.columnAttribute, bean); - if (filter == null) return; - Predicate p = foreign.get(this.foreignCache); - if (p == null) { - foreign.put(foreignCache, filter); - } else { - final Predicate one = p; - final Predicate two = filter; - p = or ? new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }; - foreign.put(foreignCache, p); - } - } - - @Override - protected boolean isCacheUseable(final Function entityApplyer) { - return joinallcached; - } - - @Override - protected Serializable getElementValue(FilterBean bean) { - if (bean == null || beanAttribute == null) return null; - Serializable rs = (Serializable) beanAttribute.get(bean); - if (rs == null) return null; - if (string && ((CharSequence) rs).length() == 0) return null; - if (number && ((Number) rs).longValue() < this.least) return null; - return rs; - } -} diff --git a/src/com/wentch/redkale/source/FilterJoinNode.java b/src/com/wentch/redkale/source/FilterJoinNode.java index cc1f2f776..4dc4fad23 100644 --- a/src/com/wentch/redkale/source/FilterJoinNode.java +++ b/src/com/wentch/redkale/source/FilterJoinNode.java @@ -56,15 +56,21 @@ public class FilterJoinNode extends FilterNode { } @Override - protected CharSequence createSQLExpress(final EntityInfo info, final Map joinTabalis, final FilterBean bean) { - return super.createSQLExpress(this.joinEntity, joinTabalis, bean); + protected void check(FilterNode node) { + Objects.requireNonNull(node); + if (!(node instanceof FilterJoinNode)) throw new IllegalArgumentException(this + " check " + String.valueOf(node) + "is not a " + FilterJoinNode.class.getSimpleName()); } @Override - protected Predicate createPredicate(final EntityCache cache, final FilterBean bean) { + protected CharSequence createSQLExpress(final EntityInfo info, final Map joinTabalis) { + return super.createSQLExpress(this.joinEntity, joinTabalis); + } + + @Override + protected Predicate createPredicate(final EntityCache cache) { if (column == null && this.nodes == null) return null; final EntityCache joinCache = this.joinEntity.getCache(); - Predicate filter = createChildPredicate(bean); + Predicate filter = createChildPredicate(); if (filter == null) return null; final Predicate inner = filter; @@ -95,13 +101,13 @@ public class FilterJoinNode extends FilterNode { }; } - private Predicate createChildPredicate(final FilterBean bean) { + private Predicate createChildPredicate() { if (column == null && this.nodes == null) return null; final EntityCache joinCache = this.joinEntity.getCache(); - Predicate filter = createElementPredicate(joinCache, true, bean); + Predicate filter = createElementPredicate(joinCache, true); if (this.nodes != null) { for (FilterNode node : this.nodes) { - Predicate f = ((FilterJoinNode) node).createChildPredicate(bean); + Predicate f = ((FilterJoinNode) node).createChildPredicate(); if (f == null) continue; final Predicate one = filter; final Predicate two = f; @@ -181,13 +187,7 @@ public class FilterJoinNode extends FilterNode { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("#-- ON ").append(joinColumns[0]).append(" = ").append(joinClass == null ? "null" : joinClass.getSimpleName()).append('.').append(joinColumns[0]); - for (int i = 1; i < joinColumns.length; i++) { - sb.append(" AND ").append(joinColumns[i]).append(" = ").append(joinClass == null ? "null" : joinClass.getSimpleName()).append('.').append(joinColumns[i]); - } - sb.append(" --# ").append(toString(joinClass == null ? null : joinClass.getSimpleName(), null)); - return sb.toString(); + return toString(joinClass == null ? null : joinClass.getSimpleName()).toString(); } public Class getJoinClass() { diff --git a/src/com/wentch/redkale/source/FilterNode.java b/src/com/wentch/redkale/source/FilterNode.java index 29e70e99a..171be0476 100644 --- a/src/com/wentch/redkale/source/FilterNode.java +++ b/src/com/wentch/redkale/source/FilterNode.java @@ -77,7 +77,7 @@ public class FilterNode { return or(new FilterNode(column, express, value)); } - protected final FilterNode any(FilterNode node, boolean sign) { + protected final FilterNode any(FilterNode node, boolean signor) { Objects.requireNonNull(node); if (this.column == null) { this.column = node.column; @@ -87,17 +87,24 @@ public class FilterNode { } if (this.nodes == null) { this.nodes = new FilterNode[]{node}; - this.or = sign; + this.or = signor; return this; } - if (or == sign) { + if (or == signor) { FilterNode[] newsiblings = new FilterNode[nodes.length + 1]; System.arraycopy(nodes, 0, newsiblings, 0, nodes.length); newsiblings[nodes.length] = node; this.nodes = newsiblings; return this; } - this.append(node, sign); + FilterNode newnode = new FilterNode(this.column, this.express, this.value); + newnode.or = this.or; + newnode.nodes = this.nodes; + this.nodes = new FilterNode[]{newnode, node}; + this.column = null; + this.express = null; + this.or = signor; + this.value = null; return this; } @@ -105,27 +112,9 @@ public class FilterNode { * 该方法需要重载 * * @param node - * @param sign */ - protected void append(FilterNode node, boolean sign) { - FilterNode newnode = new FilterNode(this.column, this.express, this.value); - newnode.or = this.or; - newnode.nodes = this.nodes; - this.nodes = new FilterNode[]{newnode, node}; - this.column = null; - this.express = null; - this.or = sign; - this.value = null; - } - - /** - * 该方法需要重载 - * - * @param bean - * @return - */ - protected Serializable getElementValue(final FilterBean bean) { - return value; + protected void check(FilterNode node) { + Objects.requireNonNull(node); } /** @@ -199,8 +188,8 @@ public class FilterNode { * @param bean * @return */ - protected CharSequence createSQLExpress(final EntityInfo info, final Map joinTabalis, final FilterBean bean) { - CharSequence sb0 = createElementSQLExpress(info, joinTabalis == null ? null : joinTabalis.get(info.getType()), bean); + protected CharSequence createSQLExpress(final EntityInfo info, final Map joinTabalis) { + CharSequence sb0 = createElementSQLExpress(info, joinTabalis == null ? null : joinTabalis.get(info.getType())); if (this.nodes == null) return sb0; final StringBuilder rs = new StringBuilder(); rs.append('('); @@ -210,7 +199,7 @@ public class FilterNode { rs.append(sb0); } for (FilterNode node : this.nodes) { - CharSequence f = node.createSQLExpress(info, joinTabalis, bean); + CharSequence f = node.createSQLExpress(info, joinTabalis); if (f == null || f.length() < 3) continue; if (more) rs.append(or ? " OR " : " AND "); rs.append(f); @@ -229,13 +218,13 @@ public class FilterNode { return new FilterNode(column, express, value); } - protected final CharSequence createElementSQLExpress(final EntityInfo info, String talis, final FilterBean bean) { + protected final CharSequence createElementSQLExpress(final EntityInfo info, String talis) { if (column == null) return null; if (talis == null) talis = "a"; if (express == ISNULL || express == ISNOTNULL) { return new StringBuilder().append(info.getSQLColumn(talis, column)).append(' ').append(express.value()); } - final CharSequence val = formatToString(express, getElementValue(bean)); + final CharSequence val = formatToString(express, getValue()); if (val == null) return null; StringBuilder sb = new StringBuilder(32); if (express == IGNORECASELIKE || express == IGNORECASENOTLIKE) { @@ -259,12 +248,12 @@ public class FilterNode { return sb; } - protected Predicate createPredicate(final EntityCache cache, final FilterBean bean) { + protected Predicate createPredicate(final EntityCache cache) { if (cache == null || (column == null && this.nodes == null)) return null; - Predicate filter = createElementPredicate(cache, false, bean); + Predicate filter = createElementPredicate(cache, false); if (this.nodes == null) return filter; for (FilterNode node : this.nodes) { - Predicate f = node.createPredicate(cache, bean); + Predicate f = node.createPredicate(cache); if (f == null) continue; final Predicate one = filter; final Predicate two = f; @@ -295,12 +284,12 @@ public class FilterNode { return filter; } - protected final Predicate createElementPredicate(final EntityCache cache, final boolean join, final FilterBean bean) { + protected final Predicate createElementPredicate(final EntityCache cache, final boolean join) { if (column == null) return null; - return createElementPredicate(cache, join, cache.getAttribute(column), bean); + return createElementPredicate(cache, join, cache.getAttribute(column)); } - protected final Predicate createElementPredicate(final EntityCache cache, final boolean join, final Attribute attr, final FilterBean bean) { + protected final Predicate createElementPredicate(final EntityCache cache, final boolean join, final Attribute attr) { if (attr == null) return null; final String field = join ? (cache.getType().getSimpleName() + "." + attr.field()) : attr.field(); if (express == ISNULL) return new Predicate() { @@ -328,7 +317,7 @@ public class FilterNode { } }; if (attr == null) return null; - Serializable val0 = getElementValue(bean); + Serializable val0 = getValue(); if (val0 == null) return null; final Class atype = attr.type(); @@ -833,43 +822,39 @@ public class FilterNode { @Override public String toString() { - return toString(null, null); + return toString(null).toString(); } - protected String toString(final String prefix, final FilterBean bean) { + protected StringBuilder toString(final String prefix) { StringBuilder sb = new StringBuilder(); - if (nodes == null) { - if (column != null) { - String col = prefix == null ? column : (prefix + "." + column); - Serializable ev = getElementValue(bean); - if (express == ISNULL || express == ISNOTNULL) { - sb.append(col).append(' ').append(express.value()); - } else if (ev != null) { - sb.append((express == IGNORECASELIKE || express == IGNORECASENOTLIKE) ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(' ').append(formatToString(express, ev)); - } - } - } else { - boolean more = false; - if (column != null) { - String col = prefix == null ? column : (prefix + "." + column); - Serializable ev = getElementValue(bean); - if (express == ISNULL || express == ISNOTNULL) { - sb.append('(').append(col).append(' ').append(express.value()); - more = true; - } else if (ev != null) { - sb.append('(').append((express == IGNORECASELIKE || express == IGNORECASENOTLIKE) ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(' ').append(formatToString(express, ev)); - more = true; - } - } + StringBuilder element = toElementString(prefix); + boolean more = element.length() > 0 && this.nodes != null; + if (more) sb.append('('); + sb.append(element); + if (this.nodes != null) { for (FilterNode node : this.nodes) { String s = node.toString(); - if (s.isEmpty()) continue; - if (sb.length() > 0) sb.append(or ? " OR " : " AND "); + if (s.length() < 1) continue; + if (sb.length() > 1) sb.append(or ? " OR " : " AND "); sb.append(s); } - if (more) sb.append(')'); } - return sb.toString(); + if (more) sb.append(')'); + return sb; + } + + protected final StringBuilder toElementString(final String prefix) { + StringBuilder sb = new StringBuilder(); + if (column != null) { + String col = prefix == null ? column : (prefix + "." + column); + Serializable ev = getValue(); + if (express == ISNULL || express == ISNOTNULL) { + sb.append(col).append(' ').append(express.value()); + } else if (ev != null) { + sb.append((express == IGNORECASELIKE || express == IGNORECASENOTLIKE) ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(' ').append(formatToString(express, ev)); + } + } + return sb; } protected static CharSequence formatToString(Object value) { diff --git a/src/com/wentch/redkale/source/FilterNodeBean.java b/src/com/wentch/redkale/source/FilterNodeBean.java new file mode 100644 index 000000000..9a2f466e1 --- /dev/null +++ b/src/com/wentch/redkale/source/FilterNodeBean.java @@ -0,0 +1,351 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.wentch.redkale.source; + +import static com.wentch.redkale.source.FilterExpress.*; +import com.wentch.redkale.util.*; +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; +import javax.persistence.*; + +/** + * + * @author zhangjx + */ +public final class FilterNodeBean implements Comparable> { + + private static final ConcurrentHashMap beanodes = new ConcurrentHashMap<>(); + + private Attribute beanAttr; + + private String column; + + private FilterExpress express; + + private boolean or; + + private FilterNodeBean[] nodeBeans; + + //-----------------join table-------------------------- + private Class joinClass; + + private String[] joinColumns; + + //---------------------------------------------------- + private long least; + + private boolean string; + + private boolean number; + + public FilterNodeBean(FilterNodeBean bean) { + this.beanAttr = bean.beanAttr; + this.column = bean.column; + this.express = bean.express; + this.joinClass = bean.joinClass; + this.joinColumns = bean.joinColumns; + this.least = bean.least; + this.string = bean.string; + this.number = bean.number; + this.or = bean.or; + this.nodeBeans = bean.nodeBeans; + } + + private FilterNodeBean(final FilterJoinColumn joinCol, final FilterColumn filterCol, final Attribute attr) { + this.beanAttr = attr; + this.joinClass = joinCol == null ? null : joinCol.table(); + this.joinColumns = joinCol == null ? null : (joinCol.columns().length == 0 ? new String[]{joinCol.column()} : joinCol.columns()); + + final Class type = attr.type(); + this.column = (filterCol != null && !filterCol.name().isEmpty()) ? filterCol.name() : attr.field(); + + FilterExpress exp = filterCol == null ? null : filterCol.express(); + if (type.isArray() || Collection.class.isAssignableFrom(type)) { + if (Range.class.isAssignableFrom(type.getComponentType())) { + if (AND != exp) exp = OR; + } else if (NOTIN != exp) exp = IN; + } else if (Range.class.isAssignableFrom(type)) { + if (NOTBETWEEN != exp) exp = BETWEEN; + } + if (exp == null) exp = EQUAL; + this.express = exp; + + this.least = filterCol == null ? 1 : filterCol.least(); + this.number = (type.isPrimitive() && type != boolean.class) || Number.class.isAssignableFrom(type); + this.string = CharSequence.class.isAssignableFrom(type); + } + + private FilterNodeBean or(FilterNodeBean node) { + return any(node, true); + } + + private FilterNodeBean and(FilterNodeBean node) { + return any(node, false); + } + + private FilterNodeBean any(FilterNodeBean node, boolean signor) { + Objects.requireNonNull(node); + if (this.column == null) { + this.beanAttr = node.beanAttr; + this.column = node.column; + this.express = node.express; + this.joinClass = node.joinClass; + this.joinColumns = node.joinColumns; + this.least = node.least; + this.string = node.string; + this.number = node.number; + return this; + } + if (this.nodeBeans == null) { + this.nodeBeans = new FilterNodeBean[]{node}; + this.or = signor; + return this; + } + if (or == signor) { + FilterNodeBean[] newsiblings = new FilterNodeBean[nodeBeans.length + 1]; + System.arraycopy(nodeBeans, 0, newsiblings, 0, nodeBeans.length); + newsiblings[nodeBeans.length] = node; + this.nodeBeans = newsiblings; + return this; + } + this.nodeBeans = new FilterNodeBean[]{new FilterNodeBean(this), node}; + this.column = null; + this.or = signor; + return this; + } + + public static FilterNode createFilterNode(final FilterBean bean) { + if (bean == null) return null; + return load(bean.getClass()).create(bean); + } + + private FilterNode create(final T bean) { + if (bean == null) return null; + FilterNode node = null; + final Serializable val = beanAttr.get(bean); + if (column != null && val != null) { + boolean skip = false; + if (string && ((CharSequence) val).length() == 0) { + skip = true; + } else if (number && ((Number) val).longValue() < least) { + skip = true; + } + if (!skip) { + if (this.joinClass == null) { + node = FilterNode.create(column, express, val); + } else { + node = FilterJoinNode.create(joinClass, joinColumns, column, express, val); + } + } + } + if (this.nodeBeans == null) return node; + for (final FilterNodeBean fnb : this.nodeBeans) { + FilterNode n = fnb.create(bean); + if (n == null) continue; + node = node == null ? n : ((!(n instanceof FilterJoinNode)) ? n.any(node, or) : node.any(n, or)); + } + return node; + } + + private static FilterNodeBean createFilterNodeBean(final Class clazz) { + final Set fields = new HashSet<>(); + final Map nodemap = new LinkedHashMap(); + Class cltmp = clazz; + do { + for (final Field field : cltmp.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (fields.contains(field.getName())) continue; + if (field.getAnnotation(Ignore.class) != null) continue; + if (field.getAnnotation(Transient.class) != null) continue; + + final boolean pubmod = Modifier.isPublic(field.getModifiers()); + + char[] chars = field.getName().toCharArray(); + chars[0] = Character.toUpperCase(chars[0]); + final Class t = field.getType(); + Method getter = null; + try { + getter = cltmp.getMethod(((t == boolean.class || t == Boolean.class) ? "is" : "get") + new String(chars)); + } catch (Exception ex) { + if (!pubmod) continue; + } + fields.add(field.getName()); + + final Attribute beanAttr = pubmod ? Attribute.create(field) : Attribute.create(getter, null); + FilterNodeBean nodeBean = new FilterNodeBean(field.getAnnotation(FilterJoinColumn.class), field.getAnnotation(FilterColumn.class), beanAttr); + + //------------------------------------ + { + FilterGroup[] refs = field.getAnnotationsByType(FilterGroup.class); + String[] groups = new String[refs.length]; + for (int i = 0; i < refs.length; i++) { + groups[i] = refs[i].value(); + } + if (groups.length == 0) groups = new String[]{"[AND]"}; + for (String key : groups) { + if (!key.startsWith("[AND]") && !key.startsWith("[OR]")) { + throw new RuntimeException(field + "'s FilterGroup.value(" + key + ") illegal, must be [AND] or [OR] startsWith"); + } + FilterNodeBean node = nodemap.get(key); + if (node == null) { + nodemap.put(key, nodeBean); + } else { + node.any(nodeBean, key.substring(key.lastIndexOf('.') + 1).contains("[OR]")); + } + } + } + } + } while ((cltmp = cltmp.getSuperclass()) != Object.class); + final Map linkes = new LinkedHashMap<>(); + nodemap.forEach((k, v) -> { + String[] keys = k.split("\\."); + LinkNode link = linkes.get(keys[0]); + if (link == null) { + linkes.put(keys[0], new LinkNode(k, v)); + } else { + link.put(keys, 0, v); + } + }); + FilterNodeBean rs = null; + for (LinkNode link : linkes.values()) { + FilterNodeBean f = link.createFilterNodeBean(); + if (f == null) continue; + rs = rs == null ? f : rs.and(f); + } + if (rs.nodeBeans != null) Arrays.sort(rs.nodeBeans); + return rs; + } + + @Override + public int compareTo(FilterNodeBean o) { + if (this.joinClass == null && o.joinClass == null) return 0; + if (this.joinClass != null && o.joinClass != null) return 0; + return this.joinClass == null ? -1 : 1; + } + + private static class LinkNode { + + public final boolean or; + + public final String key; + + public final List beans = new ArrayList<>(); + + public final Map nexts = new LinkedHashMap<>(); + + public LinkNode(String keyString, FilterNodeBean node) { + String[] keys = keyString.split("\\."); + this.key = keys[0]; + this.or = this.key.contains("[OR]"); + put(keys, 0, node); + } + + public LinkNode(String[] keyStrings, int pos, FilterNodeBean node) { + this.key = keyStrings[pos]; + this.or = this.key.contains("[OR]"); + put(keyStrings, pos, node); + } + + public FilterNodeBean createFilterNodeBean() { + FilterNodeBean node = null; + for (FilterNodeBean bean : beans) { + node = node == null ? bean : node.any(bean, or); + } + for (LinkNode link : nexts.values()) { + FilterNodeBean f = link.createFilterNodeBean(); + if (f == null) continue; + node = node == null ? f : node.any(f, or); + } + return node; + } + + public final void put(final String[] keys, int pos, final FilterNodeBean node) { + if (keys.length == pos + 1 && this.key.equals(keys[pos])) { + this.beans.add(node); + return; + } + LinkNode link = nexts.get(keys[pos + 1]); + if (link == null) { + nexts.put(keys[pos + 1], new LinkNode(keys, pos + 1, node)); + } else { + link.put(keys, pos + 1, node); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{key = '").append(key).append("', or = ").append(or); + if (!beans.isEmpty()) { + sb.append(", beans = [\r\n"); + for (FilterNodeBean bean : this.beans) { + sb.append(" ").append(bean).append("\r\n"); + } + sb.append("]"); + } + if (!nexts.isEmpty()) { + sb.append(", nexts = [\r\n"); + for (LinkNode link : this.nexts.values()) { + sb.append(" ").append(link).append("\r\n"); + } + sb.append("]"); + } + sb.append("}"); + return sb.toString(); + } + } + + private static FilterNodeBean load(Class clazz) { + FilterNodeBean rs = beanodes.get(clazz); + if (rs != null) return rs; + synchronized (beanodes) { + rs = beanodes.get(clazz); + if (rs == null) { + rs = createFilterNodeBean(clazz); + beanodes.put(clazz, rs); + } + return rs; + } + } + + @Override + public String toString() { + return toString(joinClass == null ? null : joinClass.getSimpleName()).toString(); + } + + protected StringBuilder toString(final String prefix) { + StringBuilder sb = new StringBuilder(); + StringBuilder element = toElementString(prefix); + boolean more = element.length() > 0 && this.nodeBeans != null; + if (more) sb.append('('); + sb.append(element); + if (this.nodeBeans != null) { + for (FilterNodeBean node : this.nodeBeans) { + String s = node.toString(); + if (s.length() < 1) continue; + if (sb.length() > 1) sb.append(or ? " OR " : " AND "); + sb.append(s); + } + } + if (more) sb.append(')'); + return sb; + } + + protected final StringBuilder toElementString(final String prefix) { + StringBuilder sb = new StringBuilder(); + if (column != null) { + String col = prefix == null ? column : (prefix + "." + column); + if (express == ISNULL || express == ISNOTNULL) { + sb.append(col).append(' ').append(express.value()); + } else { + sb.append((express == IGNORECASELIKE || express == IGNORECASENOTLIKE) ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(" ?"); + } + } + return sb; + } +}