/* * 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 org.redkale.source; import java.io.Serializable; import java.lang.reflect.Array; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.function.*; import java.util.logging.*; import java.util.stream.*; import javax.persistence.*; import static org.redkale.source.FilterFunc.*; import org.redkale.util.*; /** * Entity数据的缓存类 * * <p> * 详情见: https://redkale.org * * @author zhangjx * @param <T> Entity类的泛型 */ @SuppressWarnings("unchecked") public final class EntityCache<T> { //日志 private static final Logger logger = Logger.getLogger(EntityCache.class.getName()); //主键与对象的键值对 private ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap(); // CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢;10w数据查询需要 0.062秒, 查询慢40%; private Collection<T> list = new ConcurrentLinkedQueue(); //Flipper.sort转换成Comparator的缓存 private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>(); //Entity类 private final Class<T> type; //接口返回的对象是否需要复制一份 private final boolean needcopy; //Entity构建器 private final Creator<T> creator; //主键字段 private final Attribute<T, Serializable> primary; //新增时的复制器, 排除了标记为@Transient的字段 private final Reproduce<T, T> newReproduce; //修改时的复制器, 排除了标记为@Transient或@Column(updatable=false)的字段 private final Reproduce<T, T> chgReproduce; //是否已经全量加载过 private volatile boolean fullloaded; //Entity信息 final EntityInfo<T> info; //@Cacheable的定时更新秒数,为0表示不定时更新 final int interval; //@Cacheable的定时器 private ScheduledThreadPoolExecutor scheduler; public EntityCache(final EntityInfo<T> info, final Cacheable c) { this.info = info; this.interval = c == null ? 0 : c.interval(); this.type = info.getType(); this.creator = info.getCreator(); this.primary = info.primary; VirtualEntity ve = info.getType().getAnnotation(VirtualEntity.class); this.needcopy = ve == null || !ve.direct(); this.newReproduce = Reproduce.create(type, type, (m) -> { try { return type.getDeclaredField(m).getAnnotation(Transient.class) == null; } catch (Exception e) { return true; } }); this.chgReproduce = Reproduce.create(type, type, (m) -> { try { java.lang.reflect.Field field = type.getDeclaredField(m); if (field.getAnnotation(Transient.class) != null) return false; Column column = field.getAnnotation(Column.class); return (column == null || column.updatable()); } catch (Exception e) { return true; } }); } public void fullLoad() { if (info.fullloader == null) { this.list = new ConcurrentLinkedQueue(); this.map = new ConcurrentHashMap(); this.fullloaded = true; return; } this.fullloaded = false; ConcurrentHashMap newmap = new ConcurrentHashMap(); List<T> all = info.fullloader.apply(info.source, type); if (all != null) { all.stream().filter(x -> x != null).forEach(x -> { newmap.put(this.primary.get(x), x); }); } this.list = all == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all); this.map = newmap; this.fullloaded = true; if (this.interval > 0) { this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { final Thread t = new Thread(r, "EntityCache-" + type + "-Thread"); t.setDaemon(true); return t; }); this.scheduler.scheduleAtFixedRate(() -> { try { ConcurrentHashMap newmap2 = new ConcurrentHashMap(); List<T> all2 = info.fullloader.apply(info.source, type); if (all2 != null) { all2.stream().filter(x -> x != null).forEach(x -> { newmap2.put(this.primary.get(x), x); }); } this.list = all2 == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all2); this.map = newmap2; } catch (Throwable t) { logger.log(Level.SEVERE, type + " schedule(interval=" + interval + "s) Cacheable error", t); } }, interval - System.currentTimeMillis() / 1000 % interval, interval, TimeUnit.SECONDS); } } public Class<T> getType() { return type; } public int clear() { this.fullloaded = false; this.list = new ConcurrentLinkedQueue(); this.map = new ConcurrentHashMap(); if (this.scheduler != null) { this.scheduler.shutdownNow(); this.scheduler = null; } return 1; } public boolean isFullLoaded() { return fullloaded; } public T find(Serializable pk) { if (pk == null) return null; T rs = map.get(pk); return rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); } public T find(final SelectColumn selects, final Serializable pk) { if (pk == null) return null; T rs = map.get(pk); if (rs == null) return null; if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); T t = this.creator.create(); for (Attribute attr : this.info.attributes) { if (selects.test(attr.field())) attr.set(t, attr.get(rs)); } return t; } public T find(final SelectColumn selects, FilterNode node) { final Predicate<T> filter = node == null ? null : node.createPredicate(this); Stream<T> stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); Optional<T> opt = stream.findFirst(); if (!opt.isPresent()) return null; if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), opt.get()) : opt.get()); T rs = opt.get(); T t = this.creator.create(); for (Attribute attr : this.info.attributes) { if (selects.test(attr.field())) attr.set(t, attr.get(rs)); } return t; } public Serializable findColumn(final String column, final Serializable defValue, final Serializable pk) { if (pk == null) return defValue; T rs = map.get(pk); if (rs == null) return defValue; for (Attribute attr : this.info.attributes) { if (column.equals(attr.field())) { Serializable val = (Serializable) attr.get(rs); return val == null ? defValue : val; } } return defValue; } public Serializable findColumn(final String column, final Serializable defValue, FilterNode node) { final Predicate<T> filter = node == null ? null : node.createPredicate(this); Stream<T> stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); Optional<T> opt = stream.findFirst(); if (!opt.isPresent()) return defValue; T rs = opt.get(); for (Attribute attr : this.info.attributes) { if (column.equals(attr.field())) { Serializable val = (Serializable) attr.get(rs); return val == null ? defValue : val; } } return defValue; } public boolean exists(Serializable pk) { if (pk == null) return false; final Class atype = this.primary.type(); if (pk.getClass() != atype && pk instanceof Number) { if (atype == int.class || atype == Integer.class) { pk = ((Number) pk).intValue(); } else if (atype == long.class || atype == Long.class) { pk = ((Number) pk).longValue(); } else if (atype == short.class || atype == Short.class) { pk = ((Number) pk).shortValue(); } else if (atype == float.class || atype == Float.class) { pk = ((Number) pk).floatValue(); } else if (atype == byte.class || atype == Byte.class) { pk = ((Number) pk).byteValue(); } else if (atype == double.class || atype == Double.class) { pk = ((Number) pk).doubleValue(); } else if (atype == AtomicInteger.class) { pk = new AtomicInteger(((Number) pk).intValue()); } else if (atype == AtomicLong.class) { pk = new AtomicLong(((Number) pk).longValue()); } } return this.map.containsKey(pk); } public boolean exists(FilterNode node) { final Predicate<T> filter = node == null ? null : node.createPredicate(this); Stream<T> stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); return stream.findFirst().isPresent(); } public boolean exists(final Predicate<T> filter) { return (filter != null) && this.list.stream().filter(filter).findFirst().isPresent(); } public <K, V> Map<Serializable, Number> queryColumnMap(final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { final Attribute<T, Serializable> keyAttr = info.getAttribute(keyColumn); final Predicate filter = node == null ? null : node.createPredicate(this); final Attribute funcAttr = funcColumn == null ? null : info.getAttribute(funcColumn); Stream<T> stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); Collector<T, Map, ?> collector = null; final Class valtype = funcAttr == null ? null : funcAttr.type(); if (func != null) { switch (func) { case AVG: if (valtype == float.class || valtype == Float.class || valtype == double.class || valtype == Double.class) { collector = (Collector<T, Map, ?>) Collectors.averagingDouble((T t) -> ((Number) funcAttr.get(t)).doubleValue()); } else { collector = (Collector<T, Map, ?>) Collectors.averagingLong((T t) -> ((Number) funcAttr.get(t)).longValue()); } break; case COUNT: collector = (Collector<T, Map, ?>) Collectors.counting(); break; case DISTINCTCOUNT: collector = (Collector<T, Map, ?>) Collectors.mapping((t) -> funcAttr.get(t), Collectors.toSet()); break; case MAX: case MIN: Comparator<T> comp = (o1, o2) -> o1 == null ? (o2 == null ? 0 : -1) : ((Comparable) funcAttr.get(o1)).compareTo(funcAttr.get(o2)); collector = (Collector<T, Map, ?>) ((func == MAX) ? Collectors.maxBy(comp) : Collectors.minBy(comp)); break; case SUM: if (valtype == float.class || valtype == Float.class || valtype == double.class || valtype == Double.class) { collector = (Collector<T, Map, ?>) Collectors.summingDouble((T t) -> ((Number) funcAttr.get(t)).doubleValue()); } else { collector = (Collector<T, Map, ?>) Collectors.summingLong((T t) -> ((Number) funcAttr.get(t)).longValue()); } break; } } Map rs = collector == null ? stream.collect(Collectors.toMap(t -> keyAttr.get(t), t -> funcAttr.get(t), (key1, key2) -> key2)) : stream.collect(Collectors.groupingBy(t -> keyAttr.get(t), LinkedHashMap::new, collector)); if (func == MAX || func == MIN) { Map rs2 = new LinkedHashMap(); rs.forEach((x, y) -> { if (((Optional) y).isPresent()) rs2.put(x, funcAttr.get((T) ((Optional) y).get())); }); rs = rs2; } else if (func == DISTINCTCOUNT) { Map rs2 = new LinkedHashMap(); rs.forEach((x, y) -> rs2.put(x, ((Set) y).size() + 0L)); rs = rs2; } return rs; } public Map<Serializable[], Number[]> queryColumnMap(final ColumnNode[] funcNodes, final String[] groupByColumns, FilterNode node) { final Predicate<T> filter = node == null ? null : node.createPredicate(this); Stream<T> stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); final Attribute<T, Serializable>[] attrs = new Attribute[groupByColumns.length]; for (int i = 0; i < groupByColumns.length; i++) { attrs[i] = info.getAttribute(groupByColumns[i]); } final Map<String, Serializable[]> valmap = new HashMap<>(); Function<T, Serializable[]> func = t -> { StringBuilder sb = new StringBuilder(); final Serializable[] vals = new Serializable[attrs.length]; for (int i = 0; i < attrs.length; i++) { vals[i] = attrs[i].get(t); sb.append((char) 20).append(vals[i]); } final String key = sb.toString(); if (!valmap.containsKey(key)) valmap.put(key, vals); return valmap.get(key); }; Map<Serializable[], List<T>> listmap = stream.collect(Collectors.groupingBy(func)); final Map<Serializable[], Number[]> rsmap = new HashMap<>(listmap.size()); listmap.forEach((k, l) -> rsmap.put(k, queryColumnNumbers(l, funcNodes))); return rsmap; } private Number[] queryColumnNumbers(final List<T> list, final ColumnNode[] funcNodes) { if (true) throw new UnsupportedOperationException("Not supported yet."); Number[] rs = new Number[funcNodes.length]; for (int i = 0; i < rs.length; i++) { rs[i] = queryColumnNumber(list, funcNodes[i]); } return rs; } private Number queryColumnNumber(final List<T> list, final ColumnNode funcNode) { if (funcNode instanceof ColumnFuncNode) { return queryColumnNumber(list, (ColumnFuncNode) funcNode); } else if (funcNode instanceof ColumnNodeValue) { return queryColumnNumber(list, (ColumnNodeValue) funcNode); } else { return null; } } private Number queryColumnNumber(final List<T> list, final ColumnFuncNode funcNode) { if (funcNode.getValue() instanceof String) { final Attribute<T, Serializable> attr = info.getAttribute((String) funcNode.getValue()); final Function<T, Number> attrFunc = x -> (Number) attr.get(x); return getNumberResult(list, funcNode.getFunc(), null, attr.type(), attrFunc, (FilterNode) null); } Number num = null; if (funcNode.getValue() instanceof ColumnFuncNode) { num = queryColumnNumber(list, (ColumnFuncNode) funcNode.getValue()); } else if (funcNode.getValue() instanceof ColumnNodeValue) { num = queryColumnNumber(list, (ColumnNodeValue) funcNode.getValue()); } return num; } private Number queryColumnNumber(final List<T> list, final ColumnNodeValue nodeValue) { return null; } private <V> Number getNumberResult(final Collection<T> entityList, final FilterFunc func, final Number defResult, final Class attrType, final Function<T, Number> attrFunc, final FilterNode node) { final Predicate<T> filter = node == null ? null : node.createPredicate(this); Stream<T> stream = entityList.stream(); if (filter != null) stream = stream.filter(filter); switch (func) { case AVG: if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { OptionalDouble rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).average(); return rs.isPresent() ? (int) rs.getAsDouble() : defResult; } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class) { OptionalDouble rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).average(); return rs.isPresent() ? (long) rs.getAsDouble() : defResult; } else if (attrType == short.class || attrType == Short.class) { OptionalDouble rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).average(); return rs.isPresent() ? (short) rs.getAsDouble() : defResult; } else if (attrType == float.class || attrType == Float.class) { OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).average(); return rs.isPresent() ? (float) rs.getAsDouble() : defResult; } else if (attrType == double.class || attrType == Double.class) { OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).average(); return rs.isPresent() ? rs.getAsDouble() : defResult; } throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); case COUNT: return stream.count(); case DISTINCTCOUNT: return stream.map(x -> attrFunc.apply(x)).distinct().count(); case MAX: if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { OptionalInt rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).max(); return rs.isPresent() ? rs.getAsInt() : defResult; } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class) { OptionalLong rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).max(); return rs.isPresent() ? rs.getAsLong() : defResult; } else if (attrType == short.class || attrType == Short.class) { OptionalInt rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).max(); return rs.isPresent() ? (short) rs.getAsInt() : defResult; } else if (attrType == float.class || attrType == Float.class) { OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).max(); return rs.isPresent() ? (float) rs.getAsDouble() : defResult; } else if (attrType == double.class || attrType == Double.class) { OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).max(); return rs.isPresent() ? rs.getAsDouble() : defResult; } throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); case MIN: if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { OptionalInt rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).min(); return rs.isPresent() ? rs.getAsInt() : defResult; } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class) { OptionalLong rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).min(); return rs.isPresent() ? rs.getAsLong() : defResult; } else if (attrType == short.class || attrType == Short.class) { OptionalInt rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).min(); return rs.isPresent() ? (short) rs.getAsInt() : defResult; } else if (attrType == float.class || attrType == Float.class) { OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).min(); return rs.isPresent() ? (float) rs.getAsDouble() : defResult; } else if (attrType == double.class || attrType == Double.class) { OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).min(); return rs.isPresent() ? rs.getAsDouble() : defResult; } throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); case SUM: if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { return stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).sum(); } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class) { return stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).sum(); } else if (attrType == short.class || attrType == Short.class) { return (short) stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).sum(); } else if (attrType == float.class || attrType == Float.class) { return (float) stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).sum(); } else if (attrType == double.class || attrType == Double.class) { return stream.mapToDouble(x -> (Double) attrFunc.apply(x)).sum(); } throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); } return defResult; } public <V> Number getNumberResult(final FilterFunc func, final Number defResult, final String column, final FilterNode node) { final Attribute<T, Serializable> attr = column == null ? null : info.getAttribute(column); //COUNT的column=null final Function<T, Number> attrFunc = attr == null ? null : x -> (Number) attr.get(x); return getNumberResult(this.list, func, defResult, attr == null ? null : attr.type(), attrFunc, node); } public Sheet<T> querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node) { return querySheet(true, false, selects, flipper, node); } protected <T> Stream<T> distinctStream(Stream<T> stream, final List<Attribute<T, Serializable>> keyattrs) { if (keyattrs == null) return stream; final Set<String> keys = new HashSet<>(); Predicate<T> filter = t -> { StringBuilder sb = new StringBuilder(); for (Attribute attr : keyattrs) { sb.append(attr.get(t)); } String key = sb.toString(); if (keys.contains(key)) return false; keys.add(key); return true; }; return stream.filter(filter); } public Sheet<T> querySheet(final boolean needtotal, final boolean distinct, final SelectColumn selects, final Flipper flipper, FilterNode node) { final Predicate<T> filter = node == null ? null : node.createPredicate(this); final Comparator<T> comparator = createComparator(flipper); long total = 0; List<Attribute<T, Serializable>> keyattrs = null; if (distinct) { final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); info.forEachAttribute((k, v) -> { if (selects == null || selects.test(k)) attrs.add(v); }); keyattrs = attrs; } if (needtotal) { Stream<T> stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); if (distinct) stream = distinctStream(stream, keyattrs); total = stream.count(); } if (needtotal && total == 0) return new Sheet<>(0, new ArrayList()); Stream<T> stream = this.list.stream(); if (filter != null) stream = stream.filter(filter); if (distinct) stream = distinctStream(stream, keyattrs); if (comparator != null) stream = stream.sorted(comparator); if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset()); if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); final List<T> rs = new ArrayList<>(); if (selects == null) { Consumer<? super T> action = x -> rs.add(needcopy ? newReproduce.apply(creator.create(), x) : x); if (comparator != null) { stream.forEachOrdered(action); } else { stream.forEach(action); } } else { final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); info.forEachAttribute((k, v) -> { if (selects.test(k)) attrs.add(v); }); Consumer<? super T> action = x -> { final T item = creator.create(); for (Attribute attr : attrs) { attr.set(item, attr.get(x)); } rs.add(item); }; if (comparator != null) { stream.forEachOrdered(action); } else { stream.forEach(action); } } if (!needtotal) total = rs.size(); return new Sheet<>(total, rs); } public int insert(T entity) { if (entity == null) return 0; final T rs = newReproduce.apply(this.creator.create(), entity); //确保同一主键值的map与list中的对象必须共用。 T old = this.map.putIfAbsent(this.primary.get(rs), rs); if (old == null) { this.list.add(rs); return 1; } else { logger.log(Level.WARNING, this.type + " cache repeat insert data: " + entity); return 0; } } public int delete(final Serializable pk) { if (pk == null) return 0; final T rs = this.map.remove(pk); if (rs == null) return 0; this.list.remove(rs); return 1; } public Serializable[] delete(final Flipper flipper, final FilterNode node) { if (node == null || this.list.isEmpty()) return new Serializable[0]; final Comparator<T> comparator = createComparator(flipper); Stream<T> stream = this.list.stream().filter(node.createPredicate(this)); if (comparator != null) stream = stream.sorted(comparator); if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset()); if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); Object[] rms = stream.toArray(); Serializable[] ids = new Serializable[rms.length]; int i = -1; for (Object o : rms) { final T t = (T) o; ids[++i] = this.primary.get(t); this.map.remove(ids[i]); this.list.remove(t); } return ids; } public int drop() { return clear(); } public int update(final T entity) { if (entity == null) return 0; T rs = this.map.get(this.primary.get(entity)); if (rs == null) return 0; synchronized (rs) { this.chgReproduce.apply(rs, entity); } return 1; } public T update(final T entity, Collection<Attribute<T, Serializable>> attrs) { if (entity == null) return entity; T rs = this.map.get(this.primary.get(entity)); if (rs == null) return rs; synchronized (rs) { for (Attribute attr : attrs) { attr.set(rs, attr.get(entity)); } } return rs; } public T[] update(final T entity, final Collection<Attribute<T, Serializable>> attrs, final FilterNode node) { if (entity == null || node == null) return (T[]) Array.newInstance(type, 0); T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); for (T rs : rms) { synchronized (rs) { for (Attribute attr : attrs) { attr.set(rs, attr.get(entity)); } } } return rms; } public <V> T update(final Serializable pk, Attribute<T, V> attr, final V fieldValue) { if (pk == null) return null; T rs = this.map.get(pk); if (rs != null) attr.set(rs, fieldValue); return rs; } public <V> T[] update(Attribute<T, V> attr, final V fieldValue, final FilterNode node) { if (attr == null || node == null) return (T[]) Array.newInstance(type, 0); T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); for (T rs : rms) { attr.set(rs, fieldValue); } return rms; } public <V> T updateColumn(final Serializable pk, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) { if (pk == null || attrs == null || attrs.isEmpty()) return null; T rs = this.map.get(pk); if (rs == null) return rs; synchronized (rs) { for (int i = 0; i < attrs.size(); i++) { ColumnValue cv = values.get(i); updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue()); } } return rs; } public <V> T[] updateColumn(final FilterNode node, final Flipper flipper, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) { if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0); Stream<T> stream = this.list.stream(); final Comparator<T> comparator = createComparator(flipper); if (comparator != null) stream = stream.sorted(comparator); if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); T[] rms = stream.filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); for (T rs : rms) { synchronized (rs) { for (int i = 0; i < attrs.size(); i++) { ColumnValue cv = values.get(i); updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue()); } } } return rms; } public <V> T updateColumnOr(final Serializable pk, Attribute<T, V> attr, final long orvalue) { if (pk == null) return null; T rs = this.map.get(pk); if (rs == null) return rs; synchronized (rs) { return updateColumn(attr, rs, ColumnExpress.ORR, orvalue); } } public <V> T updateColumnAnd(final Serializable pk, Attribute<T, V> attr, final long andvalue) { if (pk == null) return null; T rs = this.map.get(pk); if (rs == null) return rs; synchronized (rs) { return updateColumn(attr, rs, ColumnExpress.AND, andvalue); } } public <V> T updateColumnIncrement(final Serializable pk, Attribute<T, V> attr, final long incvalue) { if (pk == null) return null; T rs = this.map.get(pk); if (rs == null) return rs; synchronized (rs) { return updateColumn(attr, rs, ColumnExpress.INC, incvalue); } } public <V> T updateColumnDecrement(final Serializable pk, Attribute<T, V> attr, final long incvalue) { if (pk == null) return null; T rs = this.map.get(pk); if (rs == null) return rs; synchronized (rs) { return updateColumn(attr, rs, ColumnExpress.DEC, incvalue); } } private <V> T updateColumn(Attribute<T, V> attr, final T entity, final ColumnExpress express, Serializable val) { final Class ft = attr.type(); Number numb = null; Serializable newval = null; switch (express) { case INC: case DEC: case MUL: case DIV: case MOD: case AND: case ORR: numb = getValue((Number) attr.get(entity), express, val); break; case MOV: if (val instanceof ColumnNodeValue) val = updateColumnNodeValue(attr, entity, (ColumnNodeValue) val); newval = val; if (val instanceof Number) numb = (Number) val; break; } if (numb != null) { if (ft == int.class || ft == Integer.class) { newval = numb.intValue(); } else if (ft == long.class || ft == Long.class) { newval = numb.longValue(); } else if (ft == short.class || ft == Short.class) { newval = numb.shortValue(); } else if (ft == float.class || ft == Float.class) { newval = numb.floatValue(); } else if (ft == double.class || ft == Double.class) { newval = numb.doubleValue(); } else if (ft == byte.class || ft == Byte.class) { newval = numb.byteValue(); } else if (ft == AtomicInteger.class) { newval = new AtomicInteger(numb.intValue()); } else if (ft == AtomicLong.class) { newval = new AtomicLong(numb.longValue()); } } else { if (ft == AtomicInteger.class && newval != null && newval.getClass() != AtomicInteger.class) { newval = new AtomicInteger(((Number) newval).intValue()); } else if (ft == AtomicLong.class && newval != null && newval.getClass() != AtomicLong.class) { newval = new AtomicLong(((Number) newval).longValue()); } } attr.set(entity, (V) newval); return entity; } private <V> Serializable updateColumnNodeValue(Attribute<T, V> attr, final T entity, ColumnNodeValue node) { Serializable left = node.getLeft(); if (left instanceof CharSequence) { left = info.getUpdateAttribute(left.toString()).get(entity); } else if (left instanceof ColumnNodeValue) { left = updateColumnNodeValue(attr, entity, (ColumnNodeValue) left); } Serializable right = node.getRight(); if (left instanceof CharSequence) { right = info.getUpdateAttribute(right.toString()).get(entity); } else if (left instanceof ColumnNodeValue) { right = updateColumnNodeValue(attr, entity, (ColumnNodeValue) right); } return getValue((Number) left, node.getExpress(), right); } private <V> Number getValue(Number numb, final ColumnExpress express, Serializable val) { switch (express) { case INC: if (numb == null) { numb = (Number) val; } else { if (numb instanceof Float || ((Number) val) instanceof Float) { numb = numb.floatValue() + ((Number) val).floatValue(); } else if (numb instanceof Double || ((Number) val) instanceof Double) { numb = numb.doubleValue() + ((Number) val).doubleValue(); } else { numb = numb.longValue() + ((Number) val).longValue(); } } break; case DEC: if (numb == null) { numb = (Number) val; } else { if (numb instanceof Float || ((Number) val) instanceof Float) { numb = numb.floatValue() - ((Number) val).floatValue(); } else if (numb instanceof Double || ((Number) val) instanceof Double) { numb = numb.doubleValue() - ((Number) val).doubleValue(); } else { numb = numb.longValue() - ((Number) val).longValue(); } } break; case MUL: if (numb == null) { numb = 0; } else { numb = numb.longValue() * ((Number) val).floatValue(); } break; case DIV: if (numb == null) { numb = 0; } else { numb = numb.longValue() / ((Number) val).floatValue(); } break; case MOD: if (numb == null) { numb = 0; } else { numb = numb.longValue() % ((Number) val).intValue(); } break; case AND: if (numb == null) { numb = 0; } else { numb = numb.longValue() & ((Number) val).longValue(); } break; case ORR: if (numb == null) { numb = 0; } else { numb = numb.longValue() | ((Number) val).longValue(); } break; } return numb; } public Attribute<T, Serializable> getAttribute(String fieldname) { return info.getAttribute(fieldname); } //------------------------------------------------------------------------------------------------------------------------------- protected Comparator<T> createComparator(Flipper flipper) { if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty() || flipper.getSort().indexOf(';') >= 0 || flipper.getSort().indexOf('\n') >= 0) return null; final String sort = flipper.getSort(); Comparator<T> comparator = this.sortComparators.get(sort); if (comparator != null) return comparator; for (String item : sort.split(",")) { if (item.trim().isEmpty()) continue; String[] sub = item.trim().split("\\s+"); int pos = sub[0].indexOf('('); Attribute<T, Serializable> attr; if (pos <= 0) { attr = getAttribute(sub[0]); } else { //含SQL函数 int pos2 = sub[0].lastIndexOf(')'); final Attribute<T, Serializable> pattr = getAttribute(sub[0].substring(pos + 1, pos2)); final String func = sub[0].substring(0, pos); if ("ABS".equalsIgnoreCase(func)) { Function getter = null; if (pattr.type() == int.class || pattr.type() == Integer.class || pattr.type() == AtomicInteger.class) { getter = x -> Math.abs(((Number) pattr.get((T) x)).intValue()); } else if (pattr.type() == long.class || pattr.type() == Long.class || pattr.type() == AtomicLong.class) { getter = x -> Math.abs(((Number) pattr.get((T) x)).longValue()); } else if (pattr.type() == float.class || pattr.type() == Float.class) { getter = x -> Math.abs(((Number) pattr.get((T) x)).floatValue()); } else if (pattr.type() == double.class || pattr.type() == Double.class) { getter = x -> Math.abs(((Number) pattr.get((T) x)).doubleValue()); } else { throw new RuntimeException("Flipper not supported sort illegal type by ABS (" + flipper.getSort() + ")"); } attr = (Attribute<T, Serializable>) Attribute.create(pattr.declaringClass(), pattr.field(), pattr.type(), getter, (o, v) -> pattr.set(o, v)); } else if (func.isEmpty()) { attr = pattr; } else { throw new RuntimeException("Flipper not supported sort illegal function (" + flipper.getSort() + ")"); } } Comparator<T> c = (sub.length > 1 && sub[1].equalsIgnoreCase("DESC")) ? (T o1, T o2) -> { Comparable c1 = (Comparable) attr.get(o1); Comparable c2 = (Comparable) attr.get(o2); return c2 == null ? -1 : c2.compareTo(c1); } : (T o1, T o2) -> { Comparable c1 = (Comparable) attr.get(o1); Comparable c2 = (Comparable) attr.get(o2); return c1 == null ? -1 : c1.compareTo(c2); }; if (comparator == null) { comparator = c; } else { comparator = comparator.thenComparing(c); } } this.sortComparators.put(sort, comparator); return comparator; } private static class UniqueSequence implements Serializable { private final Serializable[] value; public UniqueSequence(Serializable[] val) { this.value = val; } @Override public int hashCode() { return Arrays.deepHashCode(this.value); } @Override public boolean equals(Object obj) { if (obj == null) return false; if (getClass() != obj.getClass()) return false; final UniqueSequence other = (UniqueSequence) obj; if (value.length != other.value.length) return false; for (int i = 0; i < value.length; i++) { if (!value[i].equals(other.value[i])) return false; } return true; } } private static interface UniqueAttribute<T> extends Predicate<FilterNode> { public Serializable getValue(T bean); @Override public boolean test(FilterNode node); public static <T> UniqueAttribute<T> create(final Attribute<T, Serializable>[] attributes) { if (attributes.length == 1) { final Attribute<T, Serializable> attribute = attributes[0]; return new UniqueAttribute<T>() { @Override public Serializable getValue(T bean) { return attribute.get(bean); } @Override public boolean test(FilterNode node) { if (node == null || node.isOr()) return false; if (!attribute.field().equals(node.column)) return false; if (node.nodes == null) return true; for (FilterNode n : node.nodes) { if (!test(n)) return false; } return true; } }; } else { return new UniqueAttribute<T>() { @Override public Serializable getValue(T bean) { final Serializable[] rs = new Serializable[attributes.length]; for (int i = 0; i < rs.length; i++) { rs[i] = attributes[i].get(bean); } return new UniqueSequence(rs); } @Override public boolean test(FilterNode node) { return true; } }; } } } }