65 Commits

Author SHA1 Message Date
Redkale
a4ffc7a27c 2019-03-30 20:23:55 +08:00
Redkale
91bf7b1387 2019-03-30 17:28:25 +08:00
Redkale
1396296337 2019-03-29 11:51:19 +08:00
Redkale
e4672355fc Convert增加StringConvertWrapper功能 2019-03-29 11:44:37 +08:00
Redkale
129ed25ca4 2019-03-29 09:08:16 +08:00
Redkale
e6d7e5fe98 2019-03-28 17:36:31 +08:00
Redkale
73ce5fa11f Convert支持AbstractMap.SimpleEntry 2019-03-28 14:56:28 +08:00
Redkale
ce01c3d4ce 2019-03-22 12:21:38 +08:00
Redkale
3b3de316ea 2019-03-21 14:19:35 +08:00
Redkale
8c739ce54d 2019-03-16 12:58:54 +08:00
Redkale
0aa4d6c967 2019-03-15 10:19:00 +08:00
Redkale
d7a3f4d87d 2019-03-14 21:25:14 +08:00
Redkale
fe9e074581 2019-03-14 17:00:22 +08:00
Redkale
40813e8752 2019-03-14 16:17:43 +08:00
Redkale
e90f2e4142 WebSocket增加mergemsg属性功能 2019-03-14 15:27:05 +08:00
Redkale
2a19ea709b 2019-03-14 13:47:57 +08:00
Redkale
30c9be303f Convert增加ConvertMask[]参数方法 2019-03-14 13:17:31 +08:00
Redkale
e101b79472 修复ws数据包过大粘包的bug 2019-03-14 12:32:07 +08:00
Redkale
8ad919f952 修复了Convert在忽略子类某些字段时因为Method导致无法忽略父类的getter方法的bug 2019-03-06 09:31:18 +08:00
Redkale
294543c46e 取消DataSource兼容找不到unitName时使用第一个配置的功能 2019-03-05 20:16:57 +08:00
Redkale
79f8363d47 2019-03-05 12:23:21 +08:00
Redkale
6d3553b0b5 2019-02-12 13:16:43 +08:00
Redkale
403ab4e281 2019-02-12 12:23:03 +08:00
Redkale
87e7c43032 修复JDK9+以上RedkaleClassLoader的getAllURLS方法中的BUG 2019-02-12 11:52:23 +08:00
Redkale
a321b41699 2019-01-19 16:28:44 +08:00
Redkale
fea34863e3 2019-01-18 22:25:20 +08:00
Redkale
bcaf7ab73e 2019-01-18 19:48:32 +08:00
Redkale
b9d7eaee1b 2019-01-18 18:52:47 +08:00
Redkale
d605045858 2019-01-18 16:55:48 +08:00
Redkale
cf2ab617c2 修复AioAsyncConnection关闭时write队列还有数据没写完的bug 2019-01-18 15:50:23 +08:00
Redkale
204514cb08 增加Utility.nowMillis方法 2019-01-18 10:41:30 +08:00
Redkale
cfe01cca75 2019-01-16 19:04:54 +08:00
Redkale
ac294c58ae 2019-01-16 19:01:48 +08:00
Redkale
6950eb2f30 2019-01-13 16:51:06 +08:00
Redkale
847f81374b 2019-01-12 11:44:50 +08:00
Redkale
bb09aea8bb 2019-01-12 11:28:29 +08:00
Redkale
2e1ff333f5 Application.singleton多加一个参数,指定其他Service也被加载 2019-01-12 11:16:27 +08:00
Redkale
c14a2b4011 updateColumnCompose 2019-01-12 11:15:02 +08:00
Redkale
d9c6c3d2d0 2019-01-11 16:51:21 +08:00
Redkale
91d4477ed9 DataSource增加字段加解密功能,主类:CryptColumn/CryptHandler 2019-01-11 16:41:14 +08:00
Redkale
623c0a127e Attribute增加attach方法 2019-01-11 15:22:29 +08:00
Redkale
bc64666700 Reproduce.create方法中BiPredicate参数的第一个泛型改为AccessibleObject 2019-01-10 18:43:45 +08:00
Redkale
5c7dd7d782 2019-01-09 16:17:48 +08:00
Redkale
e78a2da6c0 2019-01-09 16:16:08 +08:00
Redkale
065be6f3d7 增加RetResult.success(V result)方法 2019-01-09 09:44:53 +08:00
Redkale
874f3330b8 Update README.md 2019-01-08 14:33:41 +08:00
Redkale
684edfa10b 2019-01-08 12:54:09 +08:00
Redkale
e69a120965 2019-01-08 12:46:20 +08:00
Redkale
4a36244294 2019-01-08 12:39:21 +08:00
Redkale
cb444be0f7 优化Application.singleton方法 2019-01-08 12:32:47 +08:00
Redkale
8b5cbf186f 2019-01-08 09:13:05 +08:00
Redkale
dbc6f8a196 2019-01-07 21:38:44 +08:00
Redkale
9b94604166 2019-01-07 21:17:20 +08:00
Redkale
cc98a85711 2019-01-07 21:09:22 +08:00
Redkale
6855d06f55 JsonConvert增加不带Type参数的convertTo方法 2019-01-07 20:07:36 +08:00
Redkale
89d90ddf5b 修复getHttpContent会变成POST请求的bug 2019-01-07 17:05:02 +08:00
Redkale
6280111121 2019-01-05 09:42:03 +08:00
Redkale
231d41c15f DataSource增加清空表clear和删除表drop的系列方法 2019-01-04 14:26:20 +08:00
Redkale
cfca7adc66 2019-01-03 18:38:07 +08:00
Redkale
aedd215de4 2019-01-03 18:33:49 +08:00
Redkale
df8e839580 优化WebSocket给多个userid发消息的实现 2019-01-03 09:35:28 +08:00
Redkale
300441b9f7 DataSource增加getCollectionMap系列接口 2019-01-03 09:33:19 +08:00
Redkale
1a5e9022ae Convert支持java.time.Duration 2019-01-03 09:07:26 +08:00
Redkale
2a3b8f87d3 兼容@Resource标记在泛型类型字段上 2019-01-03 09:06:08 +08:00
Redkale
b7930f1ed7 Redkale 2.0.0 开始 2019-01-03 09:05:00 +08:00
61 changed files with 2298 additions and 696 deletions

View File

@@ -19,8 +19,6 @@
</p>
&nbsp;&nbsp;&nbsp;编译RedKale 1.8.x版本需要在源码工程中的编译器选项中加入 <b>-XDignore.symbol.file=true</b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>详情请访问:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>基本文档:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>

View File

@@ -15,7 +15,7 @@
</request>
<response>
<defcookie domain="" path=""/>
<defcookie domain="" path="/"/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Credentials" value="true"/>
</response>

View File

@@ -67,7 +67,6 @@
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
@@ -114,7 +113,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<version>3.0.0</version>
<executions>
<execution>
<goals>

View File

@@ -135,7 +135,7 @@ public final class Application {
//--------------------------------------------------------------------------------------------
//是否用于main方法运行
private final boolean singletonrun;
final boolean singletonrun;
//根WatchFactory
//private final WatchFactory watchFactory = WatchFactory.root();
@@ -812,13 +812,22 @@ public final class Application {
sercdl.await();
}
public static <T extends Service> T singleton(Class<T> serviceClass) throws Exception {
return singleton("", serviceClass);
public static <T extends Service> T singleton(Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
return singleton("", serviceClass, extServiceClasses);
}
public static <T extends Service> T singleton(String name, Class<T> serviceClass) throws Exception {
public static <T extends Service> T singleton(String name, Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
final Application application = Application.create(true);
System.setProperty("red" + "kale-singleton-serviceclass", serviceClass.getName());
if (extServiceClasses != null && extServiceClasses.length > 0) {
StringBuilder sb = new StringBuilder();
for (Class clazz : extServiceClasses) {
if (sb.length() > 0) sb.append(',');
sb.append(clazz.getName());
}
System.setProperty("red" + "kale-singleton-extserviceclasses", sb.toString());
}
application.init();
application.start();
for (NodeServer server : application.servers) {
@@ -878,7 +887,7 @@ public final class Application {
return null;
}
private void shutdown() throws Exception {
public void shutdown() throws Exception {
for (ApplicationListener listener : this.listeners) {
try {
listener.preShutdown(this);

View File

@@ -11,6 +11,7 @@ import java.lang.reflect.Modifier;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Predicate;
import java.util.jar.*;
import java.util.logging.*;
import java.util.regex.*;
@@ -36,6 +37,8 @@ public final class ClassFilter<T> {
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
private Predicate<String> expectPredicate;
private boolean refused; //是否拒绝所有数据,设置true则其他规则失效,都是拒绝.
private Class superClass; //符合的父类型。不为空时扫描结果的class必须是superClass的子类
@@ -196,7 +199,7 @@ public final class ClassFilter<T> {
}
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)的
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)的
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
} else {
entrys.add(new FilterEntry(clazz, autoscan, false, property));
@@ -347,6 +350,14 @@ public final class ClassFilter<T> {
this.refused = refused;
}
public Predicate<String> getExpectPredicate() {
return expectPredicate;
}
public void setExpectPredicate(Predicate<String> predicate) {
this.expectPredicate = predicate;
}
public Set<String> getPrivilegeIncludes() {
return privilegeIncludes;
}

View File

@@ -154,6 +154,20 @@ public abstract class NodeServer {
}
ClassFilter<Service> serviceFilter = createServiceClassFilter();
if (application.singletonrun) { //singleton模式下只加载指定的Service
final String ssc = System.getProperty("red" + "kale-singleton-serviceclass");
final String extssc = System.getProperty("red" + "kale-singleton-extserviceclasses");
if (ssc != null) {
final List<String> sscList = new ArrayList<>();
sscList.add(ssc);
if (extssc != null && !extssc.isEmpty()) {
for (String s : extssc.split(",")) {
if (!s.isEmpty()) sscList.add(s);
}
}
serviceFilter.setExpectPredicate(c -> !sscList.contains(c));
}
}
ClassFilter<Filter> filterFilter = createFilterClassFilter();
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter otherFilter = createOtherClassFilter();
@@ -162,9 +176,10 @@ public abstract class NodeServer {
long e = System.currentTimeMillis() - s;
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
loadService(serviceFilter, otherFilter); //必须在servlet之前
loadFilter(filterFilter, otherFilter);
loadServlet(servletFilter, otherFilter);
if (!application.singletonrun) { //非singleton模式下才加载Filter、Servlet
loadFilter(filterFilter, otherFilter);
loadServlet(servletFilter, otherFilter);
}
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
}

View File

@@ -32,7 +32,7 @@ public class NodeSncpServer extends NodeServer {
private NodeSncpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server;
this.consumer = sncpServer == null ? null : x -> sncpServer.addSncpServlet(x);
this.consumer = sncpServer == null || application.singletonrun ? null : x -> sncpServer.addSncpServlet(x); //singleton模式下不生成SncpServlet
}
public static NodeServer createNodeServer(Application application, AnyValue serconf) {

View File

@@ -0,0 +1,64 @@
/*
* 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.convert;
import java.lang.reflect.Type;
import java.util.*;
import org.redkale.util.*;
import org.redkale.convert.Reader.ValueType;
import static org.redkale.convert.Reader.ValueType.MAP;
/**
* 对不明类型的对象进行反序列化。 <br>
* <b>注意: 目前只支持文本格式</b> <br>
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class AnyDecoder implements Decodeable<Reader, Object> {
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
}.getType();
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
}.getType();
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
protected final Decodeable<Reader, String> stringDecoder;
protected final CollectionDecoder collectionDecoder;
protected final MapDecoder mapDecoder;
public AnyDecoder(final ConvertFactory factory) {
this.stringDecoder = factory.loadDecoder(String.class);
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
}
@Override
public Object convertFrom(Reader in) {
ValueType vt = in.readType();
if (vt == null) return null;
switch (vt) {
case ARRAY:
return this.collectionDecoder.convertFrom(in);
case MAP:
return this.mapDecoder.convertFrom(in);
}
return this.stringDecoder.convertFrom(in);
}
@Override
public Type getType() {
return void.class;
}
}

View File

@@ -8,7 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.*;
/**
* Collection的反序列化操作类 <br>
@@ -60,6 +60,17 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
}
}
//仅供类似JsonAnyDecoder这种动态创建使用 不得调用 factory.register
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
Objects.requireNonNull(componentDecoder);
this.type = type;
this.componentType = componentType;
this.creator = creator;
this.componentDecoder = componentDecoder;
this.inited = true;
}
@Override
public Collection<T> convertFrom(Reader in) {
return convertFrom(in, null);

View File

@@ -33,6 +33,8 @@ public abstract class Convert<R extends Reader, W extends Writer> {
public abstract boolean isBinary();
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);

View File

@@ -91,8 +91,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(Number.class, NumberSimpledCoder.instance);
this.register(String.class, StringSimpledCoder.instance);
this.register(StringConvertWrapper.class, StringConvertWrapperSimpledCoder.instance);
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
this.register(java.util.Date.class, DateSimpledCoder.instance);
this.register(java.time.Duration.class, DurationSimpledCoder.instance);
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
@@ -219,15 +221,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
return false;
}
public ConvertColumnEntry findRef(AccessibleObject element) {
public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) {
if (element == null) return null;
ConvertColumnEntry en = this.columnEntrys.get(element);
Set<String> onlyColumns = null;
if (element instanceof Method) {
onlyColumns = ignoreAlls.get(((Method) element).getDeclaringClass());
} else if (element instanceof Field) {
onlyColumns = ignoreAlls.get(((Field) element).getDeclaringClass());
}
Set<String> onlyColumns = ignoreAlls.get(clazz);
if (en != null && onlyColumns == null) return en;
final ConvertType ct = this.getConvertType();
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
@@ -406,12 +403,27 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
}
}
public final void registerIgnoreAll(final Class type, Collection<String> excludeColumns) {
Set<String> set = ignoreAlls.get(type);
if (set == null) {
ignoreAlls.put(type, new HashSet<>(excludeColumns));
} else {
set.addAll(new ArrayList(excludeColumns));
}
}
public final void register(final Class type, boolean ignore, String... columns) {
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
}
}
public final void register(final Class type, boolean ignore, Collection<String> columns) {
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
}
}
public final boolean register(final Class type, String column, String alias) {
return register(type, column, new ConvertColumnEntry(alias));
}
@@ -604,6 +616,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
decoder = od;
} else if (!clazz.getName().startsWith("java.")
|| java.net.HttpCookie.class == clazz
|| java.util.AbstractMap.SimpleEntry.class == clazz
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
Decodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) {
@@ -687,7 +700,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
encoder = new OptionalCoder(this, type);
} else if (clazz == Object.class) {
return (Encodeable<W, E>) this.anyEncoder;
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz) {
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
Encodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())) continue;

View File

@@ -8,7 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.*;
/**
* Map的反序列化操作类 <br>
@@ -74,6 +74,20 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
}
}
//仅供类似JsonAnyDecoder这种动态创建使用 不得调用 factory.register
public MapDecoder(final ConvertFactory factory, Type type, Type keyType, Type valueType,
Creator<Map<K, V>> creator, final Decodeable<Reader, K> keyDecoder, Decodeable<Reader, V> valueDecoder) {
Objects.requireNonNull(keyDecoder);
Objects.requireNonNull(valueDecoder);
this.type = type;
this.keyType = keyType;
this.valueType = valueType;
this.creator = creator;
this.keyDecoder = keyDecoder;
this.valueDecoder = valueDecoder;
this.inited = true;
}
@Override
public Map<K, V> convertFrom(Reader in) {
return convertFrom(in, null);

View File

@@ -94,7 +94,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(field);
ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue;
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
if (fieldCoder == null) {
@@ -123,7 +123,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
continue;
}
}
ref = factory.findRef(method);
ref = factory.findRef(clazz, method);
if (ref != null && ref.ignore()) continue;
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));

View File

@@ -75,7 +75,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(field);
ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue;
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
if (fieldCoder == null) {
@@ -104,7 +104,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
continue;
}
}
ref = factory.findRef(method);
ref = factory.findRef(clazz, method);
if (ref != null && ref.ignore()) continue;
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
if (fieldCoder == null) {
@@ -253,24 +253,24 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
String fieldalias;
if (field != null) { // public field
ConvertColumnEntry ref = factory.findRef(field);
ConvertColumnEntry ref = factory.findRef(clazz, field);
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
} else if (getter != null) {
ConvertColumnEntry ref = factory.findRef(getter);
ConvertColumnEntry ref = factory.findRef(clazz, getter);
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
} else { // setter != null
ConvertColumnEntry ref = factory.findRef(setter);
ConvertColumnEntry ref = factory.findRef(clazz, setter);
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}

View File

@@ -15,6 +15,10 @@ package org.redkale.convert;
*/
public abstract class Reader {
public static enum ValueType {
STRING, ARRAY, MAP;
}
//当前对象字段名的游标
protected int fieldIndex;
@@ -73,6 +77,13 @@ public abstract class Reader {
*/
public abstract void readBlank();
/**
* 读取下个值的类型
*
* @return ValueType
*/
public abstract ValueType readType();
/**
* 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。
*

View File

@@ -0,0 +1,63 @@
/*
* 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.convert;
import org.redkale.convert.json.JsonConvert;
/**
* 序列化去掉引号的String对象。
* <blockquote><pre>
* 场景: JavaBean bean = ... ;
* Map map = new HashMap();
* map.put("bean", a);
* records.add(map);
* records需要在后期序列化写入库。 但是在这期间bean的内部字段值可能就变化了会导致入库时并不是records.add的快照信息。
* 所以需要使用StringConvertWrapper
* Map map = new HashMap();
* map.put("bean", new StringConvertWrapper(bean.toString()));
* records.add(map);
* 这样既可以保持快照又不会在bean的值上面多一层引号。
* </pre></blockquote>
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class StringConvertWrapper {
protected String value;
public StringConvertWrapper() {
}
public StringConvertWrapper(String value) {
this.value = value;
}
public static StringConvertWrapper create(Object value) {
return create(JsonConvert.root(), value);
}
public static StringConvertWrapper create(TextConvert convert, Object value) {
if (value == null) return new StringConvertWrapper(null);
if (value instanceof String) return new StringConvertWrapper((String) value);
return new StringConvertWrapper(convert.convertTo(value));
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}

View File

@@ -129,9 +129,9 @@ public abstract class Writer {
/**
* 输出一个数组前的操作
*
* @param size 数组长度
* @param size 数组长度
* @param componentEncoder Encodeable
* @param obj 对象
* @param obj 对象, 不一定是数组、Collection对象也可能是伪Collection对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
@@ -155,7 +155,7 @@ public abstract class Writer {
* @param size map大小
* @param keyEncoder Encodeable
* @param valueEncoder Encodeable
* @param obj 对象
* @param obj 对象, 不一定是Map对象也可能是伪Map对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
@@ -256,4 +256,11 @@ public abstract class Writer {
* @param value String值
*/
public abstract void writeString(String value);
/**
* 写入一个StringConvertWrapper值
*
* @param value StringConvertWrapper值
*/
public abstract void writeWrapper(StringConvertWrapper value);
}

View File

@@ -346,4 +346,9 @@ public class BsonReader extends Reader {
return value;
}
@Override
public ValueType readType() {
throw new UnsupportedOperationException("Not supported yet.");
}
}

View File

@@ -241,6 +241,11 @@ public class BsonWriter extends Writer {
writeTo(bytes);
}
@Override
public final void writeWrapper(StringConvertWrapper value) {
this.writeString(value == null ? null : value.getValue());
}
@Override
public final void writeNull() {
writeShort(Reader.SIGN_NULL);

View File

@@ -0,0 +1,41 @@
/*
* 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.convert.ext;
import java.time.Duration;
import org.redkale.convert.*;
/**
* Duration 的SimpledCoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public class DurationSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Duration> {
public static final DurationSimpledCoder instance = new DurationSimpledCoder();
@Override
public void convertTo(W out, Duration value) {
if (value == null) {
out.writeNull();
} else {
out.writeLong(value.toNanos());
}
}
@Override
public Duration convertFrom(R in) {
String value = in.readSmallString();
if (value == null) return null;
return Duration.ofNanos(Long.parseLong(value));
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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.convert.ext;
import org.redkale.convert.*;
/**
* String 的SimpledCoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class StringConvertWrapperSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringConvertWrapper> {
public static final StringConvertWrapperSimpledCoder instance = new StringConvertWrapperSimpledCoder();
@Override
public void convertTo(W out, StringConvertWrapper value) {
out.writeWrapper(value);
}
@Override
public StringConvertWrapper convertFrom(R in) {
return new StringConvertWrapper(in.readString());
}
}

View File

@@ -85,6 +85,11 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
}
//------------------------------ convertFrom -----------------------------------------------------------
public <T> T convertFrom(final Type type, final byte[] bytes) {
if (bytes == null) return null;
return convertFrom(type, new String(bytes, StandardCharsets.UTF_8));
}
public <T> T convertFrom(final Type type, final String text) {
if (text == null) return null;
return convertFrom(type, Utility.charArray(text));
@@ -128,6 +133,52 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
return rs;
}
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
public <V> V convertFrom(final String text) {
if (text == null) return null;
return (V) convertFrom(Utility.charArray(text));
}
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
public <V> V convertFrom(final char[] text) {
if (text == null) return null;
return (V) convertFrom(text, 0, text.length);
}
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
public <V> V convertFrom(final char[] text, final int start, final int len) {
if (text == null) return null;
final JsonReader in = readerPool.get();
in.setText(text, start, len);
Object rs = new AnyDecoder(factory).convertFrom(in);
readerPool.accept(in);
return (V) rs;
}
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
public <V> V convertFrom(final InputStream in) {
if (in == null) return null;
return (V) new AnyDecoder(factory).convertFrom(new JsonStreamReader(in));
}
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
public <V> V convertFrom(final ByteBuffer... buffers) {
if (buffers == null || buffers.length == 0) return null;
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers));
}
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
public <V> V convertFrom(final ConvertMask mask, final ByteBuffer... buffers) {
if (buffers == null || buffers.length == 0) return null;
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader(mask, buffers));
}
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
public <V> V convertFrom(final JsonReader reader) {
if (reader == null) return null;
return (V) new AnyDecoder(factory).convertFrom(reader);
}
//------------------------------ convertTo -----------------------------------------------------------
@Override
public String convertTo(final Object value) {

View File

@@ -158,6 +158,21 @@ public class JsonReader extends Reader {
this.position--;
}
@Override
public final ValueType readType() {
char ch = nextGoodChar();
if (ch == '{') {
backChar(ch);
return ValueType.MAP;
}
if (ch == '[') {
backChar(ch);
return ValueType.ARRAY;
}
backChar(ch);
return ValueType.STRING;
}
/**
* 判断下一个非空白字符是否为{
*

View File

@@ -319,6 +319,11 @@ public class JsonWriter extends Writer {
writeTo(false, String.valueOf(value));
}
@Override
public final void writeWrapper(StringConvertWrapper value) {
writeTo(false, String.valueOf(value));
}
@Override
public final boolean needWriteClassName() {
return false;

View File

@@ -148,6 +148,14 @@ public class Context {
executor.execute(r);
}
public int getCorePoolSize() {
return executor.getCorePoolSize();
}
public ThreadFactory getThreadFactory() {
return executor.getThreadFactory();
}
public int getBufferCapacity() {
return bufferCapacity;
}

View File

@@ -110,9 +110,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
channel.read(dst, timeout < 0 ? 0 : timeout, unit, dst, handler);
}
private <A> void nextWrite(A attachment) {
private <A> void nextWrite(Throwable exc, A attachment) {
BlockingQueue<WriteEntry> queue = this.writeQueue;
if (queue != null && exc != null && !isOpen()) {
WriteEntry entry;
while ((entry = queue.poll()) != null) {
try {
entry.writeHandler.failed(exc, entry.writeAttachment);
} catch (Throwable e) {
e.printStackTrace(System.err);
}
}
return;
}
WriteEntry entry = queue == null ? null : queue.poll();
if (entry != null) {
try {
if (entry.writeOneBuffer == null) {
@@ -312,18 +324,27 @@ public class TcpAioAsyncConnection extends AsyncConnection {
failed(e, attachment);
return;
}
nextWrite(attachment);
writeHandler.completed(writeCount, attachment);
try {
writeHandler.completed(writeCount, attachment);
} finally {
nextWrite(null, attachment);
}
} else {
nextWrite(attachment);
writeHandler.completed(result.intValue(), attachment);
try {
writeHandler.completed(result.intValue(), attachment);
} finally {
nextWrite(null, attachment);
}
}
}
@Override
public void failed(Throwable exc, A attachment) {
nextWrite(attachment);
writeHandler.failed(exc, attachment);
try {
writeHandler.failed(exc, attachment);
} finally {
nextWrite(exc, attachment);
}
}
}
@@ -350,14 +371,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
failed(e, attachment);
return;
}
nextWrite(attachment);
writeHandler.completed(result, attachment);
try {
writeHandler.completed(result, attachment);
} finally {
nextWrite(null, attachment);
}
}
@Override
public void failed(Throwable exc, A attachment) {
nextWrite(attachment);
writeHandler.failed(exc, attachment);
try {
writeHandler.failed(exc, attachment);
} finally {
nextWrite(exc, attachment);
}
}
}

View File

@@ -161,7 +161,7 @@ public class HttpResourceServlet extends HttpServlet {
}
}
public void serRoot(String rootstr) {
public void setRoot(String rootstr) {
if (rootstr == null) return;
try {
this.root = new File(rootstr).getCanonicalFile();
@@ -170,7 +170,7 @@ public class HttpResourceServlet extends HttpServlet {
}
}
public void serRoot(File file) {
public void setRoot(File file) {
if (file == null) return;
try {
this.root = file.getCanonicalFile();

View File

@@ -941,7 +941,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
}
if (request.newsessionid != null) {
String domain = defaultCookie == null ? null : defaultCookie.getDomain();
if (domain == null) {
if (domain == null || domain.isEmpty()) {
domain = "";
} else {
domain = "Domain=" + domain + "; ";
@@ -949,9 +949,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
String path = defaultCookie == null ? null : defaultCookie.getPath();
if (path == null || path.isEmpty()) path = "/";
if (request.newsessionid.isEmpty()) {
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=" + path + "; Max-Age=0; HttpOnly\r\n").getBytes());
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=/; Max-Age=0; HttpOnly\r\n").getBytes());
} else {
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=" + path + "; HttpOnly\r\n").getBytes());
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=/; HttpOnly\r\n").getBytes());
}
}
if (this.cookies != null) {

View File

@@ -375,6 +375,10 @@ public final class Rest {
pushInt(mv, rws.wsmaxbody());
mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(rws.mergemsg() ? ICONST_1 : ICONST_0);
mv.visitFieldInsn(PUTFIELD, newDynName, "mergemsg", "Z");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0);
mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z");

View File

@@ -60,6 +60,13 @@ public @interface RestWebSocket {
*/
boolean anyuser() default false;
/**
* 接收客户端的分包(last=false)消息时是否自动合并包
*
* @return 默认true
*/
boolean mergemsg() default true;
/**
* WebScoket服务器给客户端进行ping操作的间隔时间, 单位: 秒, 默认值15秒
*

View File

@@ -540,7 +540,7 @@ public abstract class WebSocket<G extends Serializable, T> {
*/
public CompletableFuture<Void> changeUserid(final G newuserid) {
if (newuserid == null) throw new NullPointerException("newuserid is null");
return _engine.changeUserid(this, newuserid);
return _engine.changeLocalUserid(this, newuserid);
}
/**

View File

@@ -76,11 +76,14 @@ public class WebSocketEngine {
@Comment("最大消息体长度, 小于1表示无限制")
protected int wsmaxbody;
@Comment("接收客户端的分包(last=false)消息时是否自动合并包")
protected boolean mergemsg = true;
@Comment("加密解密器")
protected Cryptor cryptor;
protected WebSocketEngine(String engineid, boolean single, HttpContext context, int liveinterval,
int wsmaxconns, int wsthreads, int wsmaxbody, Cryptor cryptor, WebSocketNode node, Convert sendConvert, Logger logger) {
protected WebSocketEngine(String engineid, boolean single, HttpContext context, int liveinterval, int wsmaxconns,
int wsthreads, int wsmaxbody, boolean mergemsg, Cryptor cryptor, WebSocketNode node, Convert sendConvert, Logger logger) {
this.engineid = engineid;
this.single = single;
this.context = context;
@@ -90,6 +93,7 @@ public class WebSocketEngine {
this.wsmaxconns = wsmaxconns;
this.wsthreads = wsthreads;
this.wsmaxbody = wsmaxbody;
this.mergemsg = mergemsg;
this.cryptor = cryptor;
this.logger = logger;
this.index = sequence.getAndIncrement();
@@ -127,7 +131,7 @@ public class WebSocketEngine {
}
@Comment("添加WebSocket")
void add(WebSocket socket) {
CompletableFuture<Void> addLocal(WebSocket socket) {
if (single) {
currconns.incrementAndGet();
websockets.put(socket._userid, socket);
@@ -140,11 +144,12 @@ public class WebSocketEngine {
currconns.incrementAndGet();
list.add(socket);
}
if (node != null) node.connect(socket._userid);
if (node != null) return node.connect(socket._userid);
return null;
}
@Comment("从WebSocketEngine删除指定WebSocket")
CompletableFuture<Void> removeThenClose(WebSocket socket) {
CompletableFuture<Void> removeLocalThenClose(WebSocket socket) {
Serializable userid = socket._userid;
if (single) {
currconns.decrementAndGet();
@@ -165,7 +170,7 @@ public class WebSocketEngine {
}
@Comment("更改WebSocket的userid")
CompletableFuture<Void> changeUserid(WebSocket socket, final Serializable newuserid) {
CompletableFuture<Void> changeLocalUserid(WebSocket socket, final Serializable newuserid) {
if (newuserid == null) throw new NullPointerException("newuserid is null");
final Serializable olduserid = socket._userid;
socket._userid = newuserid;
@@ -207,20 +212,20 @@ public class WebSocketEngine {
}
@Comment("给所有连接用户发送消息")
public CompletableFuture<Integer> broadcastMessage(final Object message, final boolean last) {
return broadcastMessage((Predicate) null, message, last);
public CompletableFuture<Integer> broadcastLocalMessage(final Object message, final boolean last) {
return WebSocketEngine.this.broadcastLocalMessage((Predicate) null, message, last);
}
@Comment("给指定WebSocket连接用户发送消息")
public CompletableFuture<Integer> broadcastMessage(final WebSocketRange wsrange, final Object message, final boolean last) {
public CompletableFuture<Integer> broadcastLocalMessage(final WebSocketRange wsrange, final Object message, final boolean last) {
Predicate<WebSocket> predicate = wsrange == null ? null : (ws) -> ws.predicate(wsrange);
return broadcastMessage(predicate, message, last);
return WebSocketEngine.this.broadcastLocalMessage(predicate, message, last);
}
@Comment("给指定WebSocket连接用户发送消息")
public CompletableFuture<Integer> broadcastMessage(final Predicate<WebSocket> predicate, final Object message, final boolean last) {
public CompletableFuture<Integer> broadcastLocalMessage(final Predicate<WebSocket> predicate, final Object message, final boolean last) {
if (message instanceof CompletableFuture) {
return ((CompletableFuture) message).thenCompose((json) -> broadcastMessage(predicate, json, last));
return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.broadcastLocalMessage(predicate, json, last));
}
final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null);
if (more) {
@@ -265,19 +270,19 @@ public class WebSocketEngine {
}
@Comment("给指定用户组发送消息")
public CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Stream<? extends Serializable> userids) {
public CompletableFuture<Integer> sendLocalMessage(final Object message, final boolean last, final Stream<? extends Serializable> userids) {
Object[] array = userids.toArray();
Serializable[] ss = new Serializable[array.length];
for (int i = 0; i < array.length; i++) {
ss[i] = (Serializable) array[i];
}
return sendMessage(message, last, ss);
return WebSocketEngine.this.sendLocalMessage(message, last, ss);
}
@Comment("给指定用户组发送消息")
public CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Serializable... userids) {
public CompletableFuture<Integer> sendLocalMessage(final Object message, final boolean last, final Serializable... userids) {
if (message instanceof CompletableFuture) {
return ((CompletableFuture) message).thenCompose((json) -> sendMessage(json, last, userids));
return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.sendLocalMessage(json, last, userids));
}
final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null) && userids.length > 1;
if (more) {
@@ -326,7 +331,7 @@ public class WebSocketEngine {
}
@Comment("给指定WebSocket连接用户发起操作指令")
public CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
public CompletableFuture<Integer> broadcastLocalAction(final WebSocketAction action) {
CompletableFuture<Integer> future = null;
if (single) {
for (WebSocket websocket : websockets.values()) {
@@ -343,17 +348,17 @@ public class WebSocketEngine {
}
@Comment("给指定用户组发送操作")
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Stream<? extends Serializable> userids) {
public CompletableFuture<Integer> sendLocalAction(final WebSocketAction action, final Stream<? extends Serializable> userids) {
Object[] array = userids.toArray();
Serializable[] ss = new Serializable[array.length];
for (int i = 0; i < array.length; i++) {
ss[i] = (Serializable) array[i];
}
return sendAction(action, ss);
return WebSocketEngine.this.sendLocalAction(action, ss);
}
@Comment("给指定用户组发送操作")
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
public CompletableFuture<Integer> sendLocalAction(final WebSocketAction action, final Serializable... userids) {
CompletableFuture<Integer> future = null;
if (single) {
for (Serializable userid : userids) {

View File

@@ -59,7 +59,11 @@ public abstract class WebSocketNode {
protected Semaphore semaphore;
private int tryAcquireSeconds = 12;
public void init(AnyValue conf) {
this.tryAcquireSeconds = Integer.getInteger("WebSocketNode.tryAcquireSeconds", 12);
if (sncpNodeAddresses != null && "memory".equals(sncpNodeAddresses.getType())) {
sncpNodeAddresses.initValueType(InetSocketAddress.class);
}
@@ -79,7 +83,7 @@ public abstract class WebSocketNode {
}
@Local
public final void postDestroy(AnyValue conf) {
protected void postDestroy(AnyValue conf) {
if (this.localEngine == null) return;
//关掉所有本地本地WebSocket
this.localEngine.getLocalWebSockets().forEach(g -> g.close());
@@ -90,11 +94,11 @@ public abstract class WebSocketNode {
protected abstract CompletableFuture<List<String>> getWebSocketAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable userid);
protected abstract CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable userid);
protected abstract CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids);
protected abstract CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketRange wsrange, Object message, boolean last);
protected abstract CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action, Serializable userid);
protected abstract CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action, Serializable... userids);
protected abstract CompletableFuture<Integer> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action);
@@ -204,25 +208,6 @@ public abstract class WebSocketNode {
return rs;
}
/**
* @deprecated
*
* 判断指定用户是否WebSocket在线
*
* @param userid Serializable
*
* @return boolean
*/
private CompletableFuture<Boolean> existsWebSocket2(final Serializable userid) {
if (this.localEngine != null && this.sncpNodeAddresses == null) {
return CompletableFuture.completedFuture(this.localEngine.existsLocalWebSocket(userid));
}
tryAcquireSemaphore();
CompletableFuture<Boolean> rs = this.sncpNodeAddresses.existsAsync(SOURCE_SNCP_USERID_PREFIX + userid);
if (semaphore != null) rs.whenComplete((r, e) -> releaseSemaphore());
return rs;
}
/**
* 判断指定用户是否WebSocket在线
*
@@ -429,15 +414,97 @@ public abstract class WebSocketNode {
if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, userids));
final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last));
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
return this.localEngine.sendMessage(message, last, userids);
return this.localEngine.sendLocalMessage(message, last, userids);
}
final Object remoteMessage = formatRemoteMessage(message);
CompletableFuture<Integer> future = null;
for (Serializable userid : userids) {
future = future == null ? sendOneMessage(remoteMessage, last, userid)
: future.thenCombine(sendOneMessage(remoteMessage, last, userid), (a, b) -> a | b);
CompletableFuture<Integer> rsfuture;
if (userids.length == 1) {
rsfuture = sendOneUserMessage(remoteMessage, last, userids[0]);
} else {
String[] keys = new String[userids.length];
final Map<String, Serializable> keyuser = new HashMap<>();
for (int i = 0; i < userids.length; i++) {
keys[i] = SOURCE_SNCP_USERID_PREFIX + userids[i];
keyuser.put(keys[i], userids[i]);
}
tryAcquireSemaphore();
CompletableFuture<Map<String, Collection<InetSocketAddress>>> addrsFuture = sncpNodeAddresses.getCollectionMapAsync(InetSocketAddress.class, keys);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
rsfuture = addrsFuture.thenCompose((Map<String, Collection<InetSocketAddress>> addrs) -> {
if (addrs == null || addrs.isEmpty()) {
if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node ");
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
}
Map<InetSocketAddress, List<Serializable>> addrUsers = new HashMap<>();
addrs.forEach((key, as) -> {
for (InetSocketAddress a : as) {
addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key));
}
});
if (logger.isLoggable(Level.FINEST)) {
logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found message-addr-userids: " + addrUsers);
}
CompletableFuture<Integer> future = null;
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
Serializable[] us = en.getValue().toArray(new Serializable[en.getValue().size()]);
future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, us)
: future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, us), (a, b) -> a | b);
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
});
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
}
protected CompletableFuture<Integer> sendOneUserMessage(final Object message, final boolean last, final Serializable userid) {
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid));
if (logger.isLoggable(Level.FINEST)) {
logger.finest("websocket want send message {userid:" + userid + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
}
CompletableFuture<Integer> localFuture = null;
if (this.localEngine != null) localFuture = localEngine.sendLocalMessage(message, last, userid);
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
//没有CacheSource就不会有分布式节点
return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture;
}
//远程节点发送消息
final Object remoteMessage = formatRemoteMessage(message);
tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
if (addrs == null || addrs.isEmpty()) {
if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node ");
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
}
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + localSncpAddress + ") found userid:" + userid + " on " + addrs);
CompletableFuture<Integer> future = null;
for (InetSocketAddress addr : addrs) {
if (addr == null || addr.equals(localSncpAddress)) continue;
future = future == null ? remoteNode.sendMessage(addr, remoteMessage, last, userid)
: future.thenCombine(remoteNode.sendMessage(addr, remoteMessage, last, userid), (a, b) -> a | b);
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
});
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
protected CompletableFuture<Integer> sendOneAddrMessage(final InetSocketAddress sncpAddr, final Object message, final boolean last, final Serializable... userids) {
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(sncpAddr, msg, last, userids));
if (logger.isLoggable(Level.FINEST)) {
logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
}
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids);
}
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
//没有CacheSource就不会有分布式节点
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
}
final Object remoteMessage = formatRemoteMessage(message);
return remoteNode.sendMessage(sncpAddr, remoteMessage, last, userids);
}
/**
@@ -548,10 +615,10 @@ public abstract class WebSocketNode {
if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> broadcastMessage(wsrange, convert, msg, last));
final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last));
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
return this.localEngine.broadcastMessage(wsrange, message, last);
return this.localEngine.broadcastLocalMessage(wsrange, message, last);
}
final Object remoteMessage = formatRemoteMessage(message);
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastMessage(wsrange, message, last);
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalMessage(wsrange, message, last);
tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
@@ -569,40 +636,6 @@ public abstract class WebSocketNode {
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
protected CompletableFuture<Integer> sendOneMessage(final Object message, final boolean last, final Serializable userid) {
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneMessage(msg, last, userid));
if (logger.isLoggable(Level.FINEST)) {
logger.finest("websocket want send message {userid:" + userid + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
}
CompletableFuture<Integer> localFuture = null;
if (this.localEngine != null) localFuture = localEngine.sendMessage(message, last, userid);
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
//没有CacheSource就不会有分布式节点
return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture;
}
//远程节点发送消息
final Object remoteMessage = formatRemoteMessage(message);
tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
if (addrs == null || addrs.isEmpty()) {
if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node ");
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
}
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + localSncpAddress + ") found userid:" + userid + " on " + addrs);
CompletableFuture<Integer> future = null;
for (InetSocketAddress addr : addrs) {
if (addr == null || addr.equals(localSncpAddress)) continue;
future = future == null ? remoteNode.sendMessage(addr, remoteMessage, last, userid)
: future.thenCombine(remoteNode.sendMessage(addr, remoteMessage, last, userid), (a, b) -> a | b);
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
});
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
/**
* 广播操作, 给所有人发操作
*
@@ -613,9 +646,9 @@ public abstract class WebSocketNode {
@Local
public CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
return this.localEngine.broadcastAction(action);
return this.localEngine.broadcastLocalAction(action);
}
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastAction(action);
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalAction(action);
tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
@@ -646,21 +679,53 @@ public abstract class WebSocketNode {
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
return this.localEngine.sendAction(action, userids);
return this.localEngine.sendLocalAction(action, userids);
}
CompletableFuture<Integer> future = null;
for (Serializable userid : userids) {
future = future == null ? sendOneAction(action, userid) : future.thenCombine(sendOneAction(action, userid), (a, b) -> a | b);
CompletableFuture<Integer> rsfuture;
if (userids.length == 1) {
rsfuture = sendOneUserAction(action, userids[0]);
} else {
String[] keys = new String[userids.length];
final Map<String, Serializable> keyuser = new HashMap<>();
for (int i = 0; i < userids.length; i++) {
keys[i] = SOURCE_SNCP_USERID_PREFIX + userids[i];
keyuser.put(keys[i], userids[i]);
}
tryAcquireSemaphore();
CompletableFuture<Map<String, Collection<InetSocketAddress>>> addrsFuture = sncpNodeAddresses.getCollectionMapAsync(InetSocketAddress.class, keys);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
rsfuture = addrsFuture.thenCompose((Map<String, Collection<InetSocketAddress>> addrs) -> {
if (addrs == null || addrs.isEmpty()) {
if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node ");
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
}
Map<InetSocketAddress, List<Serializable>> addrUsers = new HashMap<>();
addrs.forEach((key, as) -> {
for (InetSocketAddress a : as) {
addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key));
}
});
if (logger.isLoggable(Level.FINEST)) {
logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found action-userid-addrs: " + addrUsers);
}
CompletableFuture<Integer> future = null;
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
Serializable[] us = en.getValue().toArray(new Serializable[en.getValue().size()]);
future = future == null ? sendOneAddrAction(en.getKey(), action, us)
: future.thenCombine(sendOneAddrAction(en.getKey(), action, us), (a, b) -> a | b);
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
});
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
}
protected CompletableFuture<Integer> sendOneAction(final WebSocketAction action, final Serializable userid) {
protected CompletableFuture<Integer> sendOneUserAction(final WebSocketAction action, final Serializable userid) {
if (logger.isLoggable(Level.FINEST)) {
logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
}
CompletableFuture<Integer> localFuture = null;
if (this.localEngine != null) localFuture = localEngine.sendAction(action, userid);
if (this.localEngine != null) localFuture = localEngine.sendLocalAction(action, userid);
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
//没有CacheSource就不会有分布式节点
@@ -687,6 +752,21 @@ public abstract class WebSocketNode {
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
protected CompletableFuture<Integer> sendOneAddrAction(final InetSocketAddress sncpAddr, final WebSocketAction action, final Serializable... userids) {
if (logger.isLoggable(Level.FINEST)) {
logger.finest("websocket want send action {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", action:" + action + " from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
}
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalAction(action, userids);
}
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
//没有CacheSource就不会有分布式节点
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
}
return remoteNode.sendAction(sncpAddr, action, userids);
}
protected Object formatRemoteMessage(Object message) {
if (message instanceof WebSocketPacket) return message;
if (message instanceof byte[]) return message;
@@ -699,7 +779,7 @@ public abstract class WebSocketNode {
protected boolean tryAcquireSemaphore() {
if (this.semaphore == null) return true;
try {
return this.semaphore.tryAcquire(6, TimeUnit.SECONDS);
return this.semaphore.tryAcquire(tryAcquireSeconds, TimeUnit.SECONDS);
} catch (Exception e) {
return false;
}

View File

@@ -14,6 +14,7 @@ import java.util.function.*;
import java.util.logging.*;
import org.redkale.convert.*;
import org.redkale.net.Cryptor;
import org.redkale.util.*;
/**
*
@@ -24,6 +25,8 @@ import org.redkale.net.Cryptor;
*/
public final class WebSocketPacket {
public static final Object MESSAGE_NIL = new Object();
static final WebSocketPacket NONE = new WebSocketPacket();
public static final WebSocketPacket DEFAULT_PING_PACKET = new WebSocketPacket(FrameType.PING, new byte[0]);
@@ -34,7 +37,7 @@ public final class WebSocketPacket {
public static enum FrameType {
TEXT(0x01), BINARY(0x02), CLOSE(0x08), PING(0x09), PONG(0x0A);
SERIES(0x00), TEXT(0x01), BINARY(0x02), CLOSE(0x08), PING(0x09), PONG(0x0A);
private final int value;
@@ -48,6 +51,7 @@ public final class WebSocketPacket {
public static FrameType valueOf(int v) {
switch (v) {
case 0x00: return SERIES;
case 0x01: return TEXT;
case 0x02: return BINARY;
case 0x08: return CLOSE;
@@ -344,11 +348,19 @@ public final class WebSocketPacket {
*
* @return boolean 已接收完返回true 需要继续接收body返回false
*/
boolean receiveBody(WebSocket webSocket, ByteBuffer readBuffer) {
boolean receiveBody(final Logger logger, WebSocketRunner runner, WebSocket webSocket, ByteBuffer readBuffer) {
final boolean debug = false; //调试开关
int need = receiveLength - receiveCount;
boolean over = readBuffer.remaining() >= need;
final int remain = readBuffer.remaining();
boolean over = remain >= need;
this.receiveBuffers = Utility.append(this.receiveBuffers, readBuffer);
if (over) parseReceiveMessage(webSocket, this.receiveBuffers);
if (debug) logger.finest("receiveBody: receiveLength=" + receiveLength + ", this.receiveCount=" + this.receiveCount + ", readBuffer=" + remain);
if (over) {
this.receiveCount = this.receiveLength;
parseReceiveMessage(logger, runner, webSocket, this.receiveBuffers);
} else {
this.receiveCount += remain;
}
return over;
}
@@ -379,7 +391,7 @@ public final class WebSocketPacket {
*
* @return 返回NONE表示Buffer内容不够 返回this表示解析完成或部分解析完成返回null表示解析异常
*/
WebSocketPacket decode(final Logger logger, final WebSocket webSocket, final int wsmaxbody,
WebSocketPacket decode(final Logger logger, final WebSocketRunner runner, final WebSocket webSocket, final int wsmaxbody,
final AbstractMap.SimpleEntry<String, byte[]> halfBytes, final ByteBuffer buffer) {
//开始
final boolean debug = false; //调试开关
@@ -394,9 +406,13 @@ public final class WebSocketPacket {
final byte opcode = buffer.get(); //第一个字节
this.last = (opcode & 0b1000_0000) != 0;
this.type = FrameType.valueOf(opcode & 0xF);
if (type == FrameType.CLOSE) {
if (debug) logger.log(Level.FINEST, " receive close command from websocket client");
}
if (type == null) {
logger.log(Level.SEVERE, " receive unknown frametype(opcode=" + (opcode & 0xF) + ") from websocket client");
}
final boolean checkrsv = false;//暂时不校验
if (checkrsv && (opcode & 0b0111_0000) != 0) {
if (debug) logger.log(Level.FINE, "rsv1 rsv2 rsv3 must be 0, but not (" + opcode + ")");
@@ -438,15 +454,18 @@ public final class WebSocketPacket {
}
if (lengthCode == 0x7E) {//0x7E=126
length = (int) buffer.getChar();
} else if (lengthCode == 0x7F) {//0x7E=127
length = (int) buffer.getLong();
} else {
length = buffer.getInt();
}
}
if (length > wsmaxbody && wsmaxbody > 0) {
if (debug) logger.log(Level.FINE, "message length (" + length + ") too big, must less " + wsmaxbody + "");
logger.log(Level.WARNING, "message length (" + length + ") too big, must less " + wsmaxbody + "");
return null;
}
this.receiveLength = length;
if (debug) logger.finest("this.receiveLength: " + length + ", code=" + lengthCode + ", last=" + last);
if (masked) {
final byte[] masks = new byte[4];
buffer.get(masks);
@@ -461,7 +480,7 @@ public final class WebSocketPacket {
};
}
if (buffer.remaining() >= this.receiveLength) { //内容足够, 可以解析
this.parseReceiveMessage(webSocket, buffer);
this.parseReceiveMessage(logger, runner, webSocket, buffer);
this.receiveCount = this.receiveLength;
} else {
this.receiveCount = buffer.remaining();
@@ -470,38 +489,77 @@ public final class WebSocketPacket {
return this;
}
void parseReceiveMessage(WebSocket webSocket, ByteBuffer... buffers) {
void parseReceiveMessage(final Logger logger, WebSocketRunner runner, WebSocket webSocket, ByteBuffer... buffers) {
if (webSocket._engine.cryptor != null) {
HttpContext context = webSocket._engine.context;
buffers = webSocket._engine.cryptor.decrypt(buffers, context.getBufferSupplier(), context.getBufferConsumer());
}
if (this.type == FrameType.TEXT) {
FrameType selfType = this.type;
final boolean series = selfType == FrameType.SERIES;
if (series) {
selfType = runner.currSeriesMergeFrameType;
this.type = selfType;
} else if (!this.last && (selfType == FrameType.TEXT || selfType == FrameType.BINARY)) {
runner.currSeriesMergeFrameType = selfType;
}
if (selfType == FrameType.TEXT) {
Convert textConvert = webSocket.getTextConvert();
if (textConvert == null) {
if (textConvert == null || (!runner.mergemsg && (series || !this.last))) {
this.receiveMessage = new String(this.getReceiveBytes(buffers), StandardCharsets.UTF_8);
this.receiveType = MessageType.STRING;
} else {
this.receiveMessage = textConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
if (this.last || !runner.mergemsg) {
if (runner.currSeriesMergeMessage == null) {
this.receiveMessage = textConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
} else {
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
try {
this.receiveMessage = textConvert.convertFrom(webSocket._messageTextType, runner.currSeriesMergeMessage.getBytes());
} finally {
runner.currSeriesMergeMessage = null;
}
}
} else {
if (runner.currSeriesMergeMessage == null) runner.currSeriesMergeMessage = new ByteArray();
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
this.receiveMessage = MESSAGE_NIL;
}
this.receiveCount = this.receiveLength;
this.receiveType = MessageType.OBJECT;
}
} else if (this.type == FrameType.BINARY) {
} else if (selfType == FrameType.BINARY) {
Convert binaryConvert = webSocket.getBinaryConvert();
if (binaryConvert == null) {
if (binaryConvert == null || (!runner.mergemsg && (series || !this.last))) {
this.receiveMessage = this.getReceiveBytes(buffers);
this.receiveType = MessageType.BYTES;
} else {
this.receiveMessage = binaryConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
if (this.last || !runner.mergemsg) {
if (runner.currSeriesMergeMessage == null) {
this.receiveMessage = binaryConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
} else {
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
try {
this.receiveMessage = binaryConvert.convertFrom(webSocket._messageTextType, runner.currSeriesMergeMessage.getBytes());
} finally {
runner.currSeriesMergeMessage = null;
}
}
} else {
if (runner.currSeriesMergeMessage == null) runner.currSeriesMergeMessage = new ByteArray();
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
this.receiveMessage = MESSAGE_NIL;
}
this.receiveCount = this.receiveLength;
this.receiveType = MessageType.OBJECT;
}
} else if (this.type == FrameType.PING) {
} else if (selfType == FrameType.PING) {
this.receiveMessage = this.getReceiveBytes(buffers);
this.receiveType = MessageType.BYTES;
} else if (this.type == FrameType.PONG) {
} else if (selfType == FrameType.PONG) {
this.receiveMessage = this.getReceiveBytes(buffers);
this.receiveType = MessageType.BYTES;
} else if (this.type == FrameType.CLOSE) {
} else if (selfType == FrameType.CLOSE) {
this.receiveMessage = this.getReceiveBytes(buffers);
this.receiveType = MessageType.BYTES;
}

View File

@@ -15,6 +15,7 @@ import java.util.AbstractMap.SimpleEntry;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.logging.*;
import org.redkale.util.ByteArray;
/**
* WebSocket的消息接收发送器, 一个WebSocket对应一个WebSocketRunner
@@ -34,8 +35,14 @@ class WebSocketRunner implements Runnable {
protected final HttpContext context;
protected final boolean mergemsg;
volatile boolean closed = false;
FrameType currSeriesMergeFrameType;
ByteArray currSeriesMergeMessage;
private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用
protected long lastSendTime;
@@ -46,6 +53,7 @@ class WebSocketRunner implements Runnable {
this.context = context;
this.engine = webSocket._engine;
this.webSocket = webSocket;
this.mergemsg = webSocket._engine.mergemsg;
this.restMessageConsumer = messageConsumer;
this.channel = channel;
}
@@ -53,6 +61,7 @@ class WebSocketRunner implements Runnable {
@Override
public void run() {
final boolean debug = context.getLogger().isLoggable(Level.FINEST);
final WebSocketRunner self = this;
try {
webSocket.onConnected();
channel.setReadTimeoutSeconds(300); //读取超时5分钟
@@ -81,7 +90,7 @@ class WebSocketRunner implements Runnable {
WebSocketPacket onePacket = null;
if (unfinishPacket != null) {
if (unfinishPacket.receiveBody(webSocket, readBuffer)) { //已经接收完毕
if (unfinishPacket.receiveBody(context.getLogger(), self, webSocket, readBuffer)) { //已经接收完毕
onePacket = unfinishPacket;
unfinishPacket = null;
for (ByteBuffer b : exBuffers) {
@@ -98,7 +107,7 @@ class WebSocketRunner implements Runnable {
if (onePacket != null) packets.add(onePacket);
try {
while (true) {
WebSocketPacket packet = new WebSocketPacket().decode(context.getLogger(), webSocket, wsmaxbody, halfBytes, readBuffer);
WebSocketPacket packet = new WebSocketPacket().decode(context.getLogger(), self, webSocket, wsmaxbody, halfBytes, readBuffer);
if (packet == WebSocketPacket.NONE) break; //解析完毕但是buffer有多余字节
if (packet != null && !packet.isReceiveFinished()) {
unfinishPacket = packet;
@@ -115,7 +124,11 @@ class WebSocketRunner implements Runnable {
webSocket.onOccurException(e, null);
}
//继续监听消息
readBuffer.clear();
if (readBuffer.hasRemaining()) { //exBuffers缓存了
readBuffer = context.pollBuffer();
} else {
readBuffer.clear();
}
if (halfBytes.getValue() != null) {
readBuffer.put(halfBytes.getValue());
halfBytes.setValue(null);
@@ -130,6 +143,7 @@ class WebSocketRunner implements Runnable {
failed(null, readBuffer);
return;
}
if (packet.receiveMessage == WebSocketPacket.MESSAGE_NIL) continue; //last=false && mergemsg=true 的粘包
if (packet.type == FrameType.TEXT) {
try {
@@ -269,8 +283,8 @@ class WebSocketRunner implements Runnable {
public void failed(Throwable exc, ByteBuffer[] attachments) {
future.complete(RETCODE_SENDEXCEPTION);
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on CompletionHandler");
if (exc != null) {
context.getLogger().log(Level.FINE, "WebSocket sendMessage on CompletionHandler failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
if (exc != null && context.getLogger().isLoggable(Level.FINER)) {
context.getLogger().log(Level.FINER, "WebSocket sendMessage on CompletionHandler failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
}
}
@@ -278,7 +292,9 @@ class WebSocketRunner implements Runnable {
} catch (Exception t) {
futureResult.complete(RETCODE_SENDEXCEPTION);
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on channel.write");
context.getLogger().log(Level.FINE, "WebSocket sendMessage abort, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", t);
if (t != null && context.getLogger().isLoggable(Level.FINER)) {
context.getLogger().log(Level.FINER, "WebSocket sendMessage abort, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", t);
}
}
return futureResult;
@@ -293,24 +309,11 @@ class WebSocketRunner implements Runnable {
synchronized (this) {
if (closed) return null;
closed = true;
CompletableFuture<Void> future = engine.removeLocalThenClose(webSocket);
channel.dispose();
CompletableFuture<Void> future = engine.removeThenClose(webSocket);
webSocket.onClose(code, reason);
return future;
}
}
private static final class QueueEntry {
public final CompletableFuture<Integer> future;
public final WebSocketPacket packet;
public QueueEntry(CompletableFuture<Integer> future, WebSocketPacket packet) {
this.future = future;
this.packet = packet;
}
}
}

View File

@@ -56,6 +56,9 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
@Comment("最大消息体长度, 小于1表示无限制")
public static final String WEBPARAM__WSMAXBODY = "wsmaxbody";
@Comment("接收客户端的分包(last=false)消息时是否自动合并包")
public static final String WEBPARAM__WSMERGEMSG = "wsmergemsg";
@Comment("加密解密器")
public static final String WEBPARAM__CRYPTOR = "cryptor";
@@ -88,6 +91,9 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
//同RestWebSocket.anyuser
protected boolean anyuser = false;
//同RestWebSocket.mergemsg
protected boolean mergemsg = true;
//同RestWebSocket.cryptor, 变量名不可改, 被Rest.createRestWebSocketServlet用到
protected Cryptor cryptor;
@@ -157,7 +163,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
}
//存在WebSocketServlet则此WebSocketNode必须是本地模式Service
this.node.localEngine = new WebSocketEngine("WebSocketEngine-" + addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]",
this.single, context, liveinterval, wsmaxconns, wsthreads, wsmaxbody, this.cryptor, this.node, this.sendConvert, logger);
this.single, context, liveinterval, wsmaxconns, wsthreads, wsmaxbody, mergemsg, this.cryptor, this.node, this.sendConvert, logger);
this.node.init(conf);
this.node.localEngine.init(conf);
@@ -255,7 +261,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
CompletableFuture<Boolean> rcFuture = webSocket.onSingleRepeatConnect();
Consumer<Boolean> task = (oldkilled) -> {
if (oldkilled) {
WebSocketServlet.this.node.localEngine.add(webSocket);
WebSocketServlet.this.node.localEngine.addLocal(webSocket);
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
webSocket._runner = runner;
context.runAsync(runner);
@@ -276,7 +282,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
});
}
} else {
WebSocketServlet.this.node.localEngine.add(webSocket);
WebSocketServlet.this.node.localEngine.addLocal(webSocket);
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
webSocket._runner = runner;
context.runAsync(runner);
@@ -284,7 +290,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
}
});
} else {
WebSocketServlet.this.node.localEngine.add(webSocket);
WebSocketServlet.this.node.localEngine.addLocal(webSocket);
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
webSocket._runner = runner;
context.runAsync(runner);

View File

@@ -54,8 +54,12 @@ public class RetResult<T> {
this.result = result;
}
public static RetResult success() {
return new RetResult();
public static <T> RetResult<T> success() {
return new RetResult<>();
}
public static <V, T> RetResult<T> success(V result) {
return new RetResult().result(result);
}
public static <T> CompletableFuture<RetResult<T>> successFuture() {
@@ -203,6 +207,18 @@ public class RetResult<T> {
return attach;
}
/**
* 获取附件元素值
*
* @param name 元素名
* @param defValue 默认值
*
* @return 结果值
*/
public String getAttach(String name, String defValue) {
return attach == null ? defValue : attach.getOrDefault(name, defValue);
}
/**
* 设置结果附件
*

View File

@@ -56,27 +56,27 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
}
@Override
public CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable userid) {
public CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids) {
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
return this.localEngine.sendMessage(message, last, userid);
return this.localEngine.sendLocalMessage(message, last, userids);
}
@Override
public CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketRange wsrange, Object message, boolean last) {
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
return this.localEngine.broadcastMessage(wsrange, message, last);
return this.localEngine.broadcastLocalMessage(wsrange, message, last);
}
@Override
public CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action, Serializable userid) {
public CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action, Serializable... userids) {
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
return this.localEngine.sendAction(action, userid);
return this.localEngine.sendLocalAction(action, userids);
}
@Override
public CompletableFuture<Integer> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action) {
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
return this.localEngine.broadcastAction(action);
return this.localEngine.broadcastLocalAction(action);
}
/**

View File

@@ -200,62 +200,61 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
}
}
/**
* public static void main(String[] args) throws Exception {
* AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue();
* conf.addValue("node", new AnyValue.DefaultAnyValue().addValue("addr", "127.0.0.1").addValue("port", "6379"));
*
* CacheMemorySource source = new CacheMemorySource();
* source.defaultConvert = JsonFactory.root().getConvert();
* source.initValueType(String.class); //value用String类型
* source.initTransient(false);
* source.init(conf);
*
* System.out.println("------------------------------------");
* source.remove("key1");
* source.remove("key2");
* source.remove("300");
* source.set("key1", "value1");
* source.setString("keystr1", "strvalue1");
* source.setLong("keylong1", 333L);
* source.set("300", "4000");
* source.getAndRefresh("key1", 3500);
* System.out.println("[有值] 300 GET : " + source.get("300"));
* System.out.println("[有值] key1 GET : " + source.get("key1"));
* System.out.println("[无值] key2 GET : " + source.get("key2"));
* System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
* System.out.println("[有值] key1 EXISTS : " + source.exists("key1"));
* System.out.println("[无值] key2 EXISTS : " + source.exists("key2"));
*
* source.remove("keys3");
* source.appendListItem("keys3", "vals1");
* source.appendListItem("keys3", "vals2");
* System.out.println("-------- keys3 追加了两个值 --------");
* System.out.println("[两值] keys3 VALUES : " + source.getCollection("keys3"));
* System.out.println("[有值] keys3 EXISTS : " + source.exists("keys3"));
* source.removeListItem("keys3", "vals1");
* System.out.println("[一值] keys3 VALUES : " + source.getCollection("keys3"));
* source.getCollectionAndRefresh("keys3", 3000);
*
* source.remove("sets3");
* source.appendSetItem("sets3", "setvals1");
* source.appendSetItem("sets3", "setvals2");
* source.appendSetItem("sets3", "setvals1");
* System.out.println("[两值] sets3 VALUES : " + source.getCollection("sets3"));
* System.out.println("[有值] sets3 EXISTS : " + source.exists("sets3"));
* source.removeSetItem("sets3", "setvals1");
* System.out.println("[一值] sets3 VALUES : " + source.getCollection("sets3"));
* System.out.println("sets3 大小 : " + source.getCollectionSize("sets3"));
* System.out.println("all keys: " + source.queryKeys());
* System.out.println("newnum 值 : " + source.incr("newnum"));
* System.out.println("newnum 值 : " + source.decr("newnum"));
* System.out.println("------------------------------------");
* source.destroy(null);
* source.init(null);
* System.out.println("all keys: " + source.queryKeys());
* System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
* }
*/
public static void main(String[] args) throws Exception {
AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue();
conf.addValue("node", new AnyValue.DefaultAnyValue().addValue("addr", "127.0.0.1").addValue("port", "6379"));
CacheMemorySource source = new CacheMemorySource();
source.defaultConvert = JsonFactory.root().getConvert();
source.initValueType(String.class); //value用String类型
source.initTransient(false);
source.init(conf);
System.out.println("------------------------------------");
source.remove("key1");
source.remove("key2");
source.remove("300");
source.set("key1", "value1");
source.setString("keystr1", "strvalue1");
source.setLong("keylong1", 333L);
source.set("300", "4000");
source.getAndRefresh("key1", 3500);
System.out.println("[有值] 300 GET : " + source.get("300"));
System.out.println("[有值] key1 GET : " + source.get("key1"));
System.out.println("[无值] key2 GET : " + source.get("key2"));
System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
System.out.println("[有值] key1 EXISTS : " + source.exists("key1"));
System.out.println("[无值] key2 EXISTS : " + source.exists("key2"));
source.remove("keys3");
source.appendListItem("keys3", "vals1");
source.appendListItem("keys3", "vals2");
System.out.println("-------- keys3 追加了两个值 --------");
System.out.println("[两值] keys3 VALUES : " + source.getCollection("keys3"));
System.out.println("[有值] keys3 EXISTS : " + source.exists("keys3"));
source.removeListItem("keys3", "vals1");
System.out.println("[一值] keys3 VALUES : " + source.getCollection("keys3"));
source.getCollectionAndRefresh("keys3", 3000);
source.remove("sets3");
source.appendSetItem("sets3", "setvals1");
source.appendSetItem("sets3", "setvals2");
source.appendSetItem("sets3", "setvals1");
System.out.println("[两值] sets3 VALUES : " + source.getCollection("sets3"));
System.out.println("[有值] sets3 EXISTS : " + source.exists("sets3"));
source.removeSetItem("sets3", "setvals1");
System.out.println("[一值] sets3 VALUES : " + source.getCollection("sets3"));
System.out.println("sets3 大小 : " + source.getCollectionSize("sets3"));
System.out.println("all keys: " + source.queryKeys());
System.out.println("newnum 值 : " + source.incr("newnum"));
System.out.println("newnum 值 : " + source.decr("newnum"));
System.out.println("------------------------------------");
source.destroy(null);
source.init(null);
System.out.println("all keys: " + source.queryKeys());
System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
}
@Override
public void close() throws Exception { //给Application 关闭时调用
destroy(null);
@@ -677,16 +676,46 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return (Collection<T>) get(key);
}
@Override
public <T> Map<String, Collection<T>> getCollectionMap(final Type componentType, final String... keys) {
Map<String, Collection<T>> map = new HashMap<>();
for (String key : keys) {
Collection<T> s = (Collection<T>) get(key);
if (s != null) map.put(key, s);
}
return map;
}
@Override
public Collection<String> getStringCollection(final String key) {
return (Collection<String>) get(key);
}
@Override
public Map<String, Collection<String>> getStringCollectionMap(final String... keys) {
Map<String, Collection<String>> map = new HashMap<>();
for (String key : keys) {
Collection<String> s = (Collection<String>) get(key);
if (s != null) map.put(key, s);
}
return map;
}
@Override
public Collection<Long> getLongCollection(final String key) {
return (Collection<Long>) get(key);
}
@Override
public Map<String, Collection<Long>> getLongCollectionMap(final String... keys) {
Map<String, Collection<Long>> map = new HashMap<>();
for (String key : keys) {
Collection<Long> s = (Collection<Long>) get(key);
if (s != null) map.put(key, s);
}
return map;
}
@Override
public CompletableFuture<Collection<V>> getCollectionAsync(final String key) {
return CompletableFuture.supplyAsync(() -> getCollection(key), getExecutor());
@@ -697,16 +726,31 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.supplyAsync(() -> getCollection(key, componentType), getExecutor());
}
@Override
public CompletableFuture<Map<String, Collection<V>>> getCollectionMapAsync(final Type componentType, final String... keys) {
return CompletableFuture.supplyAsync(() -> getCollectionMap(componentType, keys), getExecutor());
}
@Override
public CompletableFuture<Collection<String>> getStringCollectionAsync(final String key) {
return CompletableFuture.supplyAsync(() -> getStringCollection(key), getExecutor());
}
@Override
public CompletableFuture<Map<String, Collection<String>>> getStringCollectionMapAsync(final String... keys) {
return CompletableFuture.supplyAsync(() -> getStringCollectionMap(keys), getExecutor());
}
@Override
public CompletableFuture<Collection<Long>> getLongCollectionAsync(final String key) {
return CompletableFuture.supplyAsync(() -> getLongCollection(key), getExecutor());
}
@Override
public CompletableFuture<Map<String, Collection<Long>>> getLongCollectionMapAsync(final String... keys) {
return CompletableFuture.supplyAsync(() -> getLongCollectionMap(keys), getExecutor());
}
@Override
public int getCollectionSize(final String key) {
Collection<V> collection = (Collection<V>) get(key);

View File

@@ -92,6 +92,8 @@ public interface CacheSource<V extends Object> {
public <T> Collection<T> getCollection(final String key, final Type componentType);
public <T> Map<String, Collection<T>> getCollectionMap(final Type componentType, final String... keys);
public int getCollectionSize(final String key);
public Collection<V> getCollectionAndRefresh(final String key, final int expireSeconds);
@@ -138,6 +140,8 @@ public interface CacheSource<V extends Object> {
public Collection<String> getStringCollection(final String key);
public Map<String, Collection<String>> getStringCollectionMap(final String... keys);
public Collection<String> getStringCollectionAndRefresh(final String key, final int expireSeconds);
public void appendStringListItem(final String key, final String value);
@@ -160,6 +164,8 @@ public interface CacheSource<V extends Object> {
public Collection<Long> getLongCollection(final String key);
public Map<String, Collection<Long>> getLongCollectionMap(final String... keys);
public Collection<Long> getLongCollectionAndRefresh(final String key, final int expireSeconds);
public void appendLongListItem(final String key, final long value);
@@ -235,6 +241,8 @@ public interface CacheSource<V extends Object> {
public <T> CompletableFuture<Collection<T>> getCollectionAsync(final String key, final Type componentType);
public <T> CompletableFuture<Map<String, Collection<T>>> getCollectionMapAsync(final Type componentType, final String... keys);
public CompletableFuture<Integer> getCollectionSizeAsync(final String key);
public CompletableFuture<Collection<V>> getCollectionAndRefreshAsync(final String key, final int expireSeconds);
@@ -281,6 +289,8 @@ public interface CacheSource<V extends Object> {
public CompletableFuture<Collection<String>> getStringCollectionAsync(final String key);
public CompletableFuture<Map<String, Collection<String>>> getStringCollectionMapAsync(final String... keys);
public CompletableFuture<Collection<String>> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds);
public CompletableFuture<Void> appendStringListItemAsync(final String key, final String value);
@@ -303,6 +313,8 @@ public interface CacheSource<V extends Object> {
public CompletableFuture<Collection<Long>> getLongCollectionAsync(final String key);
public CompletableFuture<Map<String, Collection<Long>>> getLongCollectionMapAsync(final String... keys);
public CompletableFuture<Collection<Long>> getLongCollectionAndRefreshAsync(final String key, final int expireSeconds);
public CompletableFuture<Void> appendLongListItemAsync(final String key, final long value);

View File

@@ -0,0 +1,30 @@
/*
* 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 static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* 加密字段标记 <br>
* 注意: 加密字段不能用于 LIKE 等过滤查询 <br>
* 如果有对加密字段进行过滤查询的需求就要保证加密算法也能兼容LIKE"abc"的加密字符串也是"abcde"的加密字符串的一部分
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.0.0
*/
@Inherited
@Documented
@Target({FIELD})
@Retention(RUNTIME)
public @interface CryptColumn {
Class<? extends CryptHandler> handler();
}

View File

@@ -0,0 +1,38 @@
/*
* 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;
/**
* 字段加密解密接口
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.0.0
* @param <S> 加密的字段类型
* @param <D> 加密后的数据类型
*/
public interface CryptHandler<S, D> {
/**
* 加密
*
* @param value 加密前的字段值
*
* @return 加密后的字段值
*/
public D encrypt(S value);
/**
* 解密
*
* @param value 加密的字段值
*
* @return 解密后的字段值
*/
public S decrypt(D value);
}

View File

@@ -20,5 +20,5 @@ public interface DataCacheListener {
public <T> int updateCache(Class<T> clazz, T... entitys);
public <T> int deleteCache(Class<T> clazz, Serializable... ids);
public <T> int deleteCache(Class<T> clazz, Serializable... pks);
}

View File

@@ -50,18 +50,18 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
}
@Override
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... values) {
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... entitys) {
Connection conn = null;
try {
int c = 0;
conn = writePool.poll();
final String sql = info.getInsertPrepareSQL(values[0]);
final String sql = info.getInsertPrepareSQL(entitys[0]);
final Class primaryType = info.getPrimary().type();
final Attribute primary = info.getPrimary();
Attribute<T, Serializable>[] attrs = info.insertAttributes;
conn.setReadOnly(false);
conn.setAutoCommit(true);
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, values);
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, entitys);
try {
int[] cs = prestmt.executeBatch();
int c1 = 0;
@@ -73,7 +73,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
if (info.tableStrategy == null || !info.isTableNotExist(se)) throw se;
synchronized (info.tables) {
final String oldTable = info.table;
final String newTable = info.getTable(values[0]);
final String newTable = info.getTable(entitys[0]);
if (!info.tables.contains(newTable)) {
try {
Statement st = conn.createStatement();
@@ -105,7 +105,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
}
}
prestmt.close();
prestmt = createInsertPreparedStatement(conn, sql, info, values);
prestmt = createInsertPreparedStatement(conn, sql, info, entitys);
int[] cs = prestmt.executeBatch();
int c1 = 0;
for (int cc : cs) {
@@ -118,11 +118,11 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
int i = -1;
while (set.next()) {
if (primaryType == int.class) {
primary.set(values[++i], set.getInt(1));
primary.set(entitys[++i], set.getInt(1));
} else if (primaryType == long.class) {
primary.set(values[++i], set.getLong(1));
primary.set(entitys[++i], set.getLong(1));
} else {
primary.set(values[++i], set.getObject(1));
primary.set(entitys[++i], set.getObject(1));
}
}
set.close();
@@ -131,13 +131,13 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
//------------------------------------------------------------
if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息
char[] sqlchars = sql.toCharArray();
for (final T value : values) {
for (final T value : entitys) {
//-----------------------------
StringBuilder sb = new StringBuilder(128);
int i = 0;
for (char ch : sqlchars) {
if (ch == '?') {
Object obj = attrs[i++].get(value);
Object obj = info.getSQLValue(attrs[i++], value);
if (obj != null && obj.getClass().isArray()) {
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
} else {
@@ -162,11 +162,11 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
}
protected <T> PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
final EntityInfo<T> info, T... values) throws SQLException {
final EntityInfo<T> info, T... entitys) throws SQLException {
Attribute<T, Serializable>[] attrs = info.insertAttributes;
final PreparedStatement prestmt = info.autoGenerated ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
for (final T value : values) {
for (final T value : entitys) {
if (info.autouuid) info.createPrimaryValue(value);
batchStatementParameters(conn, prestmt, info, attrs, value);
prestmt.addBatch();
@@ -174,10 +174,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
return prestmt;
}
protected <T> int batchStatementParameters(Connection conn, PreparedStatement prestmt, EntityInfo<T> info, Attribute<T, Serializable>[] attrs, T value) throws SQLException {
protected <T> int batchStatementParameters(Connection conn, PreparedStatement prestmt, EntityInfo<T> info, Attribute<T, Serializable>[] attrs, T entity) throws SQLException {
int i = 0;
for (Attribute<T, Serializable> attr : attrs) {
Serializable val = attr.get(value);
Serializable val = info.getSQLValue(attr, entity);
if (val instanceof byte[]) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) val);
@@ -186,7 +186,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
prestmt.setObject(++i, ((AtomicInteger) val).get());
} else if (val instanceof AtomicLong) {
prestmt.setObject(++i, ((AtomicLong) val).get());
} else if (val != null && !(val instanceof Number) && !(val instanceof CharSequence) && !(value instanceof java.util.Date)
} else if (val != null && !(val instanceof Number) && !(val instanceof CharSequence) && !(entity instanceof java.util.Date)
&& !val.getClass().getName().startsWith("java.sql.") && !val.getClass().getName().startsWith("java.time.")) {
prestmt.setObject(++i, info.jsonConvert.convertTo(attr.genericType(), val));
} else {
@@ -219,19 +219,59 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
}
@Override
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... values) {
protected <T> CompletableFuture<Integer> clearTableDB(EntityInfo<T> info, String sql) {
Connection conn = null;
try {
conn = writePool.poll();
conn.setReadOnly(false);
conn.setAutoCommit(true);
final String updateSQL = info.getUpdatePrepareSQL(values[0]);
final Statement stmt = conn.createStatement();
int c = stmt.executeUpdate(sql);
stmt.close();
return CompletableFuture.completedFuture(c);
} catch (SQLException e) {
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(e);
return future;
} finally {
if (conn != null) writePool.offerConnection(conn);
}
}
@Override
protected <T> CompletableFuture<Integer> dropTableDB(EntityInfo<T> info, String sql) {
Connection conn = null;
try {
conn = writePool.poll();
conn.setReadOnly(false);
conn.setAutoCommit(true);
final Statement stmt = conn.createStatement();
int c = stmt.executeUpdate(sql);
stmt.close();
return CompletableFuture.completedFuture(c);
} catch (SQLException e) {
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(e);
return future;
} finally {
if (conn != null) writePool.offerConnection(conn);
}
}
@Override
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... entitys) {
Connection conn = null;
try {
conn = writePool.poll();
conn.setReadOnly(false);
conn.setAutoCommit(true);
final String updateSQL = info.getUpdatePrepareSQL(entitys[0]);
final PreparedStatement prestmt = conn.prepareStatement(updateSQL);
Attribute<T, Serializable>[] attrs = info.updateAttributes;
final boolean debugfinest = info.isLoggable(logger, Level.FINEST);
char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null;
final Attribute<T, Serializable> primary = info.getPrimary();
for (final T value : values) {
for (final T value : entitys) {
int k = batchStatementParameters(conn, prestmt, info, attrs, value);
prestmt.setObject(++k, primary.get(value));
prestmt.addBatch();//------------------------------------------------------------
@@ -241,7 +281,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
StringBuilder sb = new StringBuilder(128);
for (char ch : sqlchars) {
if (ch == '?') {
Object obj = i == attrs.length ? primary.get(value) : attrs[i++].get(value);
Object obj = i == attrs.length ? info.getSQLValue(primary, value) : info.getSQLValue(attrs[i++], value);
if (obj != null && obj.getClass().isArray()) {
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
} else {
@@ -252,7 +292,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
}
}
String debugsql = sb.toString();
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " update sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " updates sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
} //打印结束
}
int[] pc = prestmt.executeBatch();
@@ -397,7 +437,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery();
T rs = set.next() ? info.getValue(selects, set) : null;
T rs = set.next() ? info.getEntityValue(selects, set) : null;
set.close();
ps.close();
return CompletableFuture.completedFuture(rs);
@@ -423,15 +463,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
final ResultSet set = ps.executeQuery();
Serializable val = defValue;
if (set.next()) {
if (attr.type() == byte[].class) {
Blob blob = set.getBlob(1);
if (blob != null) val = blob.getBytes(1, (int) blob.length());
} else {
val = (Serializable) set.getObject(1);
if (val != null && !CharSequence.class.isAssignableFrom(attr.type()) && (val instanceof CharSequence)) {
val = info.jsonConvert.convertFrom(attr.genericType(), val.toString());
}
}
val = info.getFieldValue(attr, set, 1);
}
set.close();
ps.close();
@@ -490,7 +522,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet set = ps.executeQuery();
while (set.next()) {
list.add(infoGetValue(info, sels, set));
list.add(getEntityValue(info, sels, set));
}
set.close();
ps.close();
@@ -522,7 +554,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
int i = 0;
while (set.next()) {
i++;
list.add(info.getValue(sels, set));
list.add(info.getEntityValue(sels, set));
if (limit <= i) break;
}
long total = list.size();

View File

@@ -84,7 +84,7 @@ public class DataMemorySource extends DataSqlSource<Void> {
}
@Override
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... values) {
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... entitys) {
return CompletableFuture.completedFuture(0);
}
@@ -94,7 +94,17 @@ public class DataMemorySource extends DataSqlSource<Void> {
}
@Override
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... values) {
protected <T> CompletableFuture<Integer> clearTableDB(EntityInfo<T> info, String sql) {
return CompletableFuture.completedFuture(0);
}
@Override
protected <T> CompletableFuture<Integer> dropTableDB(EntityInfo<T> info, String sql) {
return CompletableFuture.completedFuture(0);
}
@Override
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... entitys) {
return CompletableFuture.completedFuture(0);
}

View File

@@ -32,60 +32,105 @@ public interface DataSource {
public String getType();
//----------------------insertAsync-----------------------------
//insert 暂时不支持Collection、Stream 因为存在@RpcCall问题
/**
* 新增记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
*
* @param <T> 泛型
* @param values Entity对象
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数
*/
public <T> int insert(final T... values);
public <T> int insert(final T... entitys);
/**
* 新增记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
*
* @param <T> 泛型
* @param values Entity对象
* @param <T> 泛型
* @param entitys Entity对象
*
* @return CompletableFuture
*/
public <T> CompletableFuture<Integer> insertAsync(final T... values);
public <T> CompletableFuture<Integer> insertAsync(final T... entitys);
//-------------------------deleteAsync--------------------------
/**
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
*
* @param <T> 泛型
* @param values Entity对象
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数
*/
public <T> int delete(final T... values);
public <T> int delete(final T... entitys);
/**
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
*
* @param <T> 泛型
* @param values Entity对象
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> deleteAsync(final T... values);
/**
* 删除指定主键值的记录,多主键值必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param ids 主键值
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数
*/
public <T> int delete(final Class<T> clazz, final Serializable... ids);
default <T> int delete(final Collection<T> entitys) {
if (entitys == null || entitys.isEmpty()) return 0;
return delete(entitys.toArray());
}
/**
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数
*/
default <T> int delete(final Stream<T> entitys) {
if (entitys == null) return 0;
return delete(entitys.toArray());
}
/**
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> deleteAsync(final T... entitys);
/**
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数CompletableFuture
*/
default <T> CompletableFuture<Integer> deleteAsync(final Collection<T> entitys) {
if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0);
return deleteAsync(entitys.toArray());
}
/**
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数CompletableFuture
*/
default <T> CompletableFuture<Integer> deleteAsync(final Stream<T> entitys) {
if (entitys == null) return CompletableFuture.completedFuture(0);
return deleteAsync(entitys.toArray());
}
/**
* 删除指定主键值的记录,多主键值必须在同一张表中 <br>
@@ -93,11 +138,23 @@ public interface DataSource {
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param ids 主键值
* @param pks 主键值
*
* @return 影响的记录条数
*/
public <T> int delete(final Class<T> clazz, final Serializable... pks);
/**
* 删除指定主键值的记录,多主键值必须在同一张表中 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param pks 主键值
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Serializable... ids);
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Serializable... pks);
/**
* 删除符合过滤条件的记录 <br>
@@ -151,6 +208,100 @@ public interface DataSource {
*/
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Flipper flipper, final FilterNode node);
//------------------------clearAsync---------------------------
/**
* 清空表 <br>
* 等价SQL: TRUNCATE TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
*
* @return 影响的记录条数
*/
public <T> int clearTable(final Class<T> clazz);
/**
* 清空表 <br>
* 等价SQL: TRUNCATE TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> clearTableAsync(final Class<T> clazz);
/**
* 清空表 <br>
* 等价SQL: TRUNCATE TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return 影响的记录条数
*/
public <T> int clearTable(final Class<T> clazz, final FilterNode node);
/**
* 清空表 <br>
* 等价SQL: TRUNCATE TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> clearTableAsync(final Class<T> clazz, final FilterNode node);
//------------------------dropAsync---------------------------
/**
* 删除表 <br>
* 等价SQL: DROP TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
*
* @return 影响的记录条数
*/
public <T> int dropTable(final Class<T> clazz);
/**
* 删除表 <br>
* 等价SQL: DROP TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> dropTableAsync(final Class<T> clazz);
/**
* 删除表 <br>
* 等价SQL: DROP TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return 影响的记录条数
*/
public <T> int dropTable(final Class<T> clazz, final FilterNode node);
/**
* 删除表 <br>
* 等价SQL: DROP TABLE {table}<br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> dropTableAsync(final Class<T> clazz, final FilterNode node);
//------------------------updateAsync---------------------------
/**
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
@@ -159,12 +310,12 @@ public interface DataSource {
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id2} <br>
* &#183;&#183;&#183; <br>
*
* @param <T> 泛型
* @param values Entity对象
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数
*/
public <T> int update(final T... values);
public <T> int update(final T... entitys);
/**
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
@@ -173,12 +324,80 @@ public interface DataSource {
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id2} <br>
* &#183;&#183;&#183; <br>
*
* @param <T> 泛型
* @param values Entity对象
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数
*/
default <T> int update(final Collection<T> entitys) {
if (entitys == null || entitys.isEmpty()) return 0;
return update(entitys.toArray());
}
/**
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id1} <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id2} <br>
* &#183;&#183;&#183; <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数
*/
default <T> int update(final Stream<T> entitys) {
if (entitys == null) return 0;
return update(entitys.toArray());
}
/**
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id1} <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id2} <br>
* &#183;&#183;&#183; <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> updateAsync(final T... values);
public <T> CompletableFuture<Integer> updateAsync(final T... entitys);
/**
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id1} <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id2} <br>
* &#183;&#183;&#183; <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数CompletableFuture
*/
default <T> CompletableFuture<Integer> updateAsync(final Collection<T> entitys) {
if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0);
return updateAsync(entitys.toArray());
}
/**
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
* 等价SQL: <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id1} <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id2} <br>
* &#183;&#183;&#183; <br>
*
* @param <T> 泛型
* @param entitys Entity对象
*
* @return 影响的记录条数CompletableFuture
*/
default <T> CompletableFuture<Integer> updateAsync(final Stream<T> entitys) {
if (entitys == null) return CompletableFuture.completedFuture(0);
return updateAsync(entitys.toArray());
}
/**
* 更新单个记录的单个字段 <br>
@@ -187,13 +406,13 @@ public interface DataSource {
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param id 主键
* @param pk 主键
* @param column 待更新的字段名
* @param value 更新值
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value);
public <T> int updateColumn(final Class<T> clazz, final Serializable pk, final String column, final Serializable value);
/**
* 更新单个记录的单个字段 <br>
@@ -202,13 +421,13 @@ public interface DataSource {
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param id 主键
* @param pk 主键
* @param column 待更新的字段名
* @param value 更新值
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable id, final String column, final Serializable value);
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable pk, final String column, final Serializable value);
/**
* 更新符合过滤条件记录的单个字段 <br>
@@ -247,12 +466,12 @@ public interface DataSource {
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param id 主键
* @param pk 主键
* @param values 更新字段
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values);
public <T> int updateColumn(final Class<T> clazz, final Serializable pk, final ColumnValue... values);
/**
* 更新指定主键值记录的部分字段 <br>
@@ -261,12 +480,12 @@ public interface DataSource {
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param id 主键
* @param pk 主键
* @param values 更新字段
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable id, final ColumnValue... values);
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable pk, final ColumnValue... values);
/**
* 更新符合过滤条件记录的部分字段 <br>
@@ -336,12 +555,12 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {primary} = {bean.id} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param columns 需更新的字段名
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final T bean, final String... columns);
public <T> int updateColumn(final T entity, final String... columns);
/**
* 更新单个记录的指定字段 <br>
@@ -349,12 +568,12 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {primary} = {bean.id} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param columns 需更新的字段名
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final String... columns);
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final String... columns);
/**
* 更新符合过滤条件记录的指定字段 <br>
@@ -362,13 +581,13 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param node 过滤条件
* @param columns 需更新的字段名
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final T bean, final FilterNode node, final String... columns);
public <T> int updateColumn(final T entity, final FilterNode node, final String... columns);
/**
* 更新符合过滤条件记录的指定字段 <br>
@@ -376,13 +595,13 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param node 过滤条件
* @param columns 需更新的字段名
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final FilterNode node, final String... columns);
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final FilterNode node, final String... columns);
/**
* 更新单个记录的指定字段 <br>
@@ -390,12 +609,12 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {primary} = {bean.id} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param selects 指定字段
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final T bean, final SelectColumn selects);
public <T> int updateColumn(final T entity, final SelectColumn selects);
/**
* 更新单个记录的指定字段 <br>
@@ -403,12 +622,12 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {primary} = {bean.id} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param selects 指定字段
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final SelectColumn selects);
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final SelectColumn selects);
/**
* 更新符合过滤条件记录的指定字段 <br>
@@ -416,13 +635,13 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param node 过滤条件
* @param selects 指定字段
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final T bean, final FilterNode node, final SelectColumn selects);
public <T> int updateColumn(final T entity, final FilterNode node, final SelectColumn selects);
/**
* 更新符合过滤条件记录的指定字段 <br>
@@ -430,13 +649,13 @@ public interface DataSource {
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param entity 待更新的Entity对象
* @param node 过滤条件
* @param selects 指定字段
*
* @return 影响的记录条数CompletableFuture
*/
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final FilterNode node, final SelectColumn selects);
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final FilterNode node, final SelectColumn selects);
//############################################# 查询接口 #############################################
//-----------------------getXXXXResult-----------------------------
@@ -856,11 +1075,11 @@ public interface DataSource {
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return Entity对象
*/
public <T> T find(final Class<T> clazz, final String column, final Serializable key);
public <T> T find(final Class<T> clazz, final String column, final Serializable colval);
/**
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
@@ -869,11 +1088,11 @@ public interface DataSource {
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return Entity对象CompletableFuture
*/
public <T> CompletableFuture<T> findAsync(final Class<T> clazz, final String column, final Serializable key);
public <T> CompletableFuture<T> findAsync(final Class<T> clazz, final String column, final Serializable colval);
/**
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
@@ -1219,11 +1438,11 @@ public interface DataSource {
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return 字段值的集合
*/
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的某个字段Set集合 <br>
@@ -1234,11 +1453,11 @@ public interface DataSource {
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return 字段值的集合CompletableFuture
*/
public <T, V extends Serializable> CompletableFuture<HashSet<V>> queryColumnSetAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
public <T, V extends Serializable> CompletableFuture<HashSet<V>> queryColumnSetAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的某个字段Set集合 <br>
@@ -1305,11 +1524,11 @@ public interface DataSource {
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return 字段值的集合
*/
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的某个字段List集合 <br>
@@ -1320,11 +1539,11 @@ public interface DataSource {
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return 字段值的集合CompletableFuture
*/
public <T, V extends Serializable> CompletableFuture<List<V>> queryColumnListAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
public <T, V extends Serializable> CompletableFuture<List<V>> queryColumnListAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的某个字段List集合 <br>
@@ -1671,11 +1890,11 @@ public interface DataSource {
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key);
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的List集合 <br>
@@ -1684,11 +1903,11 @@ public interface DataSource {
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return Entity的集合CompletableFuture
*/
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final String column, final Serializable key);
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的List集合 <br>
@@ -1824,11 +2043,11 @@ public interface DataSource {
* @param clazz Entity类
* @param flipper 翻页对象
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key);
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的List集合 <br>
@@ -1838,11 +2057,11 @@ public interface DataSource {
* @param clazz Entity类
* @param flipper 翻页对象
* @param column 过滤字段名
* @param key 过滤字段值
* @param colval 过滤字段值
*
* @return Entity的集合CompletableFuture
*/
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key);
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final Flipper flipper, final String column, final Serializable colval);
/**
* 查询符合过滤条件记录的List集合 <br>

View File

@@ -157,7 +157,7 @@ public final class DataSources {
writeprop = map.get(unitName + ".write");
}
}
if ((unitName == null || unitName.isEmpty()) || readprop == null) {
if (unitName == null || unitName.isEmpty()) {
String key = null;
for (Map.Entry<String, Properties> en : map.entrySet()) {
key = en.getKey();

File diff suppressed because it is too large Load Diff

View File

@@ -144,7 +144,7 @@ public final class EntityCache<T> {
return type;
}
public void clear() {
public int clear() {
this.fullloaded = false;
this.list = new ConcurrentLinkedQueue();
this.map = new ConcurrentHashMap();
@@ -152,21 +152,22 @@ public final class EntityCache<T> {
this.scheduler.shutdownNow();
this.scheduler = null;
}
return 1;
}
public boolean isFullLoaded() {
return fullloaded;
}
public T find(Serializable id) {
if (id == null) return null;
T rs = map.get(id);
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 id) {
if (id == null) return null;
T rs = map.get(id);
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();
@@ -191,9 +192,9 @@ public final class EntityCache<T> {
return t;
}
public Serializable findColumn(final String column, final Serializable defValue, final Serializable id) {
if (id == null) return defValue;
T rs = map.get(id);
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())) {
@@ -220,29 +221,29 @@ public final class EntityCache<T> {
return defValue;
}
public boolean exists(Serializable id) {
if (id == null) return false;
public boolean exists(Serializable pk) {
if (pk == null) return false;
final Class atype = this.primary.type();
if (id.getClass() != atype && id instanceof Number) {
if (pk.getClass() != atype && pk instanceof Number) {
if (atype == int.class || atype == Integer.class) {
id = ((Number) id).intValue();
pk = ((Number) pk).intValue();
} else if (atype == long.class || atype == Long.class) {
id = ((Number) id).longValue();
pk = ((Number) pk).longValue();
} else if (atype == short.class || atype == Short.class) {
id = ((Number) id).shortValue();
pk = ((Number) pk).shortValue();
} else if (atype == float.class || atype == Float.class) {
id = ((Number) id).floatValue();
pk = ((Number) pk).floatValue();
} else if (atype == byte.class || atype == Byte.class) {
id = ((Number) id).byteValue();
pk = ((Number) pk).byteValue();
} else if (atype == double.class || atype == Double.class) {
id = ((Number) id).doubleValue();
pk = ((Number) pk).doubleValue();
} else if (atype == AtomicInteger.class) {
id = new AtomicInteger(((Number) id).intValue());
pk = new AtomicInteger(((Number) pk).intValue());
} else if (atype == AtomicLong.class) {
id = new AtomicLong(((Number) id).longValue());
pk = new AtomicLong(((Number) pk).longValue());
}
}
return this.map.containsKey(id);
return this.map.containsKey(pk);
}
public boolean exists(FilterNode node) {
@@ -439,22 +440,22 @@ public final class EntityCache<T> {
return new Sheet<>(total, rs);
}
public int insert(T value) {
if (value == null) return 0;
final T rs = newReproduce.apply(this.creator.create(), value); //确保同一主键值的map与list中的对象必须共用。
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: " + value);
logger.log(Level.WARNING, this.type + " cache repeat insert data: " + entity);
return 0;
}
}
public int delete(final Serializable id) {
if (id == null) return 0;
final T rs = this.map.remove(id);
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;
@@ -479,44 +480,48 @@ public final class EntityCache<T> {
return ids;
}
public int update(final T value) {
if (value == null) return 0;
T rs = this.map.get(this.primary.get(value));
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, value);
this.chgReproduce.apply(rs, entity);
}
return 1;
}
public T update(final T value, Collection<Attribute<T, Serializable>> attrs) {
if (value == null) return value;
T rs = this.map.get(this.primary.get(value));
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(value));
attr.set(rs, attr.get(entity));
}
}
return rs;
}
public T[] update(final T value, final Collection<Attribute<T, Serializable>> attrs, final FilterNode node) {
if (value == null || node == null) return (T[]) Array.newInstance(type, 0);
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(value));
attr.set(rs, attr.get(entity));
}
}
}
return rms;
}
public <V> T update(final Serializable id, Attribute<T, V> attr, final V fieldValue) {
if (id == null) return null;
T rs = this.map.get(id);
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;
}
@@ -530,9 +535,9 @@ public final class EntityCache<T> {
return rms;
}
public <V> T updateColumn(final Serializable id, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
if (id == null || attrs == null || attrs.isEmpty()) return null;
T rs = this.map.get(id);
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++) {
@@ -561,40 +566,40 @@ public final class EntityCache<T> {
return rms;
}
public <V> T updateColumnOr(final Serializable id, Attribute<T, V> attr, final long orvalue) {
if (id == null) return null;
T rs = this.map.get(id);
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 id, Attribute<T, V> attr, final long andvalue) {
if (id == null) return null;
T rs = this.map.get(id);
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 id, Attribute<T, V> attr, final long incvalue) {
if (id == null) return null;
T rs = this.map.get(id);
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);
}
}
private <V> T updateColumn(Attribute<T, V> attr, final T rs, final ColumnExpress express, Serializable val) {
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:
numb = (Number) attr.get(rs);
numb = (Number) attr.get(entity);
if (numb == null) {
numb = (Number) val;
} else {
@@ -602,7 +607,7 @@ public final class EntityCache<T> {
}
break;
case MUL:
numb = (Number) attr.get(rs);
numb = (Number) attr.get(entity);
if (numb == null) {
numb = 0;
} else {
@@ -610,7 +615,7 @@ public final class EntityCache<T> {
}
break;
case AND:
numb = (Number) attr.get(rs);
numb = (Number) attr.get(entity);
if (numb == null) {
numb = 0;
} else {
@@ -618,7 +623,7 @@ public final class EntityCache<T> {
}
break;
case ORR:
numb = (Number) attr.get(rs);
numb = (Number) attr.get(entity);
if (numb == null) {
numb = 0;
} else {
@@ -654,8 +659,8 @@ public final class EntityCache<T> {
newval = new AtomicLong(((Number) newval).longValue());
}
}
attr.set(rs, (V) newval);
return rs;
attr.set(entity, (V) newval);
return entity;
}
public Attribute<T, Serializable> getAttribute(String fieldname) {

View File

@@ -75,6 +75,10 @@ public final class EntityInfo<T> {
//只有field.name 与 Column.name不同才存放在aliasmap里.
private final Map<String, String> aliasmap;
//key是field的name value是CryptHandler
//字段都不存在CryptHandler时值因为为null减少判断
private final Map<String, CryptHandler> cryptmap;
//所有可更新字段,即排除了主键字段和标记为&#064;Column(updatable=false)的字段
private final Map<String, Attribute<T, Serializable>> updateAttributeMap = new HashMap<>();
@@ -274,6 +278,7 @@ public final class EntityInfo<T> {
}
this.constructorParameters = (cp == null || cp.value().length < 1) ? null : cp.value();
Attribute idAttr0 = null;
Map<String, CryptHandler> cryptmap0 = null;
Map<String, String> aliasmap0 = null;
Class cltmp = type;
Set<String> fields = new HashSet<>();
@@ -284,7 +289,7 @@ public final class EntityInfo<T> {
List<Attribute<T, Serializable>> updateattrs = new ArrayList<>();
boolean auto = false;
boolean uuid = false;
Map<Class, Creator<CryptHandler>> cryptCreatorMap = new HashMap<>();
do {
for (Field field : cltmp.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
@@ -298,9 +303,16 @@ public final class EntityInfo<T> {
if (aliasmap0 == null) aliasmap0 = new HashMap<>();
aliasmap0.put(fieldname, sqlfield);
}
final CryptColumn cpt = field.getAnnotation(CryptColumn.class);
CryptHandler cryptHandler = null;
if (cpt != null) {
if (cryptmap0 == null) cryptmap0 = new HashMap<>();
cryptHandler = cryptCreatorMap.computeIfAbsent(cpt.handler(), c -> (Creator<CryptHandler>) Creator.create(cpt.handler())).create();
cryptmap0.put(fieldname, cryptHandler);
}
Attribute attr;
try {
attr = Attribute.create(cltmp, field);
attr = Attribute.create(cltmp, field, cryptHandler);
} catch (RuntimeException e) {
continue;
}
@@ -357,6 +369,7 @@ public final class EntityInfo<T> {
this.primary = idAttr0;
this.aliasmap = aliasmap0;
this.cryptmap = cryptmap0;
this.attributes = attributeMap.values().toArray(new Attribute[attributeMap.size()]);
this.queryAttributes = queryattrs.toArray(new Attribute[queryattrs.size()]);
this.insertAttributes = insertattrs.toArray(new Attribute[insertattrs.size()]);
@@ -857,6 +870,51 @@ public final class EntityInfo<T> {
: (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname)));
}
/**
* 字段值转换成数据库的值
*
* @param fieldname 字段名
* @param fieldvalue 字段值
*
* @return Object
*/
public Object getSQLValue(String fieldname, Serializable fieldvalue) {
if (this.cryptmap == null) return fieldvalue;
CryptHandler handler = this.cryptmap.get(fieldname);
if (handler == null) return fieldvalue;
return handler.encrypt(fieldvalue);
}
/**
* 字段值转换成数据库的值
*
* @param attr Attribute
* @param entity 记录对象
*
* @return Object
*/
public Serializable getSQLValue(Attribute<T, Serializable> attr, T entity) {
Serializable val = attr.get(entity);
CryptHandler cryptHandler = attr.attach();
if (cryptHandler != null) val = (Serializable) cryptHandler.encrypt(val);
return val;
}
/**
* 数据库的值转换成数字段值
*
* @param attr Attribute
* @param entity 记录对象
*
* @return Object
*/
public Serializable getFieldValue(Attribute<T, Serializable> attr, T entity) {
Serializable val = attr.get(entity);
CryptHandler cryptHandler = attr.attach();
if (cryptHandler != null) val = (Serializable) cryptHandler.decrypt(val);
return val;
}
/**
* 获取主键字段的表字段名
*
@@ -880,26 +938,30 @@ public final class EntityInfo<T> {
/**
* 拼接UPDATE给字段赋值的SQL片段
*
* @param col 表字段名
* @param cv ColumnValue
* @param col 表字段名
* @param attr Attribute
* @param cv ColumnValue
*
* @return CharSequence
*/
protected CharSequence formatSQLValue(String col, final ColumnValue cv) {
protected CharSequence formatSQLValue(String col, Attribute<T, Serializable> attr, final ColumnValue cv) {
if (cv == null) return null;
Object val = cv.getValue();
CryptHandler handler = attr.attach();
if (handler != null) val = handler.encrypt(val);
switch (cv.getExpress()) {
case INC:
return new StringBuilder().append(col).append(" + ").append(cv.getValue());
return new StringBuilder().append(col).append(" + ").append(val);
case MUL:
return new StringBuilder().append(col).append(" * ").append(cv.getValue());
return new StringBuilder().append(col).append(" * ").append(val);
case AND:
return new StringBuilder().append(col).append(" & ").append(cv.getValue());
return new StringBuilder().append(col).append(" & ").append(val);
case ORR:
return new StringBuilder().append(col).append(" | ").append(cv.getValue());
return new StringBuilder().append(col).append(" | ").append(val);
case MOV:
return formatToString(cv.getValue());
return formatToString(val);
}
return formatToString(cv.getValue());
return formatToString(val);
}
/**
@@ -970,7 +1032,7 @@ public final class EntityInfo<T> {
* @return Entity对象
* @throws SQLException SQLException
*/
protected T getValue(final SelectColumn sels, final ResultSet set) throws SQLException {
protected T getEntityValue(final SelectColumn sels, final ResultSet set) throws SQLException {
T obj;
Attribute<T, Serializable>[] attrs = this.queryAttributes;
if (this.constructorParameters == null) {
@@ -995,17 +1057,25 @@ public final class EntityInfo<T> {
}
protected Serializable getFieldValue(Attribute<T, Serializable> attr, final ResultSet set) throws SQLException {
return getFieldValue(attr, set, 0);
}
protected Serializable getFieldValue(Attribute<T, Serializable> attr, final ResultSet set, int index) throws SQLException {
final Class t = attr.type();
Serializable o;
if (t == byte[].class) {
Blob blob = set.getBlob(this.getSQLColumn(null, attr.field()));
Blob blob = index > 0 ? set.getBlob(index) : set.getBlob(this.getSQLColumn(null, attr.field()));
if (blob == null) {
o = null;
} else { //不支持超过2G的数据
o = blob.getBytes(1, (int) blob.length());
CryptHandler cryptHandler = attr.attach();
if (cryptHandler != null) o = (Serializable) cryptHandler.decrypt(o);
}
} else {
o = (Serializable) set.getObject(this.getSQLColumn(null, attr.field()));
o = (Serializable) (index > 0 ? set.getObject(index) : set.getObject(this.getSQLColumn(null, attr.field())));
CryptHandler cryptHandler = attr.attach();
if (cryptHandler != null) o = (Serializable) cryptHandler.decrypt(o);
if (t.isPrimitive()) {
if (o != null) {
if (t == int.class) {

View File

@@ -389,7 +389,7 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
.append(' ').append(fv.getExpress().value()).append(' ').append(fv.getDestvalue());
}
final boolean fk = (val0 instanceof FilterKey);
CharSequence val = fk ? info.getSQLColumn(talis, ((FilterKey) val0).getColumn()) : formatToString(express, val0);
CharSequence val = fk ? info.getSQLColumn(talis, ((FilterKey) val0).getColumn()) : formatToString(express, info.getSQLValue(column, (Serializable) val0));
if (val == null) return null;
StringBuilder sb = new StringBuilder(32);
if (express == CONTAIN) return info.containSQL.replace("${column}", info.getSQLColumn(talis, column)).replace("${keystr}", val);

View File

@@ -131,6 +131,17 @@ public interface Attribute<T, F> {
*/
public void set(T obj, F value);
/**
* 附加对象
*
* @param <E> 泛型
*
* @return 附加对象
*/
default <E> E attach() {
return null;
}
/**
* 根据一个Field生成 Attribute 对象。
*
@@ -142,7 +153,22 @@ public interface Attribute<T, F> {
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(final java.lang.reflect.Field field) {
return create((Class<T>) field.getDeclaringClass(), field.getName(), field, null, null);
return create((Class<T>) field.getDeclaringClass(), field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null);
}
/**
* 根据一个Field生成 Attribute 对象。
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param field 字段,如果该字段不存在则抛异常
* @param attach 附加对象
*
* @return Attribute对象
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(final java.lang.reflect.Field field, Object attach) {
return create((Class<T>) field.getDeclaringClass(), field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach);
}
/**
@@ -157,7 +183,23 @@ public interface Attribute<T, F> {
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(String fieldalias, final java.lang.reflect.Field field) {
return create((Class<T>) field.getDeclaringClass(), fieldalias, field, null, null);
return create((Class<T>) field.getDeclaringClass(), fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null);
}
/**
* 根据一个Field和field的别名生成 Attribute 对象。
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param fieldalias 别名
* @param field 字段,如果该字段不存在则抛异常
* @param attach 附加对象
*
* @return Attribute对象
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(String fieldalias, final java.lang.reflect.Field field, Object attach) {
return create((Class<T>) field.getDeclaringClass(), fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach);
}
/**
@@ -172,7 +214,26 @@ public interface Attribute<T, F> {
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final String fieldname) {
try {
return create(clazz, fieldname, clazz.getDeclaredField(fieldname), null, null);
return create(clazz, fieldname, (Class) null, clazz.getDeclaredField(fieldname), (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null);
} catch (NoSuchFieldException | SecurityException ex) {
throw new RuntimeException(ex);
}
}
/**
* 根据一个Class和field真实名称生成 Attribute 对象。
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldname 字段名,如果该字段不存在则抛异常
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final String fieldname, Object attach) {
try {
return create(clazz, fieldname, (Class) null, clazz.getDeclaredField(fieldname), (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach);
} catch (NoSuchFieldException | SecurityException ex) {
throw new RuntimeException(ex);
}
@@ -189,7 +250,22 @@ public interface Attribute<T, F> {
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final java.lang.reflect.Field field) {
return create(clazz, field.getName(), field);
return create(clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null);
}
/**
* 根据一个Class和Field生成 Attribute 对象。
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param field 字段,如果该字段不存在则抛异常
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final java.lang.reflect.Field field, Object attach) {
return create(clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach);
}
/**
@@ -204,7 +280,23 @@ public interface Attribute<T, F> {
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final String fieldalias, final java.lang.reflect.Field field) {
return create(clazz, fieldalias, field, null, null);
return create(clazz, fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null);
}
/**
* 根据一个Class、field别名和Field生成 Attribute 对象。
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldalias 字段别名
* @param field 字段,如果该字段不存在则抛异常
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final String fieldalias, final java.lang.reflect.Field field, Object attach) {
return create(clazz, fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach);
}
/**
@@ -219,7 +311,23 @@ public interface Attribute<T, F> {
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) {
return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), null, null, getter, setter);
return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, null);
}
/**
* 根据一个getter和setter方法生成 Attribute 对象。 tgetter、setter不能同时为null
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param getter getter方法
* @param setter setter方法
* @param attach 附加对象
*
* @return Attribute对象
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) {
return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach);
}
/**
@@ -234,7 +342,23 @@ public interface Attribute<T, F> {
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) {
return create(clazz, null, null, getter, setter);
return create(clazz, (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, null);
}
/**
* 根据Class、getter和setter方法生成 Attribute 对象。 tgetter、setter不能同时为null
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param getter getter方法
* @param setter setter方法
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) {
return create(clazz, (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach);
}
/**
@@ -314,7 +438,7 @@ public interface Attribute<T, F> {
if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue;
if (!method.getName().startsWith("set")) continue;
if (method.getParameterCount() != 1) continue;
list.add(create(clazz, null, method));
list.add(create(clazz, (java.lang.reflect.Method) null, method));
}
return list.toArray(new Attribute[list.size()]);
}
@@ -332,7 +456,24 @@ public interface Attribute<T, F> {
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final String fieldalias, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) {
return create(clazz, fieldalias, null, getter, setter);
return create(clazz, fieldalias, (Class) null, (java.lang.reflect.Field) null, getter, setter, null);
}
/**
* 根据Class、字段别名、getter和setter方法生成 Attribute 对象。 tgetter、setter不能同时为null
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldalias 字段别名
* @param getter getter方法
* @param setter setter方法
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(Class<T> clazz, final String fieldalias, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) {
return create(clazz, fieldalias, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach);
}
/**
@@ -349,7 +490,25 @@ public interface Attribute<T, F> {
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(final Class<T> clazz, String fieldalias, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter) {
return create(clazz, fieldalias, null, field, getter, setter);
return create(clazz, fieldalias, (Class) null, field, getter, setter, null);
}
/**
* 根据Class、字段别名、Field、getter和setter方法生成 Attribute 对象。 Field、tgetter、setter不能同时为null
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldalias 字段别名
* @param field 字段
* @param getter getter方法
* @param setter setter方法
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(final Class<T> clazz, String fieldalias, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) {
return create(clazz, fieldalias, (Class) null, field, getter, setter, attach);
}
/**
@@ -364,7 +523,23 @@ public interface Attribute<T, F> {
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(final Class<T> clazz, String fieldalias, final Class<F> fieldtype) {
return create(clazz, fieldalias, fieldtype, null, (Function) null, null);
return create(clazz, fieldalias, fieldtype, (java.lang.reflect.Type) null, (Function) null, (BiConsumer) null, null);
}
/**
* 根据Class、字段别名、字段类型生成虚构的 Attribute 对象,get、set方法为空方法。
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldalias 字段别名
* @param fieldtype 字段的类
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(final Class<T> clazz, String fieldalias, final Class<F> fieldtype, Object attach) {
return create(clazz, fieldalias, fieldtype, (java.lang.reflect.Type) null, (Function) null, (BiConsumer) null, attach);
}
/**
@@ -383,6 +558,26 @@ public interface Attribute<T, F> {
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(final Class<T> clazz, String fieldalias, final Class<F> fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter) {
return create(clazz, fieldalias, fieldtype, field, getter, setter, null);
}
/**
* 根据Class、字段别名、字段类型、Field、getter和setter方法生成 Attribute 对象。 fieldalias/fieldtype、Field、tgetter、setter不能同时为null.
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldalias 字段别名
* @param fieldtype 字段类型
* @param field 字段
* @param getter getter方法
* @param setter setter方法
* @param attach 附加对象
*
* @return Attribute对象
*/
@SuppressWarnings("unchecked")
public static <T, F> Attribute<T, F> create(final Class<T> clazz, String fieldalias, final Class<F> fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) {
if (fieldalias != null && fieldalias.isEmpty()) fieldalias = null;
int mod = field == null ? java.lang.reflect.Modifier.STATIC : field.getModifiers();
if (field != null && !java.lang.reflect.Modifier.isStatic(mod) && !java.lang.reflect.Modifier.isPublic(mod)) {
@@ -477,6 +672,10 @@ public interface Attribute<T, F> {
FieldVisitor fv = cw.visitField(ACC_PRIVATE, "_gtype", "Ljava/lang/reflect/Type;", null, null);
fv.visitEnd();
}
{ //_attach
FieldVisitor fv = cw.visitField(ACC_PRIVATE, "_attach", "Ljava/lang/Object;", null, null);
fv.visitEnd();
}
{ //构造方法
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
@@ -526,6 +725,14 @@ public interface Attribute<T, F> {
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{ //attach
mv = cw.visitMethod(ACC_PUBLIC, "attach", "()Ljava/lang/Object;", "<E:Ljava/lang/Object;>()TE;", null);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "_attach", "Ljava/lang/Object;");
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{ //declaringClass 方法
mv = cw.visitMethod(ACC_PUBLIC, "declaringClass", "()Ljava/lang/Class;", null, null);
mv.visitLdcInsn(Type.getType(clazz));
@@ -632,6 +839,9 @@ public interface Attribute<T, F> {
java.lang.reflect.Field _gtype = rs.getClass().getDeclaredField("_gtype");
_gtype.setAccessible(true);
_gtype.set(rs, generictype);
java.lang.reflect.Field _attach = rs.getClass().getDeclaredField("_attach");
_attach.setAccessible(true);
_attach.set(rs, attach);
return rs;
} catch (Exception ex) {
throw new RuntimeException(ex);
@@ -655,6 +865,24 @@ public interface Attribute<T, F> {
return create(clazz, fieldname, fieldtype, fieldtype, getter, setter);
}
/**
* 根据Class、字段名、字段类型、getter和setter方法生成 Attribute 对象。 clazz、fieldname、fieldtype都不能为null
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldname 字段名
* @param fieldtype 字段类型
* @param getter getter方法
* @param setter setter方法
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(final Class<T> clazz, final String fieldname, final Class<F> fieldtype, final Function<T, F> getter, final BiConsumer<T, F> setter, Object attach) {
return create(clazz, fieldname, fieldtype, fieldtype, getter, setter, attach);
}
/**
* 根据Class、字段名、字段类型、getter和setter方法生成 Attribute 对象。 clazz、fieldname、fieldtype都不能为null
*
@@ -671,6 +899,26 @@ public interface Attribute<T, F> {
*/
public static <T, F> Attribute<T, F> create(final Class<T> clazz, final String fieldname, final Class<F> fieldtype,
final java.lang.reflect.Type fieldGenericType, final Function<T, F> getter, final BiConsumer<T, F> setter) {
return create(clazz, fieldname, fieldtype, fieldGenericType, getter, setter, null);
}
/**
* 根据Class、字段名、字段类型、getter和setter方法生成 Attribute 对象。 clazz、fieldname、fieldtype都不能为null
*
* @param <T> 依附类的类型
* @param <F> 字段类型
* @param clazz 指定依附的类
* @param fieldname 字段名
* @param fieldtype 字段类型
* @param fieldGenericType 字段泛型
* @param getter getter方法
* @param setter setter方法
* @param attach 附加对象
*
* @return Attribute对象
*/
public static <T, F> Attribute<T, F> create(final Class<T> clazz, final String fieldname, final Class<F> fieldtype,
final java.lang.reflect.Type fieldGenericType, final Function<T, F> getter, final BiConsumer<T, F> setter, final Object attach) {
Objects.requireNonNull(clazz);
Objects.requireNonNull(fieldname);
Objects.requireNonNull(fieldtype);
@@ -685,6 +933,11 @@ public interface Attribute<T, F> {
return fieldGenericType;
}
@Override
public <E> E attach() {
return (E) attach;
}
@Override
public Class<T> declaringClass() {
return clazz;

View File

@@ -85,6 +85,13 @@ public interface Creator<T> {
creatorCacheMap.put(Stream.class, (params) -> new ArrayList<>().stream());
creatorCacheMap.put(ConcurrentHashMap.class, (params) -> new ConcurrentHashMap<>());
creatorCacheMap.put(CompletableFuture.class, (params) -> new CompletableFuture<>());
creatorCacheMap.put(AbstractMap.SimpleEntry.class, new Creator<AbstractMap.SimpleEntry>() {
@Override
@ConstructorParameters({"key", "value"})
public AbstractMap.SimpleEntry create(Object... params) {
return new AbstractMap.SimpleEntry(params[0], params[1]);
}
});
}
static class SimpleClassVisitor extends ClassVisitor {

View File

@@ -5,7 +5,7 @@
*/
package org.redkale.util;
/**
/**
* <p>
* 详情见: https://redkale.org
*
@@ -17,14 +17,14 @@ public final class Redkale {
}
public static String getDotedVersion() {
return "1.9.9";
return "2.0.0";
}
public static int getMajorVersion() {
return 1;
return 2;
}
public static int getMinorVersion() {
return 9;
return 0;
}
}

View File

@@ -39,9 +39,9 @@ public class RedkaleClassLoader extends URLClassLoader {
HashSet<URL> set = new HashSet<>();
String appPath = System.getProperty("java.class.path");
if (appPath != null && !appPath.isEmpty()) {
for (String path : appPath.replace(":/", "&&").replace(":\\", "##").replace(':', ';').split(";")) {
for (String path : appPath.replace("://", "&&").replace(":\\", "##").replace(':', ';').split(";")) {
try {
set.add(Paths.get(path.replace("&&", ":/").replace("##", ":\\")).toRealPath().toFile().toURI().toURL());
set.add(Paths.get(path.replace("&&", "://").replace("##", ":\\")).toRealPath().toFile().toURI().toURL());
} catch (Exception e) {
}
}

View File

@@ -41,12 +41,12 @@ public interface Reproduce<D, S> extends BiFunction<D, S, D> {
}
@SuppressWarnings("unchecked")
public static <D, S> Reproduce<D, S> create(final Class<D> destClass, final Class<S> srcClass, final BiPredicate<Class<S>, String> srcColumnPredicate) {
public static <D, S> Reproduce<D, S> create(final Class<D> destClass, final Class<S> srcClass, final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate) {
return create(destClass, srcClass, srcColumnPredicate, (Map<String, String>) null);
}
@SuppressWarnings("unchecked")
public static <D, S> Reproduce<D, S> create(final Class<D> destClass, final Class<S> srcClass, final BiPredicate<Class<S>, String> srcColumnPredicate, final Map<String, String> names) {
public static <D, S> Reproduce<D, S> create(final Class<D> destClass, final Class<S> srcClass, final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate, final Map<String, String> names) {
// ------------------------------------------------------------------------------
final String supDynName = Reproduce.class.getName().replace('.', '/');
final String destClassName = destClass.getName().replace('.', '/');
@@ -89,7 +89,7 @@ public interface Reproduce<D, S> extends BiFunction<D, S, D> {
if (Modifier.isFinal(field.getModifiers())) continue;
if (!Modifier.isPublic(field.getModifiers())) continue;
final String sfname = field.getName();
if (srcColumnPredicate != null && !srcColumnPredicate.test(srcClass, sfname)) continue;
if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) continue;
final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname);
java.lang.reflect.Method setter = null;
@@ -128,7 +128,7 @@ public interface Reproduce<D, S> extends BiFunction<D, S, D> {
cs[0] = Character.toLowerCase(cs[0]);
sfname = new String(cs);
}
if (srcColumnPredicate != null && !srcColumnPredicate.test(srcClass, sfname)) continue;
if (srcColumnPredicate != null && !srcColumnPredicate.test(getter, sfname)) continue;
final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname);
java.lang.reflect.Method setter = null;

View File

@@ -570,7 +570,8 @@ public final class ResourceFactory {
if (Modifier.isStatic(field.getModifiers())) continue;
field.setAccessible(true);
final Class classtype = field.getType();
final Type genctype = field.getGenericType();
final Type genctype = TypeToken.containsUnknownType(field.getGenericType())
? TypeToken.getGenericType(field.getGenericType(), src.getClass()) : field.getGenericType();
Resource rc = field.getAnnotation(Resource.class);
if (rc == null) { //深度注入
boolean flag = true; //是否没有重复

View File

@@ -140,7 +140,11 @@ public class Sheet<T> implements java.io.Serializable, Iterable<T> {
return (this.rows == null) ? new ArrayList<T>().toArray() : this.rows.toArray();
}
public T[] toArray(T[] a) {
return (this.rows == null) ? new ArrayList<T>().toArray(a) : this.rows.toArray(a);
public <E> E[] toArray(E[] a) {
return (this.rows == null) ? new ArrayList<E>().toArray(a) : this.rows.toArray(a);
}
public <E> E[] toArray(IntFunction<E[]> generator) {
return (this.rows == null) ? new ArrayList<E>().toArray(generator.apply(0)) : this.rows.toArray(generator.apply(this.rows.size()));
}
}

View File

@@ -56,6 +56,27 @@ public abstract class TypeToken<T> {
return true;
}
public final static boolean containsUnknownType(final Type type) {
if (type == null) return false;
if (type instanceof Class) return false;
if (type instanceof WildcardType) return true;
if (type instanceof TypeVariable) return true;
if (type instanceof GenericArrayType) return containsUnknownType(((GenericArrayType) type).getGenericComponentType());
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
if (containsUnknownType(pt.getRawType())) return true;
if (containsUnknownType(pt.getOwnerType())) return true;
Type[] ts = pt.getActualTypeArguments();
if (ts != null) {
for (Type t : ts) {
if (containsUnknownType(t)) return true;
}
}
return false;
}
return true;
}
public final static Class typeToClass(final Type type) {
if (type instanceof Class) return (Class) type;
if (type instanceof WildcardType) return null;

View File

@@ -31,8 +31,8 @@ public final class Utility {
private static final int zoneRawOffset = TimeZone.getDefault().getRawOffset();
private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS";
//static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS";
//static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL";
private static final char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
@@ -279,14 +279,29 @@ public final class Utility {
}
/**
* 获取int数组之和
* 获取int数组之和, 空数组返回0
*
* @param array 数组
*
* @return int
*/
public static int sum(final int... array) {
if (array == null || array.length == 0) throw new NullPointerException("array is null or empty");
return sum(false, array);
}
/**
* 获取int数组之和
*
* @param check 是否检测空
* @param array 数组
*
* @return int
*/
public static int sum(boolean check, final int... array) {
if (array == null || array.length == 0) {
if (!check) return 0;
throw new NullPointerException("array is null or empty");
}
int sum = 0;
for (int i : array) {
sum += i;
@@ -295,14 +310,29 @@ public final class Utility {
}
/**
* 获取long数组之和
* 获取long数组之和, 空数组返回0
*
* @param array 数组
*
* @return long
*/
public static long sum(final long... array) {
if (array == null || array.length == 0) throw new NullPointerException("array is null or empty");
return sum(false, array);
}
/**
* 获取long数组之和
*
* @param check 是否检测空
* @param array 数组
*
* @return long
*/
public static long sum(boolean check, final long... array) {
if (array == null || array.length == 0) {
if (!check) return 0;
throw new NullPointerException("array is null or empty");
}
long sum = 0L;
for (long i : array) {
sum += i;
@@ -447,6 +477,40 @@ public final class Utility {
return sb.toString();
}
/**
* 将一个或多个byte新元素添加到byte数组结尾
*
* @param array 原数组
* @param objs 待追加数据
*
* @return 新数组
*/
public static byte[] append(final byte[] array, final byte... objs) {
if (array == null || array.length == 0) return objs;
if (objs == null || objs.length == 0) return array;
final byte[] news = new byte[array.length + objs.length];
System.arraycopy(array, 0, news, 0, array.length);
System.arraycopy(objs, 0, news, array.length, objs.length);
return news;
}
/**
* 将一个或多个short新元素添加到short数组结尾
*
* @param array 原数组
* @param objs 待追加数据
*
* @return 新数组
*/
public static short[] append(final short[] array, final short... objs) {
if (array == null || array.length == 0) return objs;
if (objs == null || objs.length == 0) return array;
final short[] news = new short[array.length + objs.length];
System.arraycopy(array, 0, news, 0, array.length);
System.arraycopy(objs, 0, news, array.length, objs.length);
return news;
}
/**
* 将一个或多个char新元素添加到char数组结尾
*
@@ -884,7 +948,16 @@ public final class Utility {
* @return 格式为yyyy-MM-dd HH:mm:ss的时间值
*/
public static String now() {
return String.format(format, System.currentTimeMillis());
return formatTime(19, -1);
}
/**
* 获取格式为yyyy-MM-dd HH:mm:ss.fff的当前时间
*
* @return 格式为yyyy-MM-dd HH:mm:ss.fff的时间值
*/
public static String nowMillis() {
return formatTime(23, -1);
}
/**
@@ -895,7 +968,47 @@ public final class Utility {
* @return 格式为yyyy-MM-dd HH:mm:ss的时间值
*/
public static String formatTime(long time) {
return String.format(format, time);
return formatTime(19, time);
}
/**
* 将指定时间格式化为 yyyy-MM-dd HH:mm:ss
*
* @param time 待格式化的时间
*
* @return 格式为yyyy-MM-dd HH:mm:ss的时间值
*/
private static String formatTime(int length, long time) {
Calendar cal = Calendar.getInstance();
if (time > -1) cal.setTimeInMillis(time);
StringBuilder sb = new StringBuilder(length);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DAY_OF_MONTH);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int seconds = cal.get(Calendar.SECOND);
sb.append(cal.get(Calendar.YEAR)).append('-');
if (month < 10) sb.append('0');
sb.append(month).append('-');
if (day < 10) sb.append('0');
sb.append(day).append(' ');
if (hour < 10) sb.append('0');
sb.append(hour).append(':');
if (minute < 10) sb.append('0');
sb.append(minute).append(':');
if (seconds < 10) sb.append('0');
sb.append(seconds);
if (length > 20) {
int millis = cal.get(Calendar.MILLISECOND);
sb.append('.');
if (millis < 10) {
sb.append("00");
} else if (millis < 100) {
sb.append('0');
}
sb.append(millis);
}
return sb.toString();
}
/**
@@ -950,6 +1063,28 @@ public final class Utility {
return today.getYear() % 100 * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth();
}
/**
* 获取当天1512312359格式的int值
*
* @return 1512312359格式的int值
*/
public static int todayYYMMDDHHmm() {
java.time.LocalDateTime today = java.time.LocalDateTime.now();
return today.getYear() % 100 * 100_00_00_00 + today.getMonthValue() * 100_00_00 + today.getDayOfMonth() * 100_00
+ today.getHour() * 100 + today.getMinute();
}
/**
* 获取当天151231235959格式的int值
*
* @return 151231235959格式的int值
*/
public static long todayYYMMDDHHmmss() {
java.time.LocalDateTime today = java.time.LocalDateTime.now();
return today.getYear() % 100 * 100_00_00_00_00L + today.getMonthValue() * 100_00_00_00 + today.getDayOfMonth() * 100_00_00
+ today.getHour() * 100_00 + today.getMinute() * 100 + today.getSecond();
}
/**
* 获取昨天20151230格式的int值
*
@@ -1833,7 +1968,7 @@ public final class Utility {
conn.setRequestProperty(en.getKey(), en.getValue());
}
}
{
if (body != null && !body.isEmpty()) { //conn.getOutputStream()会将GET强制变成POST
conn.setDoInput(true);
conn.setDoOutput(true);
conn.getOutputStream().write(body == null ? new byte[0] : body.getBytes(UTF_8));

View File

@@ -69,5 +69,7 @@ public class JsonTestMain {
SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, in);
System.out.println(entry);
System.out.println(entry2);
Map rs = (Map) convert.convertFrom(entry2.toString());
System.out.println(convert.convertTo(rs));
}
}