120 Commits
1.9.3 ... 1.9.6

Author SHA1 Message Date
Redkale
333ba0f162 2018-08-18 11:27:50 +08:00
Redkale
e039b0e9f6 2018-08-17 11:26:45 +08:00
Redkale
b3c5e3beca 2018-08-15 18:18:27 +08:00
Redkale
70ba45c3bd 2018-08-15 18:13:09 +08:00
Redkale
14ae44fcac 修复DataJdbcSource.queryList会查total的BUG 2018-08-15 16:57:44 +08:00
Redkale
f7618f5da4 DataSqlSource.directQuery接口变动 2018-08-15 14:49:20 +08:00
Redkale
d6c6e4c02e 2018-08-14 10:40:11 +08:00
Redkale
9365052b85 2018-08-13 19:20:21 +08:00
Redkale
ef88063094 修复EntityCache重复insert数据时会导致map和list的同一id的对象不一致的BUG 2018-08-13 19:12:05 +08:00
Redkale
4cbaf85eea 2018-08-13 18:30:07 +08:00
Redkale
6c07123da3 2018-08-13 18:29:12 +08:00
Redkale
04a4ce12c7 2018-08-09 19:32:03 +08:00
Redkale
e00ed8ae37 增加DataMemorySource 2018-08-08 14:30:51 +08:00
Redkale
218a79b60a 2018-08-07 15:41:22 +08:00
Redkale
19ae86c71f 2018-08-07 13:52:00 +08:00
Redkale
9250d4e64d 2018-08-07 11:53:26 +08:00
Redkale
9f5aa58a31 2018-08-06 19:58:19 +08:00
Redkale
c8b0a88573 2018-08-06 18:05:13 +08:00
Redkale
7cf3f49aa1 1.9.5.1 2018-08-06 17:39:17 +08:00
Redkale
be2c803f82 2018-08-06 17:38:03 +08:00
Redkale
fd1197e8dc 2018-08-04 23:40:52 +08:00
Redkale
115f91b64a 2018-08-04 18:31:29 +08:00
Redkale
dfb800473a 2018-08-04 18:08:11 +08:00
Redkale
c69c1bb134 ppl 2018-08-04 15:12:22 +08:00
Redkale
5b501c7c2f 2018-08-04 14:52:44 +08:00
Redkale
8d5ce56ec2 FileHandler.limit支持G/M/K 2018-08-03 22:23:56 +08:00
Redkale
15c97ddc18 2018-08-02 13:51:41 +08:00
Redkale
36d7fbf4e9 2018-07-31 15:47:18 +08:00
Redkale
919e7aa5c6 2018-07-30 16:02:26 +08:00
Redkale
2174de2b71 2018-07-30 16:01:39 +08:00
Redkale
cb9e914e44 2018-07-30 15:51:20 +08:00
Redkale
15f856b762 2018-07-30 15:26:47 +08:00
Redkale
991dba0d62 2018-07-27 21:29:50 +08:00
Redkale
aa2685d6e4 修复WebSocketEngine的future = future.whenComplete问题 2018-07-27 20:35:48 +08:00
Redkale
0952150328 2018-07-27 20:29:13 +08:00
Redkale
e6ef4d1546 2018-07-27 20:02:08 +08:00
Redkale
16cf85abb9 2018-07-27 19:59:58 +08:00
Redkale
5afe0ead94 修复WebSocketNode远程模式下forceCloseWebSocket会报错的BUG 2018-07-27 19:52:12 +08:00
Redkale
b6c933f989 WebSocketNode远程模式下forceCloseWebSocket会报错 2018-07-27 19:38:46 +08:00
Redkale
feaf1a1f06 Redkale 1.9.6 开始 2018-07-27 19:19:00 +08:00
Redkale
6b54c6e886 2018-07-26 16:16:09 +08:00
Redkale
a95b69ab79 2018-07-26 11:54:09 +08:00
Redkale
a2492ae248 2018-07-26 11:36:51 +08:00
Redkale
0db1c4413c 2018-07-26 10:53:35 +08:00
Redkale
8718bca6e8 2018-07-26 08:48:23 +08:00
Redkale
6486863d00 2018-07-25 16:36:09 +08:00
Redkale
bfc2397dbf 2018-07-25 14:58:02 +08:00
Redkale
0cfdb9795b 2018-07-25 12:06:11 +08:00
Redkale
d327757d59 2018-07-25 11:43:51 +08:00
Redkale
e88c4fa2e3 修复进程关闭时WebSocket没有执行onClose方法的BUG 2018-07-24 20:11:02 +08:00
Redkale
69a0071e17 2018-07-23 10:06:36 +08:00
Redkale
d3cfe809e7 2018-07-23 09:38:47 +08:00
Redkale
0ca6e5401a 2018-07-23 09:37:49 +08:00
Redkale
8ff2b60ed4 2018-07-22 18:37:07 +08:00
Redkale
1dbe125e27 2018-07-22 18:15:24 +08:00
Redkale
32a595262d 2018-07-22 18:03:30 +08:00
Redkale
01431a93a4 2018-07-22 17:55:02 +08:00
Redkale
00a12d8113 2018-07-21 14:21:50 +08:00
Redkale
0f2474386c 2018-07-21 10:58:17 +08:00
Redkale
5de52ed6e8 Convert优化 2018-07-21 10:50:01 +08:00
Redkale
099b3fb7f3 2018-07-20 15:00:18 +08:00
Redkale
ed85e33403 2018-07-20 11:38:53 +08:00
Redkale
daff7d095f 2018-07-20 10:58:51 +08:00
Redkale
a8ff82229f 2018-07-20 10:01:59 +08:00
Redkale
2874e7d195 2018-07-20 09:48:47 +08:00
Redkale
8baea2657d 2018-07-20 09:04:05 +08:00
Redkale
03e9a5cbcb 更新Convert的Array、Map相关接口 2018-07-19 10:26:40 +08:00
Redkale
8d2f2a28af 2018-07-18 16:14:09 +08:00
Redkale
4a4bade180 Decoder/Encoder获取更多信息 2018-07-16 19:16:10 +08:00
Redkale
28e72f9883 Convert增加readByteArray和writeByteArray方法 2018-07-16 18:38:02 +08:00
Redkale
681e3967d2 2018-07-16 14:02:30 +08:00
Redkale
640dcbc8d7 2018-07-16 12:40:32 +08:00
Redkale
19276ecb91 2018-07-16 00:36:45 +08:00
Redkale
9f9078cdc5 2018-07-16 00:33:45 +08:00
Redkale
9bd1e0c97b 2018-07-15 23:42:28 +08:00
Redkale
c2c8f700a2 2018-07-15 22:18:52 +08:00
Redkale
86895eb5ef 2018-07-15 20:10:09 +08:00
Redkale
e8dacd6b70 2018-07-15 18:11:30 +08:00
Redkale
03fcf1dc95 2018-07-15 17:43:58 +08:00
Redkale
953b2be224 2018-07-14 12:54:48 +08:00
Redkale
55645ba2a0 2018-07-14 09:22:42 +08:00
Redkale
858c6a0aaf 2018-07-14 00:14:10 +08:00
Redkale
85d4023fa2 2018-07-13 23:22:02 +08:00
Redkale
607fc8e45f 2018-07-13 23:13:42 +08:00
Redkale
511a966ce5 2018-07-13 23:11:36 +08:00
Redkale
6d135efbc6 2018-07-13 22:56:33 +08:00
Redkale
5dff6310aa 2018-07-13 11:52:28 +08:00
Redkale
194a06c748 2018-07-13 09:41:26 +08:00
Redkale
1ce97aa20d 2018-07-13 06:46:55 +08:00
Redkale
1c88fb0355 修复JsonConvert没有按指定Type进行convertTo的BUG 2018-07-12 17:45:41 +08:00
Redkale
7b81c42377 JsonConvert支持带空格的数值字符串转成Number对象 2018-07-12 14:19:40 +08:00
Redkale
1afa38a947 2018-07-11 16:58:03 +08:00
Redkale
eedb418299 增加RpcRemoteException 2018-07-11 16:15:24 +08:00
Redkale
9efc14e627 2018-07-10 15:36:23 +08:00
Redkale
0dc3d65307 去掉对Rest中find、delete开头方法的特殊处理 2018-07-10 15:25:40 +08:00
Redkale
e3ddbe609c 2018-07-09 11:10:15 +08:00
Redkale
f115934499 2018-07-08 14:49:48 +08:00
Redkale
f5e290a47a Watch组件增加可以获取指定Servie中某个可序列化的字段的值 2018-07-06 22:28:20 +08:00
Redkale
29cd395888 RestConvert增加可以返回skipAllIgnore(true)的Convert功能 2018-07-06 18:53:39 +08:00
Redkale
9ca7855756 2018-07-05 11:47:58 +08:00
Redkale
1f1ab112eb 2018-07-05 11:36:30 +08:00
Redkale
b172b66263 去掉persistence.xml的监听文件变化功能,该有watch组件提供动态修改数据源配置 2018-07-05 09:49:19 +08:00
Redkale
b08f9f5757 增加java.util.Properties的convert 2018-07-05 09:47:39 +08:00
Redkale
32e65ff304 2018-07-03 15:49:32 +08:00
Redkale
40126c923e 2018-07-03 15:09:40 +08:00
Redkale
83ae5b0a13 2018-07-03 15:05:54 +08:00
Redkale
aea6a2839d 增加LogExcludeLevel功能 2018-07-03 10:10:52 +08:00
Redkale
6211d9ff18 Redkale 1.9.5 开始 2018-07-03 09:28:17 +08:00
Redkale
0e7fab71b8 2018-06-28 09:01:33 +08:00
Redkale
a106c8ed60 2018-06-26 16:35:12 +08:00
Redkale
ae52d0ab3d 2018-06-26 16:30:47 +08:00
Redkale
c993cd5b5a Json.writeChar以'A'形式输出 2018-06-25 19:38:32 +08:00
Redkale
9bdd83cc6e 2018-06-25 18:46:53 +08:00
Redkale
1b6a23c1a9 增加APP_CONF配置项,在启动脚本中可以指定配置目录 2018-06-22 16:38:24 +08:00
Redkale
2703d94b83 修复Convert中泛型与非泛型类型并存的问题 2018-06-20 15:58:10 +08:00
Redkale
4cb51ecbe6 2018-06-20 15:48:08 +08:00
Redkale
0cf64121ae 2018-06-12 16:52:09 +08:00
Redkale
58eb3c5d64 AsyncConnection.write调整 2018-06-12 09:15:32 +08:00
Redkale
3c645b4c7f 修复Rest部分情况下获取不到参数的BUG 2018-06-09 10:15:49 +08:00
Redkale
a540eed0ed Redkale 1.9.4 开始 2018-06-09 09:48:50 +08:00
93 changed files with 2506 additions and 3212 deletions

View File

@@ -1,9 +1,10 @@
handlers = java.util.logging.ConsoleHandler
# handlers = java.util.logging.FileHandler
############################################################
.level = FINER
.level = FINEST
java.level = INFO
javax.level = INFO
@@ -14,11 +15,11 @@ jdk.level = INFO
java.util.logging.FileHandler.level = FINER
#10M
java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 10000
java.util.logging.FileHandler.limit = 10M
java.util.logging.FileHandler.count = 20
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
java.util.logging.FileHandler.append = true
java.util.logging.ConsoleHandler.level = FINER
java.util.logging.ConsoleHandler.level = FINEST

View File

@@ -89,6 +89,8 @@ public final class ApiDocsService {
for (final Class rtype : action.results()) {
results.add(rtype.getName());
if (typesmap.containsKey(rtype.getName())) continue;
if(rtype.getName().startsWith("java.")) continue;
if(rtype.getName().startsWith("javax.")) continue;
final boolean filter = FilterBean.class.isAssignableFrom(rtype);
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = rtype;
@@ -136,6 +138,8 @@ public final class ApiDocsService {
paramsList.add(parammap);
if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesmap.containsKey(ptype.getName())) continue;
if(ptype.getName().startsWith("java.")) continue;
if(ptype.getName().startsWith("javax.")) continue;
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = ptype;
@@ -192,7 +196,7 @@ public final class ApiDocsService {
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
out.write(json.getBytes("UTF-8"));
out.close();
File doctemplate = new File(app.getHome(), "conf/apidoc-template.html");
File doctemplate = new File(app.getConf(), "apidoc-template.html");
InputStream in = null;
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);

View File

@@ -61,6 +61,11 @@ public final class Application {
*/
public static final String RESNAME_APP_HOME = "APP_HOME";
/**
* 当前进程的配置目录如果不是绝对路径则视为HOME目录下的相对路径 类型String、File、Path
*/
public static final String RESNAME_APP_CONF = "APP_CONF";
/**
* application.xml 文件中resources节点的内容 类型: AnyValue
*/
@@ -137,6 +142,9 @@ public final class Application {
//进程根目录
private final File home;
//配置文件目录
private final File conf;
//日志
private final Logger logger;
@@ -162,6 +170,8 @@ public final class Application {
private Application(final boolean singletonrun, final AnyValue config) {
this.singletonrun = singletonrun;
this.config = config;
System.setProperty("redkale.version", Redkale.getDotedVersion());
System.setProperty("sun.nio.ch.maxCompletionHandlersOnStack", String.valueOf(Math.max(256, Runtime.getRuntime().availableProcessors() * 8)));
final File root = new File(System.getProperty(RESNAME_APP_HOME));
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
@@ -170,6 +180,12 @@ public final class Application {
try {
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
this.home = root.getCanonicalFile();
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
this.conf = new File(confsubpath).getCanonicalFile();
} else {
this.conf = new File(this.home, confsubpath).getCanonicalFile();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -194,7 +210,7 @@ public final class Application {
System.setProperty(RESNAME_APP_NODE, node);
}
//以下是初始化日志配置
final File logconf = new File(root, "conf/logging.properties");
final File logconf = new File(conf, "logging.properties");
if (logconf.isFile() && logconf.canRead()) {
try {
final String rootpath = root.getCanonicalPath().replace('\\', '/');
@@ -348,10 +364,22 @@ public final class Application {
return new ArrayList<>(servers);
}
public List<DataSource> getDataSources() {
return new ArrayList<>(dataSources);
}
public List<CacheSource> getCacheSources() {
return new ArrayList<>(cacheSources);
}
public File getHome() {
return home;
}
public File getConf() {
return conf;
}
public long getStartTime() {
return startTime;
}
@@ -361,7 +389,6 @@ public final class Application {
}
public void init() throws Exception {
System.setProperty("sun.nio.ch.internalThreadPoolSize", "" + Runtime.getRuntime().availableProcessors() * 4);
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + Runtime.getRuntime().availableProcessors() * 4);
System.setProperty("net.transport.poolmaxconns", "100");
System.setProperty("net.transport.pinginterval", "30");
@@ -373,12 +400,13 @@ public final class Application {
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
System.setProperty("convert.json.writer.buffer.defsize", "4096");
File persist = new File(this.home, "conf/persistence.xml");
File persist = new File(this.conf, "persistence.xml");
final String homepath = this.home.getCanonicalPath();
final String confpath = this.conf.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
logger.log(Level.INFO, "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath);
logger.log(Level.INFO, "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath + "\r\n" + RESNAME_APP_CONF + " = " + confpath);
String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
lib = lib.isEmpty() ? confpath : (lib + ";" + confpath);
Server.loadLib(classLoader, logger, lib);
//------------------------------------------------------------------------
@@ -391,7 +419,7 @@ public final class Application {
if (dfloads != null) {
for (String dfload : dfloads.split(";")) {
if (dfload.trim().isEmpty()) continue;
final File df = (dfload.indexOf('/') < 0) ? new File(home, "conf/" + dfload) : new File(dfload);
final File df = (dfload.indexOf('/') < 0) ? new File(conf, "/" + dfload) : new File(dfload);
if (df.isFile()) {
Properties ps = new Properties();
InputStream in = new FileInputStream(df);
@@ -524,8 +552,8 @@ public final class Application {
public void restoreConfig() throws IOException {
synchronized (this) {
File confFile = new File(this.home, "conf/application.xml");
confFile.renameTo(new File(this.home, "conf/application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
File confFile = new File(this.conf, "application.xml");
confFile.renameTo(new File(this.conf, "application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
ps.append(config.toXML("application"));
ps.close();
@@ -653,19 +681,21 @@ public final class Application {
runServers(timecd, watchs); //必须在所有服务都启动后再启动WATCH服务
timecd.await();
//if (!singletonrun) signalHandle();
if (!singletonrun) clearPersistData();
//if (!singletonrun) clearPersistData();
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n");
if (!singletonrun) this.serversLatch.await();
}
private void clearPersistData() {
File cachedir = new File(home, "cache");
if (!cachedir.isDirectory()) return;
for (File file : cachedir.listFiles()) {
if (file.getName().startsWith("persist-")) file.delete();
}
}
// private void clearPersistData() {
// File cachedir = new File(home, "cache");
// if (!cachedir.isDirectory()) return;
// File[] lfs = cachedir.listFiles();
// if (lfs != null) {
// for (File file : lfs) {
// if (file.getName().startsWith("persist-")) file.delete();
// }
// }
// }
// private void signalHandle() {
// //http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html
// String[] sigs = new String[]{"HUP", "TERM", "INT", "QUIT", "KILL", "TSTP", "USR1", "USR2", "STOP"};
@@ -796,8 +826,15 @@ public final class Application {
public static Application create(final boolean singleton) throws IOException {
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
System.setProperty(RESNAME_APP_HOME, home);
File appfile = new File(home, "conf/application.xml");
return new Application(singleton, load(new FileInputStream(appfile)));
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
File appfile;
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
appfile = new File(confsubpath).getCanonicalFile();
} else {
appfile = new File(new File(home), confsubpath);
}
File appconf = new File(appfile, "application.xml");
return new Application(singleton, load(new FileInputStream(appconf)));
}
public static void main(String[] args) throws Exception {

View File

@@ -550,7 +550,9 @@ public final class ClassFilter<T> {
files.add(root);
} else if (root.isDirectory()) {
if (exclude != null && exclude.equals(root)) return;
for (File f : root.listFiles()) {
File[] lfs = root.listFiles();
if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()");
for (File f : lfs) {
loadClassFiles(exclude, f, files);
}
}

View File

@@ -241,7 +241,21 @@ public class LogFileHandler extends Handler {
}
String limitstr = manager.getProperty(cname + ".limit");
try {
if (limitstr != null) this.limit = Math.abs(Integer.decode(limitstr));
if (limitstr != null) {
limitstr = limitstr.toUpperCase();
boolean g = limitstr.indexOf('G') > 0;
boolean m = limitstr.indexOf('M') > 0;
boolean k = limitstr.indexOf('K') > 0;
int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", "")));
if (g) {
ls *= 1024 * 1024 * 1024;
} else if (m) {
ls *= 1024 * 1024;
} else if (k) {
ls *= 1024;
}
this.limit = ls;
}
} catch (Exception e) {
}
String countstr = manager.getProperty(cname + ".count");

View File

@@ -41,7 +41,7 @@
html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>');
html.push('<td class="s">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
html.push('<td class="s" style="width:80px;">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
var paramshtml = [];
paramshtml.push('<table class="subtable">');
for (var p = 0; p < action.params.length; p++) {

View File

@@ -6,6 +6,7 @@
package org.redkale.boot.watch;
import org.redkale.service.AbstractService;
import org.redkale.util.Comment;
import org.redkale.watch.WatchService;
/**
@@ -14,4 +15,9 @@ import org.redkale.watch.WatchService;
*/
public abstract class AbstractWatchService extends AbstractService implements WatchService {
@Comment("缺少参数")
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
@Comment("执行异常")
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
}

View File

@@ -33,7 +33,7 @@ public class FilterWatchService extends AbstractWatchService {
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
@Resource
private Application application;
protected Application application;
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
@@ -47,4 +47,34 @@ public class FilterWatchService extends AbstractWatchService {
}
return RetResult.success();
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
@RestMapping(name = "test5", auth = false, comment = "预留")
public RetResult test5() {
return RetResult.success();
}
@RestMapping(name = "test6", auth = false, comment = "预留")
public RetResult test6() {
return RetResult.success();
}
}

View File

@@ -24,7 +24,7 @@ public class ServerWatchService extends AbstractWatchService {
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
@Resource
private Application application;
protected Application application;
@RestMapping(name = "info", comment = "单个Server信息查询")
public RetResult info(@RestParam(name = "#port:") int port) {

View File

@@ -5,10 +5,14 @@
*/
package org.redkale.boot.watch;
import java.lang.reflect.*;
import java.util.*;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.boot.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.*;
/**
* <p>
@@ -19,21 +23,173 @@ import org.redkale.net.http.*;
@RestService(name = "service", catalog = "watch", repair = false)
public class ServiceWatchService extends AbstractWatchService {
@Resource
private Application application;
@Comment("没有找到目标Service")
public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001;
@Resource
private TransportFactory transportFactory;
protected Application application;
// @RestMapping(name = "load", auth = false, comment = "动态增加Service")
// public RetResult loadService(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
// //待开发
// return RetResult.success();
// }
//
// @RestMapping(name = "stop", auth = false, comment = "动态停止Service")
// public RetResult stopService(String name, String type) {
// //待开发
// return RetResult.success();
// }
@RestConvert(type = void.class)
@RestMapping(name = "setfield", auth = false, comment = "设置Service中指定字段的内容")
public RetResult setfield(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field,
@RestParam(name = "value", comment = "字段值") String value) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
try {
Field fieldObj = null;
do {
try {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
fieldObj.setAccessible(true);
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
return RetResult.success();
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
@RestConvert(type = void.class)
@RestMapping(name = "getfield", auth = false, comment = "查询Service中指定字段的内容")
public RetResult getfield(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
try {
Field fieldObj = null;
do {
try {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
fieldObj.setAccessible(true);
return new RetResult(fieldObj.get(dest));
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
@RestConvert(type = void.class)
@RestMapping(name = "runmethod", auth = false, comment = "调用Service中指定方法")
public RetResult runmethod(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "method", comment = "Service的方法名") String method,
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
if (name == null) name = "";
if (type == null) type = "";
if (method == null) method = "";
type = type.trim();
method = method.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (method.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
final int paramcount = params == null ? 0 : params.size();
if (paramtypes != null && paramcount != paramtypes.size()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
try {
Method methodObj = null;
do {
try {
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equals(method) && m.getParameterCount() == paramcount) {
boolean flag = true;
if (paramtypes != null) {
Class[] pts = m.getParameterTypes();
for (int i = 0; i < pts.length; i++) {
if (!pts[i].getName().endsWith(paramtypes.get(i))) {
flag = false;
break;
}
}
}
if (flag) {
methodObj = m;
break;
}
}
}
if (methodObj != null) break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (methodObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")");
methodObj.setAccessible(true);
if (paramcount < 1) return new RetResult(methodObj.invoke(dest));
Object[] paramObjs = new Object[paramcount];
Type[] pts = methodObj.getGenericParameterTypes();
for (int i = 0; i < paramObjs.length; i++) {
paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i));
}
return new RetResult(methodObj.invoke(dest, paramObjs));
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
protected Object findService(String name, String type) {
Object dest = null;
for (NodeServer ns : application.getNodeServers()) {
ResourceFactory resFactory = ns.getResourceFactory();
List list = resFactory.query((n, s) -> name.equals(n) && s != null && s.getClass().getName().endsWith(type));
if (list == null || list.isEmpty()) continue;
dest = list.get(0);
}
if (dest == null) return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
return dest;
}
@RestMapping(name = "load", auth = false, comment = "动态增加Service")
public RetResult loadService(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
//待开发
return RetResult.success();
}
@RestMapping(name = "reload", auth = false, comment = "重新加载Service")
public RetResult reloadService(String name, String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "stop", auth = false, comment = "动态停止Service")
public RetResult stopService(String name, String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "find", auth = false, comment = "查找Service")
public RetResult find(String name, String type) {
//待开发
return RetResult.success();
}
}

View File

@@ -20,10 +20,10 @@ import org.redkale.net.http.*;
public class ServletWatchService extends AbstractWatchService {
@Resource
private Application application;
protected Application application;
@Resource
private TransportFactory transportFactory;
protected TransportFactory transportFactory;
//
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {

View File

@@ -5,10 +5,15 @@
*/
package org.redkale.boot.watch;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.net.http.RestService;
import org.redkale.net.http.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
*
@@ -17,10 +22,58 @@ import org.redkale.net.http.RestService;
@RestService(name = "source", catalog = "watch", repair = false)
public class SourceWatchService extends AbstractWatchService {
@Resource
private Application application;
@Comment("不存在的Source")
public static final int RET_SOURCE_NOT_EXISTS = 1605_0001;
@Comment("Source不支持getReadPoolSource/getWritePoolSource方法")
public static final int RET_SOURCE_CHANGE_METHOD_NOT_EXISTS = 1605_0002;
@Comment("PoolSource调用change方法失败")
public static final int RET_SOURCE_METHOD_INVOKE_NOT_EXISTS = 1605_0003;
@Resource
private TransportFactory transportFactory;
protected Application application;
@RestMapping(name = "change", auth = false, comment = "动态更改DataSource的配置")
public RetResult addNode(@RestParam(name = "name", comment = "DataSource的标识") final String name,
@RestParam(name = "properties", comment = "配置") final Properties properties) throws IOException {
if (name == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (name)");
if (properties == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (properties)");
DataSource source = null;
for (DataSource s : application.getDataSources()) {
String resName = ((Resourcable) s).resourceName();
if (resName == null) continue;
if (!resName.equals(name)) continue;
source = s;
break;
}
if (source == null) return new RetResult(RET_SOURCE_NOT_EXISTS, "not found source (name = " + name + ")");
Method readPoolMethod = null;
Method writePoolMethod = null;
Class stype = source.getClass();
do {
for (Method m : stype.getDeclaredMethods()) {
if (!PoolSource.class.isAssignableFrom(m.getReturnType())) continue;
if (m.getParameterCount() != 0) continue;
if (m.getName().equals("getReadPoolSource")) {
readPoolMethod = m;
} else if (m.getName().equals("getWritePoolSource")) {
writePoolMethod = m;
}
}
} while ((stype = stype.getSuperclass()) != Object.class);
if (readPoolMethod == null) return new RetResult(RET_SOURCE_CHANGE_METHOD_NOT_EXISTS, "not found source method(getReadPoolSource)");
if (writePoolMethod == null) return new RetResult(RET_SOURCE_CHANGE_METHOD_NOT_EXISTS, "not found source method(getWritePoolSource)");
readPoolMethod.setAccessible(true);
writePoolMethod.setAccessible(true);
try {
PoolSource readPoolSource = (PoolSource) readPoolMethod.invoke(source);
PoolSource writePoolSource = (PoolSource) writePoolMethod.invoke(source);
readPoolSource.change(properties);
writePoolSource.change(properties);
return RetResult.success();
} catch (Exception e) {
return new RetResult(RET_SOURCE_METHOD_INVOKE_NOT_EXISTS, "poolsource invoke method('change') error");
}
}
}

View File

@@ -36,10 +36,10 @@ public class TransportWatchService extends AbstractWatchService {
public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003;
@Resource
private Application application;
protected Application application;
@Resource
private TransportFactory transportFactory;
protected TransportFactory transportFactory;
@RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点")
public List<TransportGroupInfo> listNodes() {
@@ -135,4 +135,24 @@ public class TransportWatchService extends AbstractWatchService {
}
return RetResult.success();
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
}

View File

@@ -42,16 +42,17 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
out.writeNull();
} else {
int count = values.length - values.length % 2;
out.writeMapB(count / 2);
for (int i = 0; i < count; i += 2) {
if (i > 0) out.writeArrayMark();
this.convertTo(out, (T) values[i]);
out.writeMapMark();
Object val = values[i + 1];
if (val instanceof CompletableFuture) {
this.convertTo(out, (T) ((CompletableFuture) val).join());
} else {
this.convertTo(out, (T) val);
if (out.writeMapB(count / 2, (Encodeable) this, (Encodeable) this, values) < 0) {
for (int i = 0; i < count; i += 2) {
if (i > 0) out.writeArrayMark();
this.convertTo(out, (T) values[i]);
out.writeMapMark();
Object val = values[i + 1];
if (val instanceof CompletableFuture) {
this.convertTo(out, (T) ((CompletableFuture) val).join());
} else {
this.convertTo(out, (T) val);
}
}
}
out.writeMapE();

View File

@@ -20,19 +20,19 @@ import java.util.*;
* @param <T> 反解析的数组元素类型
*/
@SuppressWarnings("unchecked")
public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
private final Class componentClass;
protected final Class componentClass;
protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -62,8 +62,17 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
@Override
public T[] convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public T[] convertFrom(Reader in, DeMember member) {
int len = in.readArrayB(member, decoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, decoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -77,9 +86,14 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final List<T> result = new ArrayList();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -91,6 +105,18 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
return result.toArray(rs);
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, boolean first) {
return this.decoder.convertFrom(in);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
@@ -101,4 +127,12 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getDecoder() {
return decoder;
}
}

View File

@@ -19,19 +19,19 @@ import java.lang.reflect.*;
* @param <T> 序列化的数组元素类型
*/
@SuppressWarnings("unchecked")
public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
private final Encodeable anyEncoder;
protected final Encodeable anyEncoder;
private final Encodeable<Writer, Object> encoder;
protected final Encodeable<Writer, Object> encoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -57,12 +57,16 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
@Override
public void convertTo(Writer out, T[] value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, T[] value) {
if (value == null) {
out.writeNull();
return;
}
if (value.length == 0) {
out.writeArrayB(0);
out.writeArrayB(0, encoder, value);
out.writeArrayE();
return;
}
@@ -77,17 +81,22 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
}
}
}
out.writeArrayB(value.length);
final Type comp = this.componentType;
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
((v != null && v.getClass() == comp) ? encoder : anyEncoder).convertTo(out, v);
if (first) first = false;
if (out.writeArrayB(value.length, encoder, value) < 0) {
final Type comp = this.componentType;
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? encoder : anyEncoder), v, first);
if (first) first = false;
}
}
out.writeArrayE();
}
protected void writeMemberValue(Writer out, EnMember member, Encodeable<Writer, Object> encoder, Object value, boolean first) {
encoder.convertTo(out, value);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.encoder + "}";
@@ -97,4 +106,13 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Encodeable<Writer, Object> getEncoder() {
return encoder;
}
}

View File

@@ -21,19 +21,19 @@ import java.util.Collection;
* @param <T> 反解析的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
protected Creator<Collection<T>> creator;
protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -44,7 +44,7 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else if(factory.isReversible()){
} else if (factory.isReversible()) {
this.componentType = Object.class;
this.creator = factory.loadCreator(Object.class);
factory.register(type, this);
@@ -62,8 +62,17 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
@Override
public Collection<T> convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public Collection<T> convertFrom(Reader in, DeMember member) {
int len = in.readArrayB(member, decoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, decoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -77,9 +86,14 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final Collection<T> result = this.creator.create();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -90,9 +104,29 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
return result;
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, boolean first) {
return this.decoder.convertFrom(in);
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getDecoder() {
return decoder;
}
}

View File

@@ -19,15 +19,15 @@ import java.util.Collection;
* @param <T> 序列化的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
private final Type type;
protected final Type type;
private final Encodeable<Writer, Object> encoder;
protected final Encodeable<Writer, Object> encoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -52,12 +52,16 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
@Override
public void convertTo(Writer out, Collection<T> value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, Collection<T> value) {
if (value == null) {
out.writeNull();
return;
}
if (value.isEmpty()) {
out.writeArrayB(0);
out.writeArrayB(0, encoder, value);
out.writeArrayE();
return;
}
@@ -72,18 +76,28 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
}
}
}
out.writeArrayB(value.size());
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
encoder.convertTo(out, v);
if (first) first = false;
if (out.writeArrayB(value.size(), encoder, value) < 0) {
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
writeValue(out, member, v);
if (first) first = false;
}
}
out.writeArrayE();
}
protected void writeValue(Writer out, EnMember member, Object value) {
encoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, Object> getEncoder() {
return encoder;
}
}

View File

@@ -139,10 +139,56 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public abstract boolean isReversible(); //是否可逆的
public abstract boolean isFieldSort(); //当ConvertColumn.index相同时是否按字段名称排序
public abstract ConvertFactory createChild();
public abstract ConvertFactory createChild(boolean tiny);
protected SimpledCoder createEnumSimpledCoder(Class enumClass) {
return new EnumSimpledCoder(enumClass);
}
protected ObjectDecoder createObjectDecoder(Type type) {
return new ObjectDecoder(type);
}
protected ObjectEncoder createObjectEncoder(Type type) {
return new ObjectEncoder(type);
}
protected <E> Decodeable<R, E> createMapDecoder(Type type) {
return new MapDecoder(this, type);
}
protected <E> Encodeable<W, E> createMapEncoder(Type type) {
return new MapEncoder(this, type);
}
protected <E> Decodeable<R, E> createArrayDecoder(Type type) {
return new ArrayDecoder(this, type);
}
protected <E> Encodeable<W, E> createArrayEncoder(Type type) {
return new ArrayEncoder(this, type);
}
protected <E> Decodeable<R, E> createCollectionDecoder(Type type) {
return new CollectionDecoder(this, type);
}
protected <E> Encodeable<W, E> createCollectionEncoder(Type type) {
return new CollectionEncoder(this, type);
}
protected <E> Decodeable<R, E> createStreamDecoder(Type type) {
return new StreamDecoder(this, type);
}
protected <E> Encodeable<W, E> createStreamEncoder(Type type) {
return new StreamEncoder(this, type);
}
public Convert getConvert() {
return convert;
}
@@ -464,7 +510,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public final <E> Decodeable<R, E> loadDecoder(final Type type) {
Decodeable<R, E> decoder = findDecoder(type);
if (decoder != null) return decoder;
if (type instanceof GenericArrayType) return new ArrayDecoder(this, type);
if (type instanceof GenericArrayType) return createArrayDecoder(type);
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
@@ -496,8 +542,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} else {
throw new ConvertException("not support the type (" + type + ")");
}
decoder = findDecoder(clazz);
if (decoder != null) return decoder;
//此处不能再findDecoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createDecoder(type, clazz);
}
@@ -518,19 +563,19 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
Decodeable<R, E> decoder = null;
ObjectDecoder od = null;
if (clazz.isEnum()) {
decoder = new EnumSimpledCoder(clazz);
decoder = createEnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
decoder = new ArrayDecoder(this, type);
decoder = createArrayDecoder(type);
} else if (Collection.class.isAssignableFrom(clazz)) {
decoder = new CollectionDecoder(this, type);
decoder = createCollectionDecoder(type);
} else if (Stream.class.isAssignableFrom(clazz)) {
decoder = new StreamDecoder(this, type);
decoder = createStreamDecoder(type);
} else if (Map.class.isAssignableFrom(clazz)) {
decoder = new MapDecoder(this, type);
decoder = createMapDecoder(type);
} else if (Optional.class == clazz) {
decoder = new OptionalCoder(this, type);
} else if (clazz == Object.class) {
od = new ObjectDecoder(type);
od = createObjectDecoder(type);
decoder = od;
} else if (!clazz.getName().startsWith("java.")
|| java.net.HttpCookie.class == clazz
@@ -550,7 +595,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
}
}
if (simpleCoder == null) {
od = new ObjectDecoder(type);
od = createObjectDecoder(type);
decoder = od;
} else {
decoder = simpleCoder;
@@ -565,7 +610,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public final <E> Encodeable<W, E> loadEncoder(final Type type) {
Encodeable<W, E> encoder = findEncoder(type);
if (encoder != null) return encoder;
if (type instanceof GenericArrayType) return new ArrayEncoder(this, type);
if (type instanceof GenericArrayType) return createArrayEncoder(type);
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
@@ -583,8 +628,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} else {
throw new ConvertException("not support the type (" + type + ")");
}
encoder = findEncoder(clazz);
if (encoder != null) return encoder;
//此处不能再findEncoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createEncoder(type, clazz);
}
@@ -605,15 +649,15 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
Encodeable<W, E> encoder = null;
ObjectEncoder oe = null;
if (clazz.isEnum()) {
encoder = new EnumSimpledCoder(clazz);
encoder = createEnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
encoder = new ArrayEncoder(this, type);
encoder = createArrayEncoder(type);
} else if (Collection.class.isAssignableFrom(clazz)) {
encoder = new CollectionEncoder(this, type);
encoder = createCollectionEncoder(type);
} else if (Stream.class.isAssignableFrom(clazz)) {
encoder = new StreamEncoder(this, type);
encoder = createStreamEncoder(type);
} else if (Map.class.isAssignableFrom(clazz)) {
encoder = new MapEncoder(this, type);
encoder = createMapEncoder(type);
} else if (Optional.class == clazz) {
encoder = new OptionalCoder(this, type);
} else if (clazz == Object.class) {
@@ -634,7 +678,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
}
}
if (simpleCoder == null) {
oe = new ObjectEncoder(type);
oe = createObjectEncoder(type);
encoder = oe;
} else {
encoder = simpleCoder;

View File

@@ -20,10 +20,12 @@ import org.redkale.util.Attribute;
* @param <F> 字段的数据类型
*/
@SuppressWarnings("unchecked")
public final class DeMember<R extends Reader, T, F> implements Comparable<DeMember<R, T, F>> {
public final class DeMember<R extends Reader, T, F> {
protected int index;
protected int position; //从1开始
protected final Attribute<T, F> attribute;
protected Decodeable<R, F> decoder;
@@ -70,15 +72,23 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
return this.attribute;
}
public Decodeable<R, F> getDecoder() {
return decoder;
}
public int getIndex() {
return this.index;
}
@Override
public final int compareTo(DeMember<R, T, F> o) {
public int getPosition() {
return this.position;
}
public int compareTo(boolean fieldSort, DeMember<R, T, F> o) {
if (o == null) return -1;
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
return this.attribute.field().compareTo(o.attribute.field());
if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0;
}
@Override
@@ -86,7 +96,7 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
if (this == obj) return true;
if (!(obj instanceof DeMember)) return false;
DeMember other = (DeMember) obj;
return compareTo(other) == 0;
return compareTo(true, other) == 0;
}
@Override

View File

@@ -20,7 +20,7 @@ import org.redkale.util.Attribute;
* @param <F> 字段的数据类型
*/
@SuppressWarnings("unchecked")
public final class EnMember<W extends Writer, T, F> implements Comparable<EnMember<W, T, F>> {
public final class EnMember<W extends Writer, T, F> {
final Attribute<T, F> attribute;
@@ -33,6 +33,8 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
protected int index;
protected int position; //从1开始
public EnMember(Attribute<T, F> attribute, Encodeable<W, F> encoder) {
this.attribute = attribute;
this.encoder = encoder;
@@ -63,15 +65,35 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
return attribute.field().equals(name);
}
public Attribute<T, F> getAttribute() {
return attribute;
}
public Encodeable<W, F> getEncoder() {
return encoder;
}
public boolean isStringType() {
return istring;
}
public boolean isBoolType() {
return isbool;
}
public int getIndex() {
return this.index;
}
@Override
public final int compareTo(EnMember<W, T, F> o) {
public int getPosition() {
return this.position;
}
public int compareTo(boolean fieldSort, EnMember<W, T, F> o) {
if (o == null) return -1;
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
return this.attribute.field().compareTo(o.attribute.field());
if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0;
}
@Override
@@ -79,7 +101,7 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
if (this == obj) return true;
if (!(obj instanceof EnMember)) return false;
EnMember other = (EnMember) obj;
return compareTo(other) == 0;
return compareTo(true, other) == 0;
}
@Override

View File

@@ -21,13 +21,13 @@ import java.util.Map;
* @param <V> Map value的数据类型
*/
@SuppressWarnings("unchecked")
public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
private final Type type;
protected final Type type;
private final Type keyType;
protected final Type keyType;
private final Type valueType;
protected final Type valueType;
protected Creator<Map<K, V>> creator;
@@ -35,14 +35,21 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
protected final Decodeable<Reader, V> valueDecoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public MapDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {
if (type instanceof ParameterizedType) {
if (type == java.util.Properties.class) {
this.keyType = String.class;
this.valueType = String.class;
this.creator = factory.loadCreator(java.util.Properties.class);
factory.register(type, this);
this.keyDecoder = factory.loadDecoder(String.class);
this.valueDecoder = factory.loadDecoder(String.class);
} else if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.keyType = pt.getActualTypeArguments()[0];
this.valueType = pt.getActualTypeArguments()[1];
@@ -69,6 +76,10 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
@Override
public Map<K, V> convertFrom(Reader in) {
return convertFrom(in, null);
}
public Map<K, V> convertFrom(Reader in, DeMember member) {
if (this.keyDecoder == null || this.valueDecoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -80,31 +91,74 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
}
}
}
final int len = in.readMapB();
int len = in.readMapB(member, this.keyDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, null);
len = Reader.SIGN_NOLENGTH;
}
final Map<K, V> result = this.creator.create();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
K key = keyDecoder.convertFrom(in);
in.readBlank();
V value = valueDecoder.convertFrom(in);
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader entryReader = getEntryReader(in, member, first);
if (entryReader == null) break;
K key = readKeyMember(entryReader, member, first);
entryReader.readBlank();
V value = readValueMember(entryReader, member, first);
result.put(key, value);
first = false;
}
} else {
for (int i = 0; i < len; i++) {
K key = keyDecoder.convertFrom(in);
K key = readKeyMember(in, member, first);
in.readBlank();
V value = valueDecoder.convertFrom(in);
V value = readValueMember(in, member, first);
result.put(key, value);
first = false;
}
}
in.readMapE();
return result;
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Reader getEntryReader(Reader in, DeMember member, boolean first) {
return in;
}
protected K readKeyMember(Reader in, DeMember member, boolean first) {
return keyDecoder.convertFrom(in);
}
protected V readValueMember(Reader in, DeMember member, boolean first) {
return valueDecoder.convertFrom(in);
}
@Override
public Type getType() {
return this.type;
}
public Type getKeyType() {
return keyType;
}
public Type getValueType() {
return valueType;
}
public Decodeable<Reader, K> getKeyDecoder() {
return keyDecoder;
}
public Decodeable<Reader, V> getValueDecoder() {
return valueDecoder;
}
}

View File

@@ -20,17 +20,17 @@ import java.util.Map;
* @param <V> Map value的数据类型
*/
@SuppressWarnings("unchecked")
public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
private final Type type;
protected final Type type;
private final Encodeable<Writer, K> keyencoder;
protected final Encodeable<Writer, K> keyencoder;
private final Encodeable<Writer, V> valencoder;
protected final Encodeable<Writer, V> valencoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public MapEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -53,6 +53,10 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
@Override
public void convertTo(Writer out, Map<K, V> value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, Map<K, V> value) {
final Map<K, V> values = value;
if (values == null) {
out.writeNull();
@@ -70,20 +74,34 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
}
}
}
out.writeMapB(values.size());
boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) {
if (!first) out.writeArrayMark();
this.keyencoder.convertTo(out, en.getKey());
out.writeMapMark();
this.valencoder.convertTo(out, en.getValue());
if (first) first = false;
if (out.writeMapB(values.size(), (Encodeable) keyencoder, (Encodeable) valencoder, value) < 0) {
boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, en.getKey(), en.getValue(),first);
if (first) first = false;
}
}
out.writeMapE();
}
protected void writeMemberValue(Writer out, EnMember member, K key, V value,boolean first) {
keyencoder.convertTo(out, key);
out.writeMapMark();
valencoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, K> getKeyencoder() {
return keyencoder;
}
public Encodeable<Writer, V> getValencoder() {
return valencoder;
}
}

View File

@@ -7,9 +7,7 @@ package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import org.redkale.util.*;
/**
@@ -23,7 +21,7 @@ import org.redkale.util.*;
* @param <T> 反解析的数据类型
*/
@SuppressWarnings("unchecked")
public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
protected final Type type;
@@ -33,13 +31,13 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
protected DeMember<R, T, ?>[] creatorConstructorMembers = new DeMember[0];
protected DeMember<R, T, ?>[] members;
protected DeMember[] members;
protected ConvertFactory factory;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
protected ObjectDecoder(Type type) {
this.type = ((type instanceof Class) && ((Class) type).isInterface()) ? Object.class : type;
@@ -86,7 +84,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
}
final Set<DeMember> list = new HashSet();
final Set<DeMember> list = new LinkedHashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
try {
ConvertColumnEntry ref;
@@ -156,7 +154,20 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
}
this.members = list.toArray(new DeMember[list.size()]);
Arrays.sort(this.members);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
Set<Integer> pos = new HashSet<>();
for (int i = 0; i < this.members.length; i++) {
if (this.members[i].index > 0) pos.add(this.members[i].index);
}
int pidx = 0;
for (DeMember member : this.members) {
if (member.index > 0) {
member.position = member.index;
} else {
while (pos.contains(++pidx));
member.position = pidx;
}
}
if (cps != null) {
final String[] fields = cps;
@@ -190,7 +201,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
* @return 反解析后的对象结果
*/
@Override
public final T convertFrom(final R in) {
public T convertFrom(final R in) {
final String clazz = in.readObjectB(typeClass);
if (clazz == null) return null;
if (!clazz.isEmpty()) return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(in);
@@ -210,14 +221,16 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
if (this.creatorConstructorMembers == null) { //空构造函数
final T result = this.creator.create();
while (in.hasNext()) {
boolean first = true;
while (hasNext(in, first)) {
DeMember member = in.readFieldName(members);
in.readBlank();
if (member == null) {
in.skipValue(); //跳过不存在的属性的值
} else {
member.read(in, result);
readMemberValue(in, member, result, first);
}
first = false;
}
in.readObjectE(typeClass);
return result;
@@ -226,13 +239,14 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
final Object[] constructorParams = new Object[fields.length];
final Object[][] otherParams = new Object[this.members.length][2];
int oc = 0;
while (in.hasNext()) {
boolean first = true;
while (hasNext(in, first)) {
DeMember member = in.readFieldName(members);
in.readBlank();
if (member == null) {
in.skipValue(); //跳过不存在的属性的值
} else {
Object val = member.read(in);
Object val = readMemberValue(in, member, first);
boolean flag = true;
for (int i = 0; i < fields.length; i++) {
if (member == fields[i]) {
@@ -242,7 +256,9 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
}
if (flag) otherParams[oc++] = new Object[]{member.attribute, val};
}
first = false;
}
in.readObjectE(typeClass);
final T result = this.creator.create(constructorParams);
@@ -253,11 +269,27 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
}
protected boolean hasNext(R in, boolean first) {
return in.hasNext();
}
protected Object readMemberValue(R in, DeMember member, boolean first) {
return member.read(in);
}
protected void readMemberValue(R in, DeMember member, T result, boolean first) {
member.read(in, result);
}
@Override
public final Type getType() {
public Type getType() {
return this.type;
}
public DeMember[] getMembers() {
return Arrays.copyOf(members, members.length);
}
@Override
public String toString() {
return "ObjectDecoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';

View File

@@ -20,7 +20,7 @@ import org.redkale.util.*;
* @param <T> 序列化的数据类型
*/
@SuppressWarnings("unchecked")
public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
static final Type[] TYPEZERO = new Type[0];
@@ -32,9 +32,9 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
protected ConvertFactory factory;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
protected ObjectEncoder(Type type) {
this.type = type;
@@ -61,7 +61,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (type == Object.class) return;
//if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class");
final Class clazz = this.typeClass;
final Set<EnMember> list = new HashSet();
final Set<EnMember> list = new LinkedHashSet();
final boolean reversible = factory.isReversible();
Creator creator = null;
try {
@@ -108,7 +108,20 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
list.add(member);
}
this.members = list.toArray(new EnMember[list.size()]);
Arrays.sort(this.members);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
Set<Integer> pos = new HashSet<>();
for (int i = 0; i < this.members.length; i++) {
if (this.members[i].index > 0) pos.add(this.members[i].index);
}
int pidx = 0;
for (EnMember member : this.members) {
if (member.index > 0) {
member.position = member.index;
} else {
while (pos.contains(++pidx));
member.position = pidx;
}
}
} catch (Exception ex) {
throw new ConvertException(ex);
@@ -122,7 +135,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
@Override
public final void convertTo(W out, T value) {
public void convertTo(W out, T value) {
if (value == null) {
out.writeObjectNull(null);
return;
@@ -136,24 +149,29 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
}
}
if (value.getClass() != this.typeClass) {
if (value.getClass() != this.typeClass && !this.type.equals(out.specify())) {
final Class clz = value.getClass();
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clz));
factory.loadEncoder(clz).convertTo(out, value);
return;
}
out.writeObjectB(value);
for (EnMember member : members) {
out.writeObjectField(member, value);
if (out.writeObjectB(value) < 0) {
for (EnMember member : members) {
out.writeObjectField(member, value);
}
}
out.writeObjectE(value);
}
@Override
public final Type getType() {
public Type getType() {
return this.type;
}
public EnMember[] getMembers() {
return Arrays.copyOf(members, members.length);
}
@Override
public String toString() {
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';

View File

@@ -22,12 +22,46 @@ public abstract class Reader {
public static final short SIGN_NOLENGTH = -2;
public static final short SIGN_NOLENBUTBYTES = -3; //目前只适合于protobuf的boolean[]...double[]类型
/**
* 是否还存在下个元素或字段
* 是否还存在下个元素或字段 <br>
* 注意: 主要用于Array、Collection、Stream或Map等集合对象
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否还存在下个元素或字段
*/
public abstract boolean hasNext();
public abstract boolean hasNext(int startPosition, int contentLength);
/**
* 是否还存在下个元素或字段
*
*
* @return 是否还存在下个元素或字段
*/
public boolean hasNext() {
return hasNext(-1, -1);
}
/**
* 获取当前位置
*
* @return 当前位置
*/
public abstract int position();
/**
* 读取字段值内容的字节数 <br>
* 只有在readXXXB方法返回SIGN_NOLENBUTBYTES值才会调用此方法
*
* @param member DeMember
* @param decoder Decodeable
*
* @return 内容大小, 不确定返回-1
*/
public abstract int readMemberContentLength(DeMember member, Decodeable decoder);
/**
* 跳过值(不包含值前面的字段)
@@ -61,9 +95,12 @@ public abstract class Reader {
/**
* 读取数组的开头并返回数组的长度
*
* @param member DeMember
* @param decoder Decodeable
*
* @return 返回数组的长度
*/
public abstract int readArrayB();
public abstract int readArrayB(DeMember member, Decodeable decoder);
/**
* 读取数组的尾端
@@ -74,9 +111,12 @@ public abstract class Reader {
/**
* 读取map的开头并返回map的size
*
* @param member DeMember
* @param keydecoder Decodeable
*
* @return 返回map的size
*/
public abstract int readMapB();
public abstract int readMapB(DeMember member, Decodeable keydecoder);
/**
* 读取数组的尾端
@@ -107,6 +147,13 @@ public abstract class Reader {
*/
public abstract byte readByte();
/**
* 读取byte[]
*
* @return byte[]
*/
public abstract byte[] readByteArray();
/**
* 读取一个char值
*

View File

@@ -22,7 +22,7 @@ import java.lang.reflect.Type;
*/
public abstract class SimpledCoder<R extends Reader, W extends Writer, T> implements Decodeable<R, T>, Encodeable<W, T> {
private Type type;
protected Type type;
@Override
public abstract void convertTo(final W out, final T value);

View File

@@ -22,19 +22,19 @@ import java.util.stream.Stream;
* @param <T> 反解析的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
protected Creator<Stream<T>> creator;
protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public StreamDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -58,8 +58,17 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
@Override
public Stream<T> convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public Stream<T> convertFrom(Reader in, DeMember member) {
int len = in.readArrayB(member, this.decoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, this.decoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -73,9 +82,14 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final List<T> result = new ArrayList();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -86,9 +100,29 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
return result.stream();
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, boolean first) {
return this.decoder.convertFrom(in);
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getDecoder() {
return decoder;
}
}

View File

@@ -19,15 +19,15 @@ import java.util.stream.Stream;
* @param <T> 序列化的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
private final Type type;
protected final Type type;
private final Encodeable<Writer, Object> encoder;
protected final Encodeable<Writer, Object> encoder;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public StreamEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -52,13 +52,17 @@ public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
@Override
public void convertTo(Writer out, Stream<T> value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, Stream<T> value) {
if (value == null) {
out.writeNull();
return;
}
Object[] array = value.toArray();
if (array.length == 0) {
out.writeArrayB(0);
out.writeArrayB(0, encoder, array);
out.writeArrayE();
return;
}
@@ -73,18 +77,28 @@ public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
}
}
}
out.writeArrayB(array.length);
boolean first = true;
for (Object v : array) {
if (!first) out.writeArrayMark();
encoder.convertTo(out, v);
if (first) first = false;
if (out.writeArrayB(array.length, encoder, array) < 0) {
boolean first = true;
for (Object v : array) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, v, first);
if (first) first = false;
}
}
out.writeArrayE();
}
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
encoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, Object> getEncoder() {
return encoder;
}
}

View File

@@ -5,7 +5,7 @@
*/
package org.redkale.convert;
import org.redkale.util.Attribute;
import java.lang.reflect.*;
/**
* 序列化的数据输出流
@@ -20,6 +20,33 @@ public abstract class Writer {
//当前对象输出字段名之前是否需要分隔符, JSON字段间的分隔符为,逗号
protected boolean comma;
//convertTo时是否以指定Type的ObjectEncoder进行处理
protected Type specify;
/**
* 设置specify
*
* @param value Type
*/
public void specify(Type value) {
if (value instanceof GenericArrayType) {
this.specify = ((GenericArrayType) value).getGenericComponentType();
} else if (value instanceof Class && ((Class) value).isArray()) {
this.specify = ((Class) value).getComponentType();
} else {
this.specify = value;
}
}
/**
* 返回specify
*
* @return int
*/
public Type specify() {
return this.specify;
}
/**
* 当tiny=true时 字符串为空、boolean为false的字段值都会被跳过 不会输出。
*
@@ -51,9 +78,12 @@ public abstract class Writer {
* 注: 覆盖此方法必须要先调用父方法 super.writeObjectB(obj);
*
* @param obj 写入的对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
public void writeObjectB(Object obj) {
public int writeObjectB(Object obj) {
this.comma = false;
return -1;
}
/**
@@ -74,7 +104,7 @@ public abstract class Writer {
* @param obj 写入的对象
*/
@SuppressWarnings("unchecked")
public final void writeObjectField(final EnMember member, Object obj) {
public void writeObjectField(final EnMember member, Object obj) {
Object value = member.attribute.get(obj);
if (value == null) return;
if (tiny()) {
@@ -84,7 +114,7 @@ public abstract class Writer {
if (!((Boolean) value)) return;
}
}
this.writeFieldName(member.attribute);
this.writeFieldName(member);
member.encoder.convertTo(this, value);
this.comma = true;
}
@@ -99,9 +129,13 @@ public abstract class Writer {
/**
* 输出一个数组前的操作
*
* @param size 数组长度
* @param size 数组长度
* @param encoder Encodeable
* @param obj 对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
public abstract void writeArrayB(int size);
public abstract int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj);
/**
* 输出数组元素间的间隔符
@@ -118,9 +152,14 @@ public abstract class Writer {
/**
* 输出一个Map前的操作
*
* @param size map大小
* @param size map大小
* @param keyEncoder Encodeable
* @param valueEncoder Encodeable
* @param obj 对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
public abstract void writeMapB(int size);
public abstract int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj);
/**
* 输出一个Map中key与value间的间隔符
@@ -137,9 +176,9 @@ public abstract class Writer {
/**
* 输出一个字段名
*
* @param attribute 字段的Attribute对象
* @param member 字段的EnMember对象
*/
public abstract void writeFieldName(Attribute attribute);
public abstract void writeFieldName(EnMember member);
/**
* 写入一个boolean值
@@ -155,6 +194,13 @@ public abstract class Writer {
*/
public abstract void writeByte(byte value);
/**
* 写入byte[]
*
* @param values byte[]
*/
public abstract void writeByteArray(byte[] values);
/**
* 写入一个char值
*

View File

@@ -51,10 +51,12 @@ public class BsonByteBufferReader extends BsonReader {
/**
* 判断下一个非空白字节是否为[
*
* @param member DeMember
* @param decoder Decodeable
* @return 数组长度或 SIGN_NULL
*/
@Override
public final int readArrayB() {
public final int readArrayB(DeMember member, Decodeable decoder) {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
short lt = readShort();

View File

@@ -132,6 +132,7 @@ public class BsonByteBufferWriter extends BsonWriter {
@Override
protected boolean recycle() {
this.index = 0;
this.specify = null;
this.buffers = null;
return false;
}

View File

@@ -84,4 +84,9 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
return true;
}
@Override
public boolean isFieldSort() {
return true;
}
}

View File

@@ -171,8 +171,8 @@ public class BsonReader extends Reader {
}
@Override
public final int readMapB() {
return readArrayB();
public final int readMapB(DeMember member, Decodeable keydecoder) {
return readArrayB(member, keydecoder);
}
@Override
@@ -185,7 +185,7 @@ public class BsonReader extends Reader {
* @return 数组长度或SIGN_NULL
*/
@Override
public int readArrayB() {
public int readArrayB(DeMember member, Decodeable decoder) {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
return (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
@@ -202,13 +202,26 @@ public class BsonReader extends Reader {
public final void readBlank() {
}
@Override
public int position() {
return this.position;
}
@Override
public int readMemberContentLength(DeMember member, Decodeable decoder) {
return -1;
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否存在
*/
@Override
public final boolean hasNext() {
public boolean hasNext(int startPosition, int contentLength) {
byte b = readByte();
if (b == SIGN_HASNEXT) return true;
if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT)
@@ -248,6 +261,41 @@ public class BsonReader extends Reader {
return content[++this.position];
}
@Override
public final byte[] readByteArray() {
int len = readArrayB(null, null);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = readMemberContentLength(null, null);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
int startPosition = position();
while (hasNext(startPosition, contentLength)) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = readByte();
}
readArrayE();
byte[] newdata = new byte[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
byte[] values = new byte[len];
for (int i = 0; i < values.length; i++) {
values[i] = readByte();
}
readArrayE();
return values;
}
}
@Override
public char readChar() {
return (char) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position]));

View File

@@ -98,6 +98,7 @@ public class BsonWriter extends Writer {
protected boolean recycle() {
this.count = 0;
this.specify = null;
if (this.content.length > defaultSize) {
this.content = new byte[defaultSize];
}
@@ -124,6 +125,22 @@ public class BsonWriter extends Writer {
writeTo(value);
}
@Override
public final void writeByteArray(byte[] values) {
if (values == null) {
writeNull();
return;
}
writeArrayB(values.length, null, values);
boolean flag = false;
for (byte v : values) {
if (flag) writeArrayMark();
writeByte(v);
flag = true;
}
writeArrayE();
}
@Override
public final void writeChar(final char value) {
writeTo((byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF));
@@ -166,10 +183,11 @@ public class BsonWriter extends Writer {
}
@Override
public final void writeObjectB(Object obj) {
public final int writeObjectB(Object obj) {
super.writeObjectB(obj);
writeSmallString("");
writeShort(BsonReader.SIGN_OBJECTB);
return -1;
}
@Override
@@ -179,7 +197,8 @@ public class BsonWriter extends Writer {
}
@Override
public final void writeFieldName(Attribute attribute) {
public final void writeFieldName(EnMember member) {
Attribute attribute = member.getAttribute();
writeByte(BsonReader.SIGN_HASNEXT);
writeSmallString(attribute.field());
byte typeval = 127; //字段的类型值
@@ -266,8 +285,9 @@ public class BsonWriter extends Writer {
}
@Override
public final void writeArrayB(int size) {
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
writeInt(size);
return -1;
}
@Override
@@ -279,8 +299,9 @@ public class BsonWriter extends Writer {
}
@Override
public void writeMapB(int size) {
writeArrayB(size);
public int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
writeArrayB(size, valueEncoder, obj);
return -1;
}
@Override

View File

@@ -29,24 +29,31 @@ public final class BoolArraySimpledCoder<R extends Reader, W extends Writer> ext
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (boolean v : values) {
if (flag) out.writeArrayMark();
out.writeBoolean(v);
flag = true;
if (out.writeArrayB(values.length, BoolSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (boolean v : values) {
if (flag) out.writeArrayMark();
out.writeBoolean(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public boolean[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, BoolSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, BoolSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
boolean[] data = new boolean[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
boolean[] newdata = new boolean[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -11,7 +11,7 @@ import org.redkale.convert.Writer;
/**
* byte[] 的SimpledCoder实现
*
*
* <p>
* 详情见: https://redkale.org
*
@@ -25,47 +25,12 @@ public final class ByteArraySimpledCoder<R extends Reader, W extends Writer> ext
@Override
public void convertTo(W out, byte[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (byte v : values) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
}
out.writeArrayE();
out.writeByteArray(values);
}
@Override
public byte[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
while (in.hasNext()) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readByte();
}
in.readArrayE();
byte[] newdata = new byte[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
byte[] values = new byte[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readByte();
}
in.readArrayE();
return values;
}
return in.readByteArray();
}
}

View File

@@ -30,24 +30,31 @@ public final class ByteBufferSimpledCoder<R extends Reader, W extends Writer> ex
out.writeNull();
return;
}
out.writeArrayB(value.remaining());
boolean flag = false;
for (byte v : value.array()) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
if (out.writeArrayB(value.remaining(), ByteSimpledCoder.instance, value) < 0) {
boolean flag = false;
for (byte v : value.array()) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public ByteBuffer convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, ByteSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, ByteSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -12,7 +12,9 @@ import org.redkale.convert.Writer;
/**
* char[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +29,31 @@ public final class CharArraySimpledCoder<R extends Reader, W extends Writer> ext
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (char v : values) {
if (flag) out.writeArrayMark();
out.writeChar(v);
flag = true;
if (out.writeArrayB(values.length, CharSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (char v : values) {
if (flag) out.writeArrayMark();
out.writeChar(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public char[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, CharSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, CharSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
char[] data = new char[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
char[] newdata = new char[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -30,24 +30,31 @@ public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> e
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (double v : values) {
if (flag) out.writeArrayMark();
out.writeDouble(v);
flag = true;
if (out.writeArrayB(values.length, DoubleSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (double v : values) {
if (flag) out.writeArrayMark();
out.writeDouble(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public double[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, DoubleSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, DoubleSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
double[] data = new double[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
double[] newdata = new double[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -45,4 +45,8 @@ public final class EnumSimpledCoder<R extends Reader, W extends Writer, E extend
return (E) Enum.valueOf(type, value);
}
@Override
public Class<E> getType() {
return type;
}
}

View File

@@ -12,7 +12,9 @@ import org.redkale.convert.Writer;
/**
* float[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +29,31 @@ public final class FloatArraySimpledCoder<R extends Reader, W extends Writer> ex
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (float v : values) {
if (flag) out.writeArrayMark();
out.writeFloat(v);
flag = true;
if (out.writeArrayB(values.length, FloatSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (float v : values) {
if (flag) out.writeArrayMark();
out.writeFloat(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public float[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, FloatSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, FloatSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
float[] data = new float[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
float[] newdata = new float[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -30,24 +30,31 @@ public final class IntArraySimpledCoder<R extends Reader, W extends Writer> exte
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (int v : values) {
if (flag) out.writeArrayMark();
out.writeInt(v);
flag = true;
if (out.writeArrayB(values.length, IntSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (int v : values) {
if (flag) out.writeArrayMark();
out.writeInt(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public int[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, IntSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, IntSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
int[] data = new int[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
int[] newdata = new int[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -30,24 +30,31 @@ public final class LongArraySimpledCoder<R extends Reader, W extends Writer> ext
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (long v : values) {
if (flag) out.writeArrayMark();
out.writeLong(v);
flag = true;
if (out.writeArrayB(values.length, LongSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (long v : values) {
if (flag) out.writeArrayMark();
out.writeLong(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public long[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, LongSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, LongSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
long[] data = new long[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
long[] newdata = new long[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -12,7 +12,9 @@ import org.redkale.convert.Writer;
/**
* short[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +29,31 @@ public final class ShortArraySimpledCoder<R extends Reader, W extends Writer> ex
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (short v : values) {
if (flag) out.writeArrayMark();
out.writeShort(v);
flag = true;
if (out.writeArrayB(values.length, ShortSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (short v : values) {
if (flag) out.writeArrayMark();
out.writeShort(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public short[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, ShortSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, ShortSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
short[] data = new short[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
short[] newdata = new short[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -5,14 +5,14 @@
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
import org.redkale.convert.*;
/**
* String[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +27,35 @@ public final class StringArraySimpledCoder<R extends Reader, W extends Writer> e
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (String v : values) {
if (flag) out.writeArrayMark();
out.writeString(v);
flag = true;
if (out.writeArrayB(values.length, StringSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (String v : values) {
if (flag) out.writeArrayMark();
out.writeString(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public String[] convertFrom(R in) {
int len = in.readArrayB();
return convertFrom(in, null);
}
public String[] convertFrom(R in, DeMember member) {
int len = in.readArrayB(member, StringSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, StringSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
String[] data = new String[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
String[] newdata = new String[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -126,21 +126,38 @@ public class JsonByteBufferReader extends JsonReader {
if (ch == '{') return "";
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return null;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null;
throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "'");
StringBuilder sb = new StringBuilder();
sb.append(ch);
char one;
try {
while ((one = nextChar()) != 0) sb.append(one);
} catch (Exception e) {
}
throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + sb + ")");
}
/**
* 判断下一个非空白字符是否为[
*
* @param member DeMember
* @param decoder Decodeable
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public final int readArrayB() {
public final int readArrayB(DeMember member, Decodeable decoder) {
char ch = nextGoodChar();
if (ch == '[' || ch == '{') return SIGN_NOLENGTH;
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL;
throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "'");
StringBuilder sb = new StringBuilder();
sb.append(ch);
char one;
try {
while ((one = nextChar()) != 0) sb.append(one);
} catch (Exception e) {
}
throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + sb + ")");
}
/**
@@ -150,16 +167,26 @@ public class JsonByteBufferReader extends JsonReader {
public final void readBlank() {
char ch = nextGoodChar();
if (ch == ':') return;
throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ")");
StringBuilder sb = new StringBuilder();
sb.append(ch);
char one;
try {
while ((one = nextChar()) != 0) sb.append(one);
} catch (Exception e) {
}
throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ") in (" + sb + ")");
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否存在
*/
@Override
public final boolean hasNext() {
public boolean hasNext(int startPosition, int contentLength) {
char ch = nextGoodChar();
if (ch == ',') return true;
if (ch == '}' || ch == ']' || ch == 0) return false;
@@ -272,8 +299,10 @@ public class JsonByteBufferReader extends JsonReader {
@Override
public final int readInt() {
char firstchar = nextGoodChar();
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
firstchar = nextChar();
quote = true;
firstchar = nextGoodChar();
if (firstchar == '"' || firstchar == '\'') return 0;
}
int value = 0;
@@ -288,6 +317,7 @@ public class JsonByteBufferReader extends JsonReader {
if (ch >= '0' && ch <= '9') {
value = (value << 3) + (value << 1) + (ch - '0');
} else if (ch == '"' || ch == '\'') {
} else if (quote && ch <= ' ') {
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;
@@ -306,8 +336,10 @@ public class JsonByteBufferReader extends JsonReader {
@Override
public final long readLong() {
char firstchar = nextGoodChar();
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
firstchar = nextChar();
quote = true;
firstchar = nextGoodChar();
if (firstchar == '"' || firstchar == '\'') return 0L;
}
long value = 0;
@@ -322,6 +354,7 @@ public class JsonByteBufferReader extends JsonReader {
if (ch >= '0' && ch <= '9') {
value = (value << 3) + (value << 1) + (ch - '0');
} else if (ch == '"' || ch == '\'') {
} else if (quote && ch <= ' ') {
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;

View File

@@ -49,6 +49,7 @@ public class JsonByteBufferWriter extends JsonWriter {
@Override
protected boolean recycle() {
this.index = 0;
this.specify = null;
this.charset = null;
this.buffers = null;
return false;

View File

@@ -80,8 +80,8 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
return writerPool.get().tiny(tiny);
}
public void offerJsonWriter(final JsonWriter out) {
if (out != null) writerPool.accept(out);
public void offerJsonWriter(final JsonWriter writer) {
if (writer != null) writerPool.accept(writer);
}
//------------------------------ convertFrom -----------------------------------------------------------
@@ -139,20 +139,21 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
public String convertTo(final Type type, final Object value) {
if (type == null) return null;
if (value == null) return "null";
final JsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
String result = out.toString();
writerPool.accept(out);
final JsonWriter writer = writerPool.get().tiny(tiny);
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
String result = writer.toString();
writerPool.accept(writer);
return result;
}
@Override
public String convertMapTo(final Object... values) {
if (values == null) return "null";
final JsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
String result = out.toString();
writerPool.accept(out);
final JsonWriter writer = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
String result = writer.toString();
writerPool.accept(writer);
return result;
}
@@ -170,6 +171,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
new JsonStreamWriter(tiny, out).writeNull();
} else {
final JsonWriter writer = writerPool.get().tiny(tiny);
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
byte[] bs = writer.toBytes();
writerPool.accept(writer);
@@ -216,6 +218,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
if (value == null) {
out.writeNull();
} else {
out.specify(type);
factory.loadEncoder(type).convertTo(out, value);
}
return out.toBuffers();
@@ -246,6 +249,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
if (value == null) {
writer.writeNull();
} else {
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
}
}
@@ -265,14 +269,15 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
public JsonWriter convertToWriter(final Type type, final Object value) {
if (type == null) return null;
final JsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
return out;
final JsonWriter writer = writerPool.get().tiny(tiny);
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
return writer;
}
public JsonWriter convertMapToWriter(final Object... values) {
final JsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
return out;
final JsonWriter writer = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
return writer;
}
}

View File

@@ -85,4 +85,9 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
public boolean isReversible() {
return false;
}
@Override
public boolean isFieldSort() {
return true;
}
}

View File

@@ -189,11 +189,14 @@ public class JsonReader extends Reader {
/**
* 判断下一个非空白字符是否为{
*
* @param member DeMember
* @param keydecoder Decodeable
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public final int readMapB() {
return readArrayB();
public final int readMapB(DeMember member, Decodeable keydecoder) {
return readArrayB(member, keydecoder);
}
@Override
@@ -203,10 +206,13 @@ public class JsonReader extends Reader {
/**
* 判断下一个非空白字符是否为[
*
* @param member DeMember
* @param decoder Decodeable
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public int readArrayB() {
public int readArrayB(DeMember member, Decodeable decoder) {
char ch = this.text[++this.position];
if (ch == '[') return SIGN_NOLENGTH;
if (ch == '{') return SIGN_NOLENGTH;
@@ -244,13 +250,26 @@ public class JsonReader extends Reader {
throw new ConvertException("'" + new String(text) + "'expected a ':' but '" + ch + "'(position = " + position + ") in (" + new String(this.text) + ")");
}
@Override
public int position() {
return this.position;
}
@Override
public int readMemberContentLength(DeMember member, Decodeable decoder) {
return -1;
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否存在
*/
@Override
public boolean hasNext() {
public boolean hasNext(int startPosition, int contentLength) {
char ch = this.text[++this.position];
if (ch == ',') return true;
if (ch == '}' || ch == ']') return false;
@@ -335,8 +354,16 @@ public class JsonReader extends Reader {
if (firstchar > ' ') break;
}
}
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
quote = true;
firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0;
@@ -352,7 +379,8 @@ public class JsonReader extends Reader {
if (currpos == eof) break;
char ch = text0[++currpos];
int val = digits[ch];
if (val == -3) break;
if (quote && val == -3) continue;
if (val <= -3) break;
if (val == -1) throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")");
if (val != -2) value = value * 10 + val;
}
@@ -377,8 +405,16 @@ public class JsonReader extends Reader {
if (firstchar > ' ') break;
}
}
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
quote = true;
firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0L;
@@ -394,7 +430,8 @@ public class JsonReader extends Reader {
if (currpos == eof) break;
char ch = text0[++currpos];
int val = digits[ch];
if (val == -3) break;
if (quote && val == -3) continue;
if (val <= -3) break;
if (val == -1) throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")");
if (val != -2) value = value * 10 + val;
}
@@ -435,6 +472,41 @@ public class JsonReader extends Reader {
return (byte) readInt();
}
@Override
public final byte[] readByteArray() {
int len = readArrayB(null, null);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = readMemberContentLength(null, null);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
int startPosition = position();
while (hasNext(startPosition, contentLength)) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = readByte();
}
readArrayE();
byte[] newdata = new byte[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
byte[] values = new byte[len];
for (int i = 0; i < values.length; i++) {
values[i] = readByte();
}
readArrayE();
return values;
}
}
@Override
public final char readChar() {
return (char) readInt();
@@ -448,6 +520,7 @@ public class JsonReader extends Reader {
@Override
public final float readFloat() {
String chars = readSmallString();
if (chars != null) chars = chars.trim();
if (chars == null || chars.isEmpty()) return 0.f;
return Float.parseFloat(chars);
}
@@ -455,6 +528,7 @@ public class JsonReader extends Reader {
@Override
public final double readDouble() {
String chars = readSmallString();
if (chars != null) chars = chars.trim();
if (chars == null || chars.isEmpty()) return 0.0;
return Double.parseDouble(chars);
}
@@ -590,7 +664,8 @@ public class JsonReader extends Reader {
digits[i] = i - 'A' + 10;
}
digits['"'] = digits['\''] = -2; //-2 跳过
digits[','] = digits['}'] = digits[']'] = digits[' '] = digits['\t'] = digits['\r'] = digits['\n'] = digits[':'] = -3; //-3退出
digits[' '] = digits['\t'] = digits['\r'] = digits['\n'] = -3; //-3可能跳过
digits[','] = digits['}'] = digits[']'] = digits[':'] = -4; //-4退出
}
}

View File

@@ -6,7 +6,7 @@
package org.redkale.convert.json;
import java.nio.ByteBuffer;
import org.redkale.convert.Writer;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
@@ -99,6 +99,7 @@ public class JsonWriter extends Writer {
protected boolean recycle() {
this.count = 0;
this.specify = null;
if (this.content.length > defaultSize) {
this.content = new char[defaultSize];
}
@@ -156,9 +157,9 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeFieldName(Attribute attribute) {
public final void writeFieldName(EnMember member) {
if (this.comma) writeTo(',');
writeTo(true, attribute.field());
writeTo(true, member.getAttribute().field());
writeTo(':');
}
@@ -187,6 +188,22 @@ public class JsonWriter extends Writer {
writeInt(value);
}
@Override
public final void writeByteArray(byte[] values) {
if (values == null) {
writeNull();
return;
}
writeArrayB(values.length, null, values);
boolean flag = false;
for (byte v : values) {
if (flag) writeArrayMark();
writeByte(v);
flag = true;
}
writeArrayE();
}
@Override
public final void writeChar(char value) {
writeInt(value);
@@ -312,9 +329,10 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeObjectB(Object obj) {
public final int writeObjectB(Object obj) {
super.writeObjectB(obj);
writeTo('{');
return -1;
}
@Override
@@ -328,8 +346,9 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeArrayB(int size) {
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
writeTo('[');
return -1;
}
@Override
@@ -343,8 +362,9 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeMapB(int size) {
public final int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
writeTo('{');
return -1;
}
@Override

View File

@@ -11,7 +11,7 @@ import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.*;
import java.util.function.Consumer;
import javax.net.ssl.SSLContext;
@@ -42,6 +42,9 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
protected Consumer<AsyncConnection> beforeCloseListener;
//关联的事件数, 小于1表示没有事件
protected final AtomicInteger eventing = new AtomicInteger();
public final long getLastReadTime() {
return readtime;
}
@@ -50,6 +53,14 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
return writetime;
}
public final int increEventing() {
return eventing.incrementAndGet();
}
public final int decreEventing() {
return eventing.decrementAndGet();
}
public abstract boolean isTCP();
public abstract boolean shutdownInput();

View File

@@ -5,10 +5,8 @@
*/
package org.redkale.net;
import java.io.IOException;
import java.net.*;
import java.nio.*;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.charset.*;
import java.util.concurrent.*;
import java.util.function.*;
@@ -145,10 +143,6 @@ public class Context {
return executor.submit(r);
}
public AsynchronousChannelGroup createAsynchronousChannelGroup() throws IOException {
return AsynchronousChannelGroup.withThreadPool(executor);
}
public void runAsync(Runnable r) {
executor.execute(r);
}

View File

@@ -5,6 +5,7 @@
*/
package org.redkale.net;
import java.io.IOException;
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.TimeUnit;
@@ -20,7 +21,7 @@ import org.redkale.util.*;
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public final class PrepareRunner implements Runnable {
public class PrepareRunner implements Runnable {
private final AsyncConnection channel;
@@ -105,4 +106,39 @@ public final class PrepareRunner implements Runnable {
}
}
protected void prepare(ByteBuffer buffer, Request request, Response response) throws IOException {
context.prepare.prepare(buffer, request, response);
}
protected void initResponse(Response response, AsyncConnection channel) {
response.init(channel);
}
protected Response pollResponse() {
return context.responsePool.get();
}
protected Request pollRequest(Response response) {
return response.request;
}
protected AsyncConnection removeChannel(Response response) {
return response.removeChannel();
}
protected ByteBuffer pollReadBuffer(Request request) {
return request.pollReadBuffer();
}
protected ByteBuffer pollReadBuffer(Response response) {
return response.request.pollReadBuffer();
}
protected void offerReadBuffer(Request request, ByteBuffer buffer) {
request.offerReadBuffer(buffer);
}
protected void offerReadBuffer(Response response, ByteBuffer buffer) {
response.request.offerReadBuffer(buffer);
}
}

View File

@@ -210,7 +210,7 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
@SuppressWarnings("unchecked")
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
public final void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
public void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
executeCounter.incrementAndGet();
final int rs = request.readHeader(buffer);
if (rs < 0) {
@@ -218,7 +218,11 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
if (rs != Integer.MIN_VALUE) illRequestCounter.incrementAndGet();
response.finish(true);
} else if (rs == 0) {
request.offerReadBuffer(buffer);
if (buffer.hasRemaining()) {
request.setMoredata(buffer);
} else {
request.offerReadBuffer(buffer);
}
request.prepare();
response.filter = this.headFilter;
response.servlet = this;
@@ -236,7 +240,11 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
buffer.clear();
request.channel.read(buffer, buffer, this);
} else {
request.offerReadBuffer(buffer);
if (buffer.hasRemaining()) {
request.setMoredata(buffer);
} else {
request.offerReadBuffer(buffer);
}
request.prepare();
try {
response.filter = PrepareServlet.this.headFilter;

View File

@@ -31,6 +31,10 @@ public abstract class Request<C extends Context> {
protected boolean keepAlive;
protected boolean more; //pipeline模式
protected ByteBuffer moredata; //pipeline模式
protected AsyncConnection channel;
protected ByteBuffer readBuffer;
@@ -50,6 +54,16 @@ public abstract class Request<C extends Context> {
this.jsonConvert = context.getJsonConvert();
}
protected void setMoredata(ByteBuffer buffer) {
this.moredata = buffer;
}
protected ByteBuffer removeMoredata() {
ByteBuffer rs = this.moredata;
this.moredata = null;
return rs;
}
protected ByteBuffer pollReadBuffer() {
ByteBuffer buffer = this.readBuffer;
this.readBuffer = null;
@@ -90,6 +104,8 @@ public abstract class Request<C extends Context> {
protected void recycle() {
createtime = 0;
keepAlive = false;
more = false;
moredata = null;
attributes.clear();
channel = null; // close it by response
}

View File

@@ -251,7 +251,8 @@ public abstract class Response<C extends Context, R extends Request<C>> {
}
this.recycleListener = null;
}
if (request.keepAlive && channel != null) {
if (request.more) removeChannel();
if (request.keepAlive && !request.more && channel != null) {
if (channel.isOpen()) {
AsyncConnection conn = removeChannel();
this.recycle();
@@ -279,24 +280,44 @@ public abstract class Response<C extends Context, R extends Request<C>> {
public void finish(ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffer, buffer, finishHandler);
ByteBuffer data = this.request.removeMoredata();
final AsyncConnection conn = this.channel;
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffer, buffer, finishHandler);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
public void finish(boolean kill, ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffer, buffer, finishHandler);
ByteBuffer data = this.request.removeMoredata();
final AsyncConnection conn = this.channel;
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffer, buffer, finishHandler);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
public void finish(ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffers, buffers, finishHandler2);
final AsyncConnection conn = this.channel;
ByteBuffer data = this.request.removeMoredata();
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffers, buffers, finishHandler2);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
public void finish(boolean kill, ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffers, buffers, finishHandler2);
final AsyncConnection conn = this.channel;
ByteBuffer data = this.request.removeMoredata();
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffers, buffers, finishHandler2);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
protected <A> void send(final ByteBuffer buffer, final A attachment, final CompletionHandler<Integer, A> handler) {

View File

@@ -396,7 +396,9 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
if (s.endsWith("*")) {
File root = new File(s.substring(0, s.length() - 1));
if (root.isDirectory()) {
for (File f : root.listFiles()) {
File[] lfs = root.listFiles();
if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()");
for (File f : lfs) {
set.add(f.toURI().toURL());
}
}

View File

@@ -23,6 +23,8 @@ import javax.net.ssl.SSLContext;
*/
public class TcpAioAsyncConnection extends AsyncConnection {
private final Semaphore semaphore = new Semaphore(1);
private int readTimeoutSeconds;
private int writeTimeoutSeconds;
@@ -31,6 +33,8 @@ public class TcpAioAsyncConnection extends AsyncConnection {
private final SocketAddress remoteAddress;
private BlockingQueue<WriteEntry> writeQueue;
public TcpAioAsyncConnection(final AsynchronousSocketChannel ch, SSLContext sslContext,
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds,
final AtomicLong livingCounter, final AtomicLong closedCounter) {
@@ -102,33 +106,86 @@ public class TcpAioAsyncConnection extends AsyncConnection {
channel.read(dst, timeout < 0 ? 0 : timeout, unit, attachment, handler);
}
private <A> void nextWrite(A attachment) {
BlockingQueue<WriteEntry> queue = this.writeQueue;
WriteEntry entry = queue == null ? null : queue.poll();
if (entry != null) {
try {
if (entry.writeOneBuffer == null) {
write(false, entry.writeBuffers, entry.writeOffset, entry.writeLength, entry.writeAttachment, entry.writeHandler);
} else {
write(false, entry.writeOneBuffer, entry.writeAttachment, entry.writeHandler);
}
} catch (Exception e) {
entry.writeHandler.failed(e, entry.writeAttachment);
}
} else {
semaphore.release();
}
}
@Override
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
write(true, src, attachment, handler);
}
private <A> void write(boolean acquire, ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
if (acquire && !semaphore.tryAcquire()) {
if (this.writeQueue == null) {
synchronized (semaphore) {
if (this.writeQueue == null) {
this.writeQueue = new LinkedBlockingDeque<>();
}
}
}
this.writeQueue.add(new WriteEntry(src, attachment, handler));
return;
}
WriteOneCompletionHandler newHandler = new WriteOneCompletionHandler(src, handler);
if (!channel.isOpen()) {
newHandler.failed(new ClosedChannelException(), attachment);
return;
}
this.writetime = System.currentTimeMillis();
if (writeTimeoutSeconds > 0) {
channel.write(src, writeTimeoutSeconds, TimeUnit.SECONDS, attachment, handler);
} else {
channel.write(src, attachment, handler);
try {
if (writeTimeoutSeconds > 0) {
channel.write(src, writeTimeoutSeconds, TimeUnit.SECONDS, attachment, newHandler);
} else {
channel.write(src, attachment, newHandler);
}
} catch (Exception e) {
newHandler.failed(e, attachment);
}
}
@Override
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler<Integer, ? super A> handler) {
write(true, srcs, offset, length, attachment, handler);
}
private <A> void write(boolean acquire, ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler<Integer, ? super A> handler) {
if (acquire && !semaphore.tryAcquire()) {
if (this.writeQueue == null) {
synchronized (semaphore) {
if (this.writeQueue == null) {
this.writeQueue = new LinkedBlockingDeque<>();
}
}
}
this.writeQueue.add(new WriteEntry(srcs, offset, length, attachment, handler));
return;
}
WriteMoreCompletionHandler newHandler = new WriteMoreCompletionHandler(srcs, offset, length, handler);
if (!channel.isOpen()) {
newHandler.failed(new ClosedChannelException(), attachment);
return;
}
this.writetime = System.currentTimeMillis();
channel.write(srcs, offset, length, writeTimeoutSeconds > 0 ? writeTimeoutSeconds : 60, TimeUnit.SECONDS,
attachment, new CompletionHandler<Long, A>() {
@Override
public void completed(Long result, A attachment) {
handler.completed(result.intValue(), attachment);
}
@Override
public void failed(Throwable exc, A attachment) {
handler.failed(exc, attachment);
}
});
try {
channel.write(srcs, offset, length, writeTimeoutSeconds > 0 ? writeTimeoutSeconds : 60, TimeUnit.SECONDS, attachment, newHandler);
} catch (Exception e) {
newHandler.failed(e, attachment);
}
}
@Override
@@ -179,6 +236,17 @@ public class TcpAioAsyncConnection extends AsyncConnection {
public final void close() throws IOException {
super.close();
channel.close();
BlockingQueue<WriteEntry> queue = this.writeQueue;
if (queue == null) return;
WriteEntry entry;
Exception ex = null;
while ((entry = queue.poll()) != null) {
if (ex == null) ex = new ClosedChannelException();
try {
entry.writeHandler.failed(ex, entry.writeAttachment);
} catch (Exception e) {
}
}
}
@Override
@@ -191,4 +259,125 @@ public class TcpAioAsyncConnection extends AsyncConnection {
return true;
}
private class WriteMoreCompletionHandler<A> implements CompletionHandler<Long, A> {
private final CompletionHandler<Integer, A> writeHandler;
private final ByteBuffer[] writeBuffers;
private int writeOffset;
private int writeLength;
private int writeCount;
public WriteMoreCompletionHandler(ByteBuffer[] buffers, int offset, int length, CompletionHandler handler) {
this.writeBuffers = buffers;
this.writeOffset = offset;
this.writeLength = length;
this.writeHandler = handler;
}
@Override
public void completed(Long result, A attachment) {
if (result >= 0) {
writeCount += result;
try {
int index = -1;
for (int i = writeOffset; i < (writeOffset + writeLength); i++) {
if (writeBuffers[i].hasRemaining()) {
index = i;
break;
}
}
if (index >= 0) {
writeOffset += index;
writeLength -= index;
channel.write(writeBuffers, writeOffset, writeLength, writeTimeoutSeconds > 0 ? writeTimeoutSeconds : 60, TimeUnit.SECONDS, attachment, this);
return;
}
} catch (Exception e) {
failed(e, attachment);
return;
}
nextWrite(attachment);
writeHandler.completed(writeCount, attachment);
} else {
nextWrite(attachment);
writeHandler.completed(result.intValue(), attachment);
}
}
@Override
public void failed(Throwable exc, A attachment) {
nextWrite(attachment);
writeHandler.failed(exc, attachment);
}
}
private class WriteOneCompletionHandler<A> implements CompletionHandler<Integer, A> {
private final CompletionHandler writeHandler;
private final ByteBuffer writeOneBuffer;
public WriteOneCompletionHandler(ByteBuffer buffer, CompletionHandler handler) {
this.writeOneBuffer = buffer;
this.writeHandler = handler;
}
@Override
public void completed(Integer result, A attachment) {
try {
if (writeOneBuffer.hasRemaining()) {
channel.write(writeOneBuffer, attachment, this);
return;
}
} catch (Exception e) {
failed(e, attachment);
return;
}
nextWrite(attachment);
writeHandler.completed(result, attachment);
}
@Override
public void failed(Throwable exc, A attachment) {
nextWrite(attachment);
writeHandler.failed(exc, attachment);
}
}
private static class WriteEntry {
ByteBuffer writeOneBuffer;
ByteBuffer[] writeBuffers;
int writingCount;
int writeOffset;
int writeLength;
Object writeAttachment;
CompletionHandler writeHandler;
public WriteEntry(ByteBuffer writeOneBuffer, Object writeAttachment, CompletionHandler writeHandler) {
this.writeOneBuffer = writeOneBuffer;
this.writeAttachment = writeAttachment;
this.writeHandler = writeHandler;
}
public WriteEntry(ByteBuffer[] writeBuffers, int writeOffset, int writeLength, Object writeAttachment, CompletionHandler writeHandler) {
this.writeBuffers = writeBuffers;
this.writeOffset = writeOffset;
this.writeLength = writeLength;
this.writeAttachment = writeAttachment;
this.writeHandler = writeHandler;
}
}
}

View File

@@ -32,7 +32,8 @@ public class TcpAioProtocolServer extends ProtocolServer {
@Override
public void open(AnyValue config) throws IOException {
group = AsynchronousChannelGroup.withThreadPool(context.executor);
//group = AsynchronousChannelGroup.withThreadPool(context.executor);
group = AsynchronousChannelGroup.withFixedThreadPool(context.executor.getCorePoolSize(), context.executor.getThreadFactory());
this.serverChannel = AsynchronousServerSocketChannel.open(group);
final Set<SocketOption<?>> options = this.serverChannel.supportedOptions();

View File

@@ -22,17 +22,17 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public class TcpNioAsyncConnection extends AsyncConnection {
private int readTimeoutSeconds;
protected int readTimeoutSeconds;
private int writeTimeoutSeconds;
protected int writeTimeoutSeconds;
private final Selector selector;
protected final Selector selector;
private SelectionKey key;
protected SelectionKey key;
private final SocketChannel channel;
protected final SocketChannel channel;
private final SocketAddress remoteAddress;
protected final SocketAddress remoteAddress;
ByteBuffer readBuffer;
@@ -362,4 +362,5 @@ public class TcpNioAsyncConnection extends AsyncConnection {
public final boolean isTCP() {
return true;
}
}

View File

@@ -10,7 +10,7 @@ import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.*;
import org.redkale.util.AnyValue;
/**
@@ -27,9 +27,9 @@ public class TcpNioProtocolServer extends ProtocolServer {
private ServerSocketChannel serverChannel;
private NIOThreadWorker[] workers;
private NioThreadWorker[] workers;
private NIOThreadWorker currWorker;
private NioThreadWorker currWorker;
private boolean running;
@@ -82,11 +82,11 @@ public class TcpNioProtocolServer extends ProtocolServer {
@Override
public void accept() throws IOException {
this.serverChannel.register(acceptSelector, SelectionKey.OP_ACCEPT);
final CountDownLatch cdl = new CountDownLatch(1);
this.running = true;
this.workers = new NIOThreadWorker[Runtime.getRuntime().availableProcessors()];
this.workers = new NioThreadWorker[Runtime.getRuntime().availableProcessors()];
final CountDownLatch wkcdl = new CountDownLatch(workers.length);
for (int i = 0; i < workers.length; i++) {
workers[i] = new NIOThreadWorker();
workers[i] = new NioThreadWorker(wkcdl, i + 1, workers.length);
workers[i].setDaemon(true);
workers[i].start();
}
@@ -95,6 +95,12 @@ public class TcpNioProtocolServer extends ProtocolServer {
}
workers[workers.length - 1].next = workers[0];
currWorker = workers[0];
try {
wkcdl.await(3, TimeUnit.SECONDS);
} catch (Exception e) {
throw new IOException(e);
}
final CountDownLatch cdl = new CountDownLatch(1);
new Thread() {
@Override
public void run() {
@@ -111,12 +117,6 @@ public class TcpNioProtocolServer extends ProtocolServer {
if (key.isAcceptable()) {
try {
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
channel.configureBlocking(false);
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
createCounter.incrementAndGet();
livingCounter.incrementAndGet();
currWorker.addChannel(channel);
@@ -134,45 +134,91 @@ public class TcpNioProtocolServer extends ProtocolServer {
}
}.start();
try {
cdl.await();
cdl.await(3, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
throw new IOException(e);
}
}
@Override
public void close() throws IOException {
if (!this.running) return;
this.running = false;
serverChannel.close();
acceptSelector.close();
for (NIOThreadWorker worker : workers) {
for (NioThreadWorker worker : workers) {
worker.interrupt();
}
this.running = false;
}
class NIOThreadWorker extends Thread {
class NioThreadWorker extends Thread {
final Selector selector;
NIOThreadWorker next;
final CountDownLatch cdl;
public NIOThreadWorker() {
private final Queue<TcpNioAsyncConnection> connected;
private final CopyOnWriteArrayList<TcpNioAsyncConnection> done;
protected volatile Thread ownerThread;
NioThreadWorker next;
public NioThreadWorker(final CountDownLatch cdl, int idx, int count) {
this.cdl = cdl;
String idxstr = "000000" + idx;
this.setName("NioThreadWorker:" + context.getServerAddress().getPort() + "-" + idxstr.substring(idxstr.length() - ("" + count).length()));
try {
this.selector = Selector.open();
} catch (IOException e) {
throw new RuntimeException(e);
}
this.connected = new ArrayBlockingQueue<>(1000000);
this.done = new CopyOnWriteArrayList<>();
}
public void addChannel(SocketChannel channel) throws IOException {
AsyncConnection conn = new TcpNioAsyncConnection(channel, null, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
context.runAsync(new PrepareRunner(context, conn, null, null));
public boolean addChannel(SocketChannel channel) throws IOException {
TcpNioAsyncConnection conn = new TcpNioAsyncConnection(channel, null, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
return connected.add(conn);
}
protected void processConnected() {
TcpNioAsyncConnection schannel;
try {
while ((schannel = connected.poll()) != null) {
SocketChannel channel = schannel.channel;
channel.configureBlocking(false);
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
channel.register(selector, SelectionKey.OP_READ).attach(schannel);
}
} catch (IOException e) {
// do nothing
}
synchronized (done) {
for (TcpNioAsyncConnection conn : done) {
if (conn.key != null && conn.key.isValid()) {
conn.key.interestOps(SelectionKey.OP_WRITE);
}
}
done.clear();
}
}
public boolean isSameThread() {
return this.ownerThread == Thread.currentThread();
}
@Override
public void run() {
this.ownerThread = Thread.currentThread();
if (cdl != null) cdl.countDown();
while (running) {
processConnected();
try {
selector.select(50);
} catch (IOException e) {
@@ -207,13 +253,28 @@ public class TcpNioProtocolServer extends ProtocolServer {
return;
}
if (conn == null) return;
if (key.isWritable()) {
if (conn.writeHandler != null) writeOP(key, socket, conn);
} else if (key.isReadable()) {
if (key.isReadable()) {
if (conn.readHandler != null) readOP(key, socket, conn);
} else if (key.isWritable()) {
if (conn.writeHandler != null) writeOP(key, socket, conn);
}
}
private void closeOP(SelectionKey key) {
if (key == null) return;
TcpNioAsyncConnection conn = (TcpNioAsyncConnection) key.attachment();
try {
if (key.isValid()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
socketChannel.close();
key.attach(null);
key.cancel();
}
} catch (IOException e) {
}
conn.dispose();
}
private void readOP(SelectionKey key, SocketChannel socket, TcpNioAsyncConnection conn) {
final CompletionHandler handler = conn.removeReadHandler();
final ByteBuffer buffer = conn.removeReadBuffer();

View File

@@ -165,17 +165,18 @@ public class HttpRequest extends Request<HttpContext> {
header.addValue(name, value);
}
}
array.clear();
if (buffer.hasRemaining()) array.write(buffer, buffer.remaining());
if (this.contentType != null && this.contentType.contains("boundary=")) {
this.boundary = true;
}
if (this.contentType != null && this.contentType.contains("boundary=")) this.boundary = true;
if (this.boundary) this.keepAlive = false; //文件上传必须设置keepAlive为false因为文件过大时用户不一定会skip掉多余的数据
array.clear();
if (this.contentLength > 0 && (this.contentType == null || !this.boundary)) {
if (this.contentLength > context.getMaxbody()) return -1;
array.write(buffer, Math.min((int) this.contentLength, buffer.remaining()));
int lr = (int) this.contentLength - array.size();
return lr > 0 ? lr : 0;
}
if (buffer.hasRemaining() && (this.boundary || !this.keepAlive)) array.write(buffer, buffer.remaining()); //文件上传、HTTP1.0或Connection:close
//暂不考虑是keep-alive且存在body却没有指定Content-Length的情况
return 0;
}

View File

@@ -27,7 +27,6 @@ import org.redkale.util.*;
import org.redkale.source.Flipper;
/**
* 以find开头的方法且参数只有一个且参数类型为primitive class或String则RestParam值默认为#
* <p>
* 详情见: https://redkale.org
*
@@ -133,6 +132,9 @@ public final class Rest {
final JsonFactory childFactory = JsonFactory.create();
List<Class> types = new ArrayList<>();
for (RestConvert rc : converts) {
if (rc.type() == void.class || rc.type() == Void.class) {
return JsonFactory.create().skipAllIgnore(true).getConvert();
}
if (types.contains(rc.type())) throw new RuntimeException("@RestConvert type(" + rc.type() + ") repeat");
if (rc.skipIgnore()) {
childFactory.registerSkipIgnore(rc.type());
@@ -401,6 +403,7 @@ public final class Rest {
Set<String> paramnames = new HashSet<>();
String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method);
List<String> names = asmParamMap.get(methodesc);
if (names != null) while (names.remove(" ")); //删掉空元素
Parameter[] params = method.getParameters();
final LinkedHashMap<String, Parameter> paramap = new LinkedHashMap(); //必须使用LinkedHashMap确保顺序
for (int j = 0; j < params.length; j++) { //字段列表
@@ -858,8 +861,8 @@ public final class Rest {
final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class);
if (rcs != null && rcs.length > 0) restConverts.add(rcs);
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, entry.name, "(" + reqDesc + respDesc + ")V", null, new String[]{"java/io/IOException"}));
//mv.setDebug(true);
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, entry.name.replace('/', '$').replace('.', '_'), "(" + reqDesc + respDesc + ")V", null, new String[]{"java/io/IOException"}));
//mv.setDebug(true);
mv.debugLine();
mv.visitVarInsn(ALOAD, 0);
@@ -891,6 +894,7 @@ public final class Rest {
int maxLocals = 4;
List<String> asmParamNames = asmParamMap == null ? null : asmParamMap.get(method.getName() + ":" + Type.getMethodDescriptor(method));
if (asmParamNames != null) while (asmParamNames.remove(" ")); //删掉空元素
List<Object[]> paramlist = new ArrayList<>();
//解析方法中的每个参数
for (int i = 0; i < params.length; i++) {
@@ -983,10 +987,6 @@ public final class Rest {
throw new RuntimeException("Parameter " + param.getName() + " not found name by @RestParam in " + method);
}
}
if (annhead == null && anncookie == null && annaddr == null && annbody == null && annfile == null
&& (entry.name.startsWith("find") || entry.name.startsWith("delete")) && params.length == 1) {
if (ptype.isPrimitive() || ptype == String.class) n = "#";
}
if (annhead == null && anncookie == null && annsid == null && annaddr == null && annbody == null && annfile == null
&& !ptype.isPrimitive() && ptype != String.class && ptype != Flipper.class && !CompletionHandler.class.isAssignableFrom(ptype)
&& !ptype.getName().startsWith("java") && n.charAt(0) != '#' && !"&".equals(n)) { //判断Json对象是否包含@RestUploadFile
@@ -1723,6 +1723,7 @@ public final class Rest {
}
cw.visitEnd();
Class<?> newClazz = new RestClassLoader(loader).loadClass(newDynName.replace('/', '.'), cw.toByteArray());
try {
T obj = ((Class<T>) newClazz).getDeclaredConstructor().newInstance();
@@ -1821,7 +1822,7 @@ public final class Rest {
int pos = t.indexOf(defmodulename);
n = pos > 0 ? t.substring(0, pos) : t;
}
this.name = n;
this.name = n.trim();
this.mappingMethod = method;
this.methods = mapping.methods();
this.auth = mapping.auth();
@@ -1837,12 +1838,6 @@ public final class Rest {
break;
}
}
if (!pound && params.length == 1) {
Class ptype = method.getParameterTypes()[0];
if (this.name.startsWith("find") || this.name.startsWith("delete")) {
if (ptype.isPrimitive() || ptype == String.class) pound = true;
}
}
this.existsPound = pound;
}

View File

@@ -11,6 +11,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 只能依附在Service实现类的public方法上, 当方法的返回值以JSON输出时对指定类型的转换设定。 <br>
* 注意: 如果 type() == void.class 则无视其他参数固定返回 JsonFactory.create().skipAllIgnore(true).getConvert();
*
* <p>
* 详情见: https://redkale.org

View File

@@ -32,7 +32,6 @@ public @interface RestParam {
* name='&#38;'表示当前用户; <br>
* name='#'表示截取uri最后一段; <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* 若方法名以find、delete开头且方法的参数只有一个且参数类型是基本数据类型或String则默认值为"#" <br>
*
* @return String
*/

View File

@@ -37,9 +37,20 @@ import org.redkale.util.Comment;
*/
public abstract class WebSocket<G extends Serializable, T> {
@Comment("强制关闭结果码")
public static final int CLOSECODE_FORCED = 1;
//--------------------------- CLOSECODE -------------------------------
@Comment("服务器主动关闭")
public static final int CLOSECODE_SERVERCLOSE = 3001;
@Comment("客户端主动关闭")
public static final int CLOSECODE_CLIENTCLOSE = 3002;
@Comment("异常关闭")
public static final int CLOSECODE_WSEXCEPTION = 3003;
@Comment("异常数据强制关闭")
public static final int CLOSECODE_ILLPACKET = 3004;
//---------------------------- RETCODE --------------------------------
@Comment("消息不合法")
public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2
@@ -802,7 +813,10 @@ public abstract class WebSocket<G extends Serializable, T> {
* 显式地关闭WebSocket
*/
public final void close() {
if (this._runner != null) this._runner.closeRunner(CLOSECODE_FORCED, "user close");
if (this._runner != null) {
CompletableFuture<Void> future = this._runner.closeRunner(CLOSECODE_SERVERCLOSE, "user close");
if (future != null) future.join();
}
}
/**

View File

@@ -144,12 +144,12 @@ public class WebSocketEngine {
}
@Comment("从WebSocketEngine删除指定WebSocket")
void removeThenClose(WebSocket socket) {
CompletableFuture<Void> removeThenClose(WebSocket socket) {
Serializable userid = socket._userid;
if (single) {
currconns.decrementAndGet();
websockets.remove(userid);
if (node != null) node.disconnect(userid);
if (node != null) return node.disconnect(userid);
} else { //非线程安全, 在常规场景中无需锁
List<WebSocket> list = websockets2.get(userid);
if (list != null) {
@@ -157,10 +157,11 @@ public class WebSocketEngine {
list.remove(socket);
if (list.isEmpty()) {
websockets2.remove(userid);
if (node != null) node.disconnect(userid);
if (node != null) return node.disconnect(userid);
}
}
}
return null;
}
@Comment("更改WebSocket的userid")
@@ -242,7 +243,7 @@ public class WebSocketEngine {
}
}
}
if (future != null) future = future.whenComplete((rs, ex) -> context.offerBuffer(packet.sendBuffers));
if (future != null) future.whenComplete((rs, ex) -> context.offerBuffer(packet.sendBuffers));
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
} else {
CompletableFuture<Integer> future = null;
@@ -301,7 +302,7 @@ public class WebSocketEngine {
}
}
}
if (future != null) future = future.whenComplete((rs, ex) -> context.offerBuffer(packet.sendBuffers));
if (future != null) future.whenComplete((rs, ex) -> context.offerBuffer(packet.sendBuffers));
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
} else {
CompletableFuture<Integer> future = null;

View File

@@ -80,7 +80,7 @@ public abstract class WebSocketNode {
public final void postDestroy(AnyValue conf) {
if (this.localEngine == null) return;
//关掉所有本地本地WebSocket
this.localEngine.getLocalWebSockets().forEach(g -> disconnect(g.getUserid()).join());
this.localEngine.getLocalWebSockets().forEach(g -> g.close());
if (sncpNodeAddresses != null && localSncpAddress != null) {
sncpNodeAddresses.removeSetItem(SOURCE_SNCP_ADDRS_KEY, localSncpAddress);
}
@@ -92,13 +92,13 @@ public abstract class WebSocketNode {
protected abstract CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketRange wsrange, Object message, boolean last);
protected abstract CompletableFuture<Void> connect(Serializable userid, InetSocketAddress addr);
protected abstract CompletableFuture<Void> connect(Serializable userid, InetSocketAddress sncpAddr);
protected abstract CompletableFuture<Void> disconnect(Serializable userid, InetSocketAddress addr);
protected abstract CompletableFuture<Void> disconnect(Serializable userid, InetSocketAddress sncpAddr);
protected abstract CompletableFuture<Void> changeUserid(Serializable fromuserid, Serializable touserid, InetSocketAddress addr);
protected abstract CompletableFuture<Void> changeUserid(Serializable fromuserid, Serializable touserid, InetSocketAddress sncpAddr);
protected abstract CompletableFuture<Integer> forceCloseWebSocket(Serializable userid, InetSocketAddress addr);
protected abstract CompletableFuture<Integer> forceCloseWebSocket(Serializable userid, @RpcTargetAddress InetSocketAddress targetAddress);
//--------------------------------------------------------------------------------
final CompletableFuture<Void> connect(final Serializable userid) {
@@ -221,7 +221,7 @@ public abstract class WebSocketNode {
* @return int
*/
@Local
public final CompletableFuture<Integer> forceCloseWebSocket(final Serializable userid) {
public CompletableFuture<Integer> forceCloseWebSocket(final Serializable userid) {
CompletableFuture<Integer> localFuture = null;
if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userid));
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
@@ -244,7 +244,7 @@ public abstract class WebSocketNode {
}
return future == null ? CompletableFuture.completedFuture(0) : future;
});
return localFuture.thenCombine(remoteFuture, (a, b) -> a + b);
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a + b);
}
//--------------------------------------------------------------------------------
@@ -380,7 +380,7 @@ public abstract class WebSocketNode {
* @return 为0表示成功 其他值表示部分发送异常
*/
@Local
public final CompletableFuture<Integer> sendMessage(final Convert convert, final Object message0, final boolean last, final Serializable... userids) {
public CompletableFuture<Integer> sendMessage(final Convert convert, final Object message0, final boolean last, final Serializable... userids) {
if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
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));
@@ -500,7 +500,7 @@ public abstract class WebSocketNode {
* @return 为0表示成功 其他值表示部分发送异常
*/
@Local
public final CompletableFuture<Integer> broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message0, final boolean last) {
public CompletableFuture<Integer> broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message0, final boolean last) {
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) { //本地模式且没有分布式
@@ -525,7 +525,7 @@ public abstract class WebSocketNode {
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
private CompletableFuture<Integer> sendOneMessage(final Object message, final boolean last, final Serializable userid) {
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");
@@ -559,7 +559,7 @@ public abstract class WebSocketNode {
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
private Object formatRemoteMessage(Object message) {
protected Object formatRemoteMessage(Object message) {
if (message instanceof WebSocketPacket) return message;
if (message instanceof byte[]) return message;
if (message instanceof CharSequence) return message;

View File

@@ -13,7 +13,6 @@ import java.nio.channels.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.logging.*;
@@ -39,10 +38,6 @@ class WebSocketRunner implements Runnable {
volatile boolean closed = false;
private final AtomicBoolean writing = new AtomicBoolean();
private final BlockingQueue<QueueEntry> writeQueue = new ArrayBlockingQueue(512);
private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用
protected long lastSendTime;
@@ -79,8 +74,8 @@ class WebSocketRunner implements Runnable {
@Override
public void completed(Integer count, Void attachment1) {
if (count < 1) {
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner(userid="+webSocket.getUserid()+") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
closeRunner(0, "read buffer count is " + count);
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner(userid=" + webSocket.getUserid() + ") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
closeRunner(CLOSECODE_ILLPACKET, "read buffer count is " + count);
return;
}
try {
@@ -187,17 +182,17 @@ class WebSocketRunner implements Runnable {
}
} else if (packet.type == FrameType.CLOSE) {
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner onMessage by CLOSE FrameType : " + packet);
closeRunner(0, "received CLOSE frame-type message");
closeRunner(CLOSECODE_CLIENTCLOSE, "received CLOSE frame-type message");
return;
} else {
context.getLogger().log(Level.WARNING, "WebSocketRunner onMessage by unknown FrameType : " + packet);
closeRunner(0, "received unknown frame-type message");
closeRunner(CLOSECODE_ILLPACKET, "received unknown frame-type message");
return;
}
}
} catch (Exception e) {
context.getLogger().log(Level.WARNING, "WebSocketRunner(userid=" + webSocket.getUserid() + ") onMessage by received error", e);
closeRunner(0, "websocket-received error");
closeRunner(CLOSECODE_WSEXCEPTION, "websocket-received error");
}
}
@@ -205,9 +200,9 @@ class WebSocketRunner implements Runnable {
public void failed(Throwable exc, Void attachment2) {
if (exc != null) {
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner read WebSocketPacket failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
closeRunner(0, "read websocket-packet failed");
closeRunner(CLOSECODE_WSEXCEPTION, "read websocket-packet failed");
} else {
closeRunner(RETCODE_ILLEGALBUFFER, "decode websocket-packet error");
closeRunner(CLOSECODE_WSEXCEPTION, "decode websocket-packet error");
}
}
});
@@ -217,7 +212,7 @@ class WebSocketRunner implements Runnable {
}
} catch (Throwable e) {
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner abort on read bytes from channel, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", e);
closeRunner(0, "read bytes from channel error");
closeRunner(CLOSECODE_WSEXCEPTION, "read bytes from channel error");
}
}
@@ -228,12 +223,6 @@ class WebSocketRunner implements Runnable {
//System.out.println("推送消息");
final CompletableFuture<Integer> futureResult = new CompletableFuture<>();
try {
synchronized (writing) {
if (writing.getAndSet(true)) {
writeQueue.add(new QueueEntry(futureResult, packet));
return futureResult;
}
}
ByteBuffer[] buffers = packet.sendBuffers != null ? packet.duplicateSendBuffers() : packet.encode(this.context.getBufferSupplier(), this.context.getBufferConsumer(), webSocket._engine.cryptor);
//if (debug) context.getLogger().log(Level.FINEST, "wsrunner.sending websocket message: " + packet);
@@ -277,18 +266,6 @@ class WebSocketRunner implements Runnable {
}
}
}
QueueEntry entry = null;
synchronized (writing) {
entry = writeQueue.poll();
if (entry == null) writing.set(false);
}
if (entry != null) {
future = entry.future;
ByteBuffer[] buffers = entry.packet.sendBuffers != null ? entry.packet.duplicateSendBuffers() : entry.packet.encode(context.getBufferSupplier(), context.getBufferConsumer(), webSocket._engine.cryptor);
lastSendTime = System.currentTimeMillis();
//if (debug) context.getLogger().log(Level.FINEST, "wsrunner.sending websocket message: " + entry.packet);
channel.write(buffers, buffers, this);
}
} catch (Exception e) {
future.complete(RETCODE_SENDEXCEPTION);
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on rewrite");
@@ -298,7 +275,6 @@ class WebSocketRunner implements Runnable {
@Override
public void failed(Throwable exc, ByteBuffer[] attachments) {
writing.set(false);
future.complete(RETCODE_SENDEXCEPTION);
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on CompletionHandler");
if (exc != null) {
@@ -308,7 +284,6 @@ class WebSocketRunner implements Runnable {
}
});
} catch (Exception t) {
writing.set(false);
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);
@@ -321,21 +296,17 @@ class WebSocketRunner implements Runnable {
return closed;
}
public void closeRunner(int code, String reason) {
if (closed) return;
public CompletableFuture<Void> closeRunner(int code, String reason) {
if (closed) return null;
synchronized (this) {
if (closed) return;
if (closed) return null;
closed = true;
channel.dispose();
context.offerBuffer(readBuffer);
readBuffer = null;
engine.removeThenClose(webSocket);
CompletableFuture<Void> future = engine.removeThenClose(webSocket);
webSocket.onClose(code, reason);
QueueEntry entry = writeQueue.poll();
while (entry != null) {
entry.future.complete(RETCODE_WSOCKET_CLOSED);
entry = writeQueue.poll();
}
return future;
}
}

View File

@@ -330,9 +330,11 @@ public final class SncpClient {
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
}
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
} catch (RpcRemoteException re) {
throw re;
} catch (InterruptedException | ExecutionException | TimeoutException e) {
logger.log(Level.SEVERE, actions[index].method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote error", e);
throw new RuntimeException(actions[index].method + " sncp remote error", e);
//logger.log(Level.SEVERE, actions[index].method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote error", e);
throw new RpcRemoteException(actions[index].method + " sncp remote error", e);
} finally {
bsonConvert.offerBsonReader(reader);
}
@@ -403,7 +405,7 @@ public final class SncpClient {
public void completed(Integer count, Void attachment2) {
try {
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
future.completeExceptionally(new RuntimeException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
transport.offerBuffer(buffer);
transport.offerConnection(true, conn);
return;

View File

@@ -53,6 +53,7 @@ public final class SncpRequest extends Request<SncpContext> {
@Override
protected int readHeader(ByteBuffer buffer) {
if (buffer.remaining() < HEADER_SIZE) {
if (buffer.hasRemaining()) buffer.get(new byte[buffer.remaining()]);
this.ping = true;
return 0;
}

View File

@@ -0,0 +1,33 @@
/*
* 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.service;
/**
* 供RPC协议使用
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class RpcRemoteException extends RuntimeException {
public RpcRemoteException() {
super();
}
public RpcRemoteException(String s) {
super(s);
}
public RpcRemoteException(String message, Throwable cause) {
super(message, cause);
}
public RpcRemoteException(Throwable cause) {
super(cause);
}
}

View File

@@ -56,13 +56,13 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
}
@Override
public CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress addr, Object message, boolean last, Serializable userid) {
public CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable userid) {
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
return this.localEngine.sendMessage(message, last, userid);
}
@Override
public CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress addr, final WebSocketRange wsrange, Object message, boolean last) {
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);
}
@@ -124,15 +124,15 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
/**
* 强制关闭用户的WebSocket
*
* @param userid Serializable
* @param sncpAddr InetSocketAddress
* @param userid Serializable
* @param targetAddress InetSocketAddress
*
* @return 无返回值
*/
@Override
public CompletableFuture<Integer> forceCloseWebSocket(Serializable userid, InetSocketAddress sncpAddr) {
public CompletableFuture<Integer> forceCloseWebSocket(Serializable userid, @RpcTargetAddress InetSocketAddress targetAddress) {
//不能从sncpNodeAddresses中移除因为engine.forceCloseWebSocket 会调用到disconnect
if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " forceCloseWebSocket from " + sncpAddr);
if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " forceCloseWebSocket from " + targetAddress);
if (localEngine == null) return CompletableFuture.completedFuture(0);
return CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userid));
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@ import java.sql.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.Consumer;
import java.util.function.*;
import java.util.logging.Level;
import org.redkale.service.Local;
import org.redkale.util.*;
@@ -45,8 +45,8 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
}
@Override
protected PoolSource<Connection> createPoolSource(DataSource source, String rwtype, ArrayBlockingQueue queue, Properties prop) {
return new PoolJdbcSource(this.name, this.persistxml, rwtype, queue, prop, this.logger);
protected PoolSource<Connection> createPoolSource(DataSource source, String rwtype, ArrayBlockingQueue queue, Semaphore semaphore, Properties prop) {
return new PoolJdbcSource(this.name, this.persistxml, rwtype, queue, semaphore, prop, this.logger);
}
@Override
@@ -63,7 +63,12 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
conn.setAutoCommit(true);
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, values);
try {
prestmt.executeBatch();
int[] cs = prestmt.executeBatch();
int c1 = 0;
for (int cc : cs) {
c1 += cc;
}
c = c1;
} catch (SQLException se) {
if (info.tableStrategy == null || !info.isTableNotExist(se)) throw se;
synchronized (info.tables) {
@@ -142,7 +147,8 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
sb.append(ch);
}
}
logger.finest(info.getType().getSimpleName() + " insert sql=" + sb.toString().replaceAll("(\r|\n)", "\\n"));
String debugsql = sb.toString();
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " insert sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
}
} //打印结束
return CompletableFuture.completedFuture(c);
@@ -190,7 +196,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
conn.setReadOnly(false);
conn.setAutoCommit(true);
sql += ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit()));
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
final Statement stmt = conn.createStatement();
int c = stmt.executeUpdate(sql);
stmt.close();
@@ -251,7 +257,8 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
sb.append(ch);
}
}
logger.finest(info.getType().getSimpleName() + " update sql=" + sb.toString().replaceAll("(\r|\n)", "\\n"));
String debugsql = sb.toString();
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " update sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
} //打印结束
}
int[] pc = prestmt.executeBatch();
@@ -289,7 +296,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
prestmt.close();
return CompletableFuture.completedFuture(c);
} else {
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
final Statement stmt = conn.createStatement();
int c = stmt.executeUpdate(sql);
stmt.close();
@@ -453,7 +460,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
boolean rs = set.next() ? (set.getInt(1) > 0) : false;
set.close();
ps.close();
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " exists (" + rs + ") sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists (" + rs + ") sql=" + sql);
return CompletableFuture.completedFuture(rs);
} catch (SQLException e) {
if (info.tableStrategy != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(false);
@@ -476,10 +483,11 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
if ("mysql".equals(this.readPool.getDbtype()) || "postgresql".equals(this.readPool.getDbtype())) {
final String dbtype = this.readPool.getDbtype();
if ("mysql".equals(dbtype) || "postgresql".equals(dbtype)) {
final String listsql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + createSQLOrderby(info, flipper) + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset()));
if (info.isLoggable(logger, Level.FINEST)) {
if (info.isLoggable(logger, Level.FINEST, listsql)) {
logger.finest(info.getType().getSimpleName() + " query sql=" + listsql);
}
PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
@@ -490,18 +498,22 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
set.close();
ps.close();
long total = list.size();
final String countsql = "SELECT COUNT(*) FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
ps = conn.prepareStatement(countsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
set = ps.executeQuery();
if (set.next()) total = set.getLong(1);
set.close();
ps.close();
if (needtotal) {
final String countsql = "SELECT COUNT(*) FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (info.isLoggable(logger, Level.FINEST, countsql)) {
logger.finest(info.getType().getSimpleName() + " query countsql=" + countsql);
}
ps = conn.prepareStatement(countsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
set = ps.executeQuery();
if (set.next()) total = set.getLong(1);
set.close();
ps.close();
}
return CompletableFuture.completedFuture(new Sheet<>(total, list));
}
final String sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper);
if (info.isLoggable(logger, Level.FINEST)) {
if (info.isLoggable(logger, Level.FINEST, sql)) {
logger.finest(info.getType().getSimpleName() + " query sql=" + sql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset())));
}
conn.setReadOnly(true);
@@ -582,12 +594,15 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
* 直接本地执行SQL语句进行查询远程模式不可用 <br>
* 通常用于复杂的关联查询 <br>
*
* @param sql SQL语句
* @param consumer 回调函数
* @param <V> 泛型
* @param sql SQL语句
* @param handler 回调函数
*
* @return 结果
*/
@Local
@Override
public void directQuery(String sql, Consumer<ResultSet> consumer) {
public <V> V directQuery(String sql, Function<ResultSet, V> handler) {
final Connection conn = readPool.poll();
try {
if (logger.isLoggable(Level.FINEST)) logger.finest("direct query sql=" + sql);
@@ -595,9 +610,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
final Statement statement = conn.createStatement();
//final PreparedStatement statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = statement.executeQuery(sql);// ps.executeQuery();
consumer.accept(set);
V rs = handler.apply(set);
set.close();
statement.close();
return rs;
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {

View File

@@ -0,0 +1,141 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.source;
import java.io.Serializable;
import java.net.URL;
import java.sql.ResultSet;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import org.redkale.service.Local;
import org.redkale.util.*;
/**
*
*
* @author zhangjx
*/
/**
* DataSource的Memory实现类 <br>
* 注意: javax.persistence.jdbc.url 需要指定为 memory:source
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Local
@AutoLoad(false)
@SuppressWarnings("unchecked")
@ResourceType(DataSource.class)
public class DataMemorySource extends DataSqlSource<Void> {
public DataMemorySource(String unitName, URL persistxml, Properties readprop, Properties writeprop) {
super(unitName, persistxml, readprop, writeprop);
this.cacheForbidden = false;
}
@Local
@Override
public String getType() {
return "memory";
}
@Override
protected boolean isOnlyCache(EntityInfo info) {
return true;
}
@Local
@Override
public int directExecute(String sql) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Local
@Override
public int[] directExecute(String... sqls) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Local
@Override
public <V> V directQuery(String sql, Function<ResultSet, V> handler) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
protected boolean isAsync() {
return true;
}
@Override
protected String prepareParamSign(int index) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
protected PoolSource<Void> createPoolSource(DataSource source, String rwtype, ArrayBlockingQueue queue, Semaphore semaphore, Properties prop) {
return null;
}
@Override
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... values) {
return CompletableFuture.completedFuture(0);
}
@Override
protected <T> CompletableFuture<Integer> deleteDB(EntityInfo<T> info, Flipper flipper, String sql) {
return CompletableFuture.completedFuture(0);
}
@Override
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... values) {
return CompletableFuture.completedFuture(0);
}
@Override
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, Flipper flipper, String sql, boolean prepared, Object... params) {
return CompletableFuture.completedFuture(0);
}
@Override
protected <T, N extends Number> CompletableFuture<Map<String, N>> getNumberMapDB(EntityInfo<T> info, String sql, FilterFuncColumn... columns) {
return CompletableFuture.completedFuture(null);
}
@Override
protected <T> CompletableFuture<Number> getNumberResultDB(EntityInfo<T> info, String sql, Number defVal, String column) {
return CompletableFuture.completedFuture(defVal);
}
@Override
protected <T, K extends Serializable, N extends Number> CompletableFuture<Map<K, N>> queryColumnMapDB(EntityInfo<T> info, String sql, String keyColumn) {
return CompletableFuture.completedFuture(null);
}
@Override
protected <T> CompletableFuture<T> findDB(EntityInfo<T> info, String sql, boolean onlypk, SelectColumn selects) {
return CompletableFuture.completedFuture(null);
}
@Override
protected <T> CompletableFuture<Serializable> findColumnDB(EntityInfo<T> info, String sql, boolean onlypk, String column, Serializable defValue) {
return CompletableFuture.completedFuture(null);
}
@Override
protected <T> CompletableFuture<Boolean> existsDB(EntityInfo<T> info, String sql, boolean onlypk) {
return CompletableFuture.completedFuture(false);
}
@Override
protected <T> CompletableFuture<Sheet<T>> querySheetDB(EntityInfo<T> info, boolean needtotal, SelectColumn selects, Flipper flipper, FilterNode node) {
return CompletableFuture.completedFuture(new Sheet<>());
}
}

View File

@@ -23,7 +23,7 @@ public final class DataSources {
public static final String JDBC_CACHE_MODE = "javax.persistence.cachemode";
public static final String JDBC_CONNECTIONSMAX = "javax.persistence.connections.limit";
public static final String JDBC_CONNECTIONS_LIMIT = "javax.persistence.connections.limit";
public static final String JDBC_CONNECTIONSCAPACITY = "javax.persistence.connections.bufcapacity";
@@ -47,6 +47,8 @@ public final class DataSources {
public static final String JDBC_PWD = "javax.persistence.jdbc.password";
public static final String JDBC_ENCODING = "javax.persistence.jdbc.encoding";
public static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
public static final String JDBC_SOURCE = "javax.persistence.jdbc.source";
@@ -54,11 +56,11 @@ public final class DataSources {
private DataSources() {
}
public static DataSource createDataSource(final String unitName, Properties prop) throws IOException {
public static DataSource createDataSource2(final String unitName, Properties prop) throws IOException {
return new DataJdbcSource(unitName, null, prop, prop);
}
public static DataSource createDataSource(final String unitName, Properties readprop, Properties writeprop) throws IOException {
public static DataSource createDataSource2(final String unitName, Properties readprop, Properties writeprop) throws IOException {
return new DataJdbcSource(unitName, null, readprop, writeprop);
}
@@ -70,7 +72,7 @@ public final class DataSources {
public static DataSource createDataSource(final String unitName, URL persistxml) throws IOException {
if (persistxml == null) persistxml = DataSources.class.getResource("/persistence.xml");
InputStream in = persistxml.openStream();
InputStream in = persistxml == null ? null : persistxml.openStream();
if (in == null) return null;
Map<String, Properties> map = loadPersistenceXml(in);
Properties readprop = null;
@@ -101,6 +103,8 @@ public final class DataSources {
}
if (readprop == null) throw new IOException("Cannot find (resource.name = '" + unitName + "') DataSource");
if (writeprop == null) writeprop = readprop;
if (readprop.getProperty(JDBC_URL, "").startsWith("memory:source")) return new DataMemorySource(unitName, persistxml, readprop, writeprop);
String impl = readprop.getProperty(JDBC_DATASOURCE_CLASS, DataJdbcSource.class.getName());
if (DataJdbcSource.class.getName().equals(impl)) {
try {

View File

@@ -67,11 +67,13 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@SuppressWarnings({"OverridableMethodCallInConstructor", "LeakingThisInConstructor"})
public DataSqlSource(String unitName, URL persistxml, Properties readprop, Properties writeprop) {
if (readprop == null) readprop = new Properties();
if (writeprop == null) writeprop = readprop;
final AtomicInteger counter = new AtomicInteger();
this.threads = Integer.decode(readprop.getProperty(JDBC_CONNECTIONSMAX, "" + Runtime.getRuntime().availableProcessors() * 16));
int maxconns = Math.max(8, Integer.decode(readprop.getProperty(JDBC_CONNECTIONSMAX, "" + Runtime.getRuntime().availableProcessors() * 16)));
this.threads = Integer.decode(readprop.getProperty(JDBC_CONNECTIONS_LIMIT, "" + Runtime.getRuntime().availableProcessors() * 16));
int maxconns = Math.max(8, Integer.decode(readprop.getProperty(JDBC_CONNECTIONS_LIMIT, "" + Math.min(1000, Runtime.getRuntime().availableProcessors() * 200))));
if (readprop != writeprop) {
this.threads += Integer.decode(writeprop.getProperty(JDBC_CONNECTIONSMAX, "" + Runtime.getRuntime().availableProcessors() * 16));
this.threads += Integer.decode(writeprop.getProperty(JDBC_CONNECTIONS_LIMIT, "" + Runtime.getRuntime().availableProcessors() * 16));
maxconns = 0;
}
final String cname = this.getClass().getSimpleName();
@@ -92,7 +94,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
return t;
});
final int bufferCapacity = Math.max(8 * 1024, Integer.decode(readprop.getProperty(JDBC_CONNECTIONSCAPACITY, "" + 8 * 1024)));
this.bufferPool = new ObjectPool<>(new AtomicLong(), new AtomicLong(), this.threads,
this.bufferPool = new ObjectPool<>(new AtomicLong(), new AtomicLong(), Math.max(maxconns, this.threads * 2),
(Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false;
e.clear();
@@ -102,8 +104,9 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
this.persistxml = persistxml;
this.cacheForbidden = "NONE".equalsIgnoreCase(readprop.getProperty(JDBC_CACHE_MODE));
ArrayBlockingQueue<DBChannel> queue = maxconns > 0 ? new ArrayBlockingQueue(maxconns) : null;
this.readPool = createPoolSource(this, "read", queue, readprop);
this.writePool = createPoolSource(this, "write", queue, writeprop);
Semaphore semaphore = maxconns > 0 ? new Semaphore(maxconns) : null;
this.readPool = createPoolSource(this, "read", queue, semaphore, readprop);
this.writePool = createPoolSource(this, "write", queue, semaphore, writeprop);
}
@Local
@@ -113,7 +116,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public abstract int[] directExecute(String... sqls);
@Local
public abstract void directQuery(String sql, Consumer<ResultSet> consumer);
public abstract <V> V directQuery(String sql, Function<ResultSet, V> handler);
//是否异步, 为true则只能调用pollAsync方法为false则只能调用poll方法
protected abstract boolean isAsync();
@@ -122,7 +125,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
protected abstract String prepareParamSign(int index);
//创建连接池
protected abstract PoolSource<DBChannel> createPoolSource(DataSource source, String rwtype, ArrayBlockingQueue queue, Properties prop);
protected abstract PoolSource<DBChannel> createPoolSource(DataSource source, String rwtype, ArrayBlockingQueue queue, Semaphore semaphore, Properties prop);
//插入纪录
protected abstract <T> CompletableFuture<Integer> insertDB(final EntityInfo<T> info, T... values);
@@ -205,8 +208,8 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Local
@Override
public void close() throws Exception {
readPool.close();
writePool.close();
if (readPool != null) readPool.close();
if (writePool != null) writePool.close();
}
@Local
@@ -226,7 +229,11 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
}
protected <T> EntityInfo<T> loadEntityInfo(Class<T> clazz) {
return EntityInfo.load(clazz, this.cacheForbidden, this.readPool.props, this, fullloader);
return EntityInfo.load(clazz, this.cacheForbidden, this.readPool == null ? null : this.readPool.props, this, fullloader);
}
protected boolean isOnlyCache(EntityInfo info) {
return info.isVirtualEntity();
}
/**
@@ -282,7 +289,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
info.createPrimaryValue(value);
}
}
if (info.isVirtualEntity()) return insertCache(info, values);
if (isOnlyCache(info)) return insertCache(info, values);
return insertDB(info, values).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -303,7 +310,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
info.createPrimaryValue(value);
}
}
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> insertCache(info, values), getExecutor());
}
if (isAsync()) return insertDB(info, values).whenComplete((rs, t) -> {
@@ -390,7 +397,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T> int delete(Class<T> clazz, Serializable... ids) {
if (ids.length == 0) return -1;
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return deleteCache(info, -1, ids);
if (isOnlyCache(info)) return deleteCache(info, -1, ids);
return deleteCompose(info, ids).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -404,7 +411,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Serializable... ids) {
if (ids.length == 0) return CompletableFuture.completedFuture(-1);
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> deleteCache(info, -1, ids), getExecutor());
}
if (isAsync()) return deleteCompose(info, ids).whenComplete((rs, t) -> {
@@ -436,7 +443,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T> int delete(Class<T> clazz, final Flipper flipper, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return deleteCache(info, -1, flipper, node);
if (isOnlyCache(info)) return deleteCache(info, -1, flipper, node);
return DataSqlSource.this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -449,7 +456,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Flipper flipper, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> deleteCache(info, -1, flipper, node), getExecutor());
}
if (isAsync()) return DataSqlSource.this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> {
@@ -479,7 +486,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
sql += FilterNode.formatToString(ids[i]);
}
sql += ")";
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
return deleteDB(info, null, sql);
}
@@ -498,7 +505,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
String sql = "DELETE " + ("mysql".equals(this.readPool.getDbtype()) ? "a" : "") + " FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1))
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + info.createSQLOrderby(flipper);
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " delete sql="
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql="
+ (sql + ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit()))));
return deleteDB(info, flipper, sql);
}
@@ -561,7 +568,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
checkEntity("update", false, values);
final Class<T> clazz = (Class<T>) values[0].getClass();
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return updateCache(info, -1, values);
if (isOnlyCache(info)) return updateCache(info, -1, values);
return updateDB(info, values).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -578,7 +585,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
if (future != null) return future;
final Class<T> clazz = (Class<T>) values[0].getClass();
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return CompletableFuture.supplyAsync(() -> updateCache(info, -1, values), getExecutor());
if (isOnlyCache(info)) return CompletableFuture.supplyAsync(() -> updateCache(info, -1, values), getExecutor());
if (isAsync()) return updateDB(info, values).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -609,7 +616,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T> int updateColumn(Class<T> clazz, Serializable id, String column, Serializable value) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return updateCache(info, -1, id, column, value);
if (isOnlyCache(info)) return updateCache(info, -1, id, column, value);
return updateColumnCompose(info, id, column, value).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -622,7 +629,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable id, final String column, final Serializable value) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, id, column, value), getExecutor());
}
if (isAsync()) return updateColumnCompose(info, id, column, value).whenComplete((rs, t) -> {
@@ -666,7 +673,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T> int updateColumn(Class<T> clazz, String column, Serializable value, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return updateCache(info, -1, column, value, node);
if (isOnlyCache(info)) return updateCache(info, -1, column, value, node);
return DataSqlSource.this.updateColumnCompose(info, column, value, node).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -679,7 +686,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final String column, final Serializable value, final FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, column, value, node), getExecutor());
}
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, column, value, node).whenComplete((rs, t) -> {
@@ -740,7 +747,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
if (values == null || values.length < 1) return -1;
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return updateCache(info, -1, id, values);
if (isOnlyCache(info)) return updateCache(info, -1, id, values);
return DataSqlSource.this.updateColumnCompose(info, id, values).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -754,7 +761,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
if (values == null || values.length < 1) return CompletableFuture.completedFuture(-1);
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, id, values), getExecutor());
}
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, id, values).whenComplete((rs, t) -> {
@@ -819,7 +826,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
if (values == null || values.length < 1) return -1;
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return updateCache(info, -1, node, flipper, values);
if (isOnlyCache(info)) return updateCache(info, -1, node, flipper, values);
return DataSqlSource.this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -833,7 +840,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
if (values == null || values.length < 1) return CompletableFuture.completedFuture(-1);
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, node, flipper, values), getExecutor());
}
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> {
@@ -890,22 +897,22 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T> int updateColumn(final T bean, final String... columns) {
return updateColumn(bean, SelectColumn.createIncludes(columns));
return updateColumn(bean, SelectColumn.includes(columns));
}
@Override
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final String... columns) {
return updateColumnAsync(bean, SelectColumn.createIncludes(columns));
return updateColumnAsync(bean, SelectColumn.includes(columns));
}
@Override
public <T> int updateColumn(final T bean, final FilterNode node, final String... columns) {
return updateColumn(bean, node, SelectColumn.createIncludes(columns));
return updateColumn(bean, node, SelectColumn.includes(columns));
}
@Override
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final FilterNode node, final String... columns) {
return updateColumnAsync(bean, node, SelectColumn.createIncludes(columns));
return updateColumnAsync(bean, node, SelectColumn.includes(columns));
}
@Override
@@ -913,7 +920,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
if (bean == null || selects == null) return -1;
Class<T> clazz = (Class) bean.getClass();
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return updateCache(info, -1, false, bean, null, selects);
if (isOnlyCache(info)) return updateCache(info, -1, false, bean, null, selects);
return DataSqlSource.this.updateColumnCompose(info, false, bean, null, selects).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -928,7 +935,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
if (bean == null || selects == null) return CompletableFuture.completedFuture(-1);
Class<T> clazz = (Class) bean.getClass();
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, false, bean, null, selects), getExecutor());
}
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, false, bean, null, selects).whenComplete((rs, t) -> {
@@ -952,7 +959,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
if (bean == null || node == null || selects == null) return -1;
Class<T> clazz = (Class) bean.getClass();
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) return updateCache(info, -1, true, bean, node, selects);
if (isOnlyCache(info)) return updateCache(info, -1, true, bean, node, selects);
return DataSqlSource.this.updateColumnCompose(info, true, bean, node, selects).whenComplete((rs, t) -> {
if (t != null) {
futureCompleteConsumer.accept(rs, t);
@@ -967,7 +974,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
if (bean == null || node == null || selects == null) return CompletableFuture.completedFuture(-1);
Class<T> clazz = (Class) bean.getClass();
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
if (isOnlyCache(info)) {
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, true, bean, node, selects), getExecutor());
}
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, true, bean, node, selects).whenComplete((rs, t) -> {
@@ -1158,7 +1165,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) {
final EntityInfo info = loadEntityInfo(entityClass);
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) {
final Map map = new HashMap<>();
if (node == null || node.isCacheUseable(this)) {
for (FilterFuncColumn ffc : columns) {
@@ -1176,7 +1183,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <N extends Number> CompletableFuture<Map<String, N>> getNumberMapAsync(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) {
final EntityInfo info = loadEntityInfo(entityClass);
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) {
final Map map = new HashMap<>();
if (node == null || node.isCacheUseable(this)) {
for (FilterFuncColumn ffc : columns) {
@@ -1205,7 +1212,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
}
final String sql = "SELECT " + sb + " FROM " + info.getTable(node) + " a"
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " getnumbermap sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " getnumbermap sql=" + sql);
return getNumberMapDB(info, sql, columns);
}
@@ -1264,7 +1271,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) {
final EntityInfo info = loadEntityInfo(entityClass);
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) {
if (node == null || node.isCacheUseable(this)) {
return cache.getNumberResult(func, defVal, column, node);
}
@@ -1276,7 +1283,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public CompletableFuture<Number> getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) {
final EntityInfo info = loadEntityInfo(entityClass);
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) {
if (node == null || node.isCacheUseable(this)) {
return CompletableFuture.completedFuture(cache.getNumberResult(func, defVal, column, node));
}
@@ -1292,7 +1299,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT " + func.getColumn((column == null || column.isEmpty() ? "*" : info.getSQLColumn("a", column))) + " FROM " + info.getTable(node) + " a"
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (info.isLoggable(logger, Level.FINEST)) logger.finest(entityClass.getSimpleName() + " getnumberresult sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(entityClass.getSimpleName() + " getnumberresult sql=" + sql);
return getNumberResultDB(info, sql, defVal, column);
}
@@ -1321,7 +1328,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) {
final EntityInfo info = loadEntityInfo(entityClass);
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) {
if (node == null || node.isCacheUseable(this)) {
return cache.queryColumnMap(keyColumn, func, funcColumn, node);
}
@@ -1333,7 +1340,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
public <T, K extends Serializable, N extends Number> CompletableFuture<Map<K, N>> queryColumnMapAsync(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) {
final EntityInfo info = loadEntityInfo(entityClass);
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) {
if (node == null || node.isCacheUseable(this)) {
return CompletableFuture.completedFuture(cache.queryColumnMap(keyColumn, func, funcColumn, node));
}
@@ -1350,7 +1357,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT a." + sqlkey + ", " + func.getColumn((funcColumn == null || funcColumn.isEmpty() ? "*" : info.getSQLColumn("a", funcColumn)))
+ " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + sqlkey;
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql);
return queryColumnMapDB(info, sql, keyColumn);
}
@@ -1399,7 +1406,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
protected <T> CompletableFuture<T> findCompose(final EntityInfo<T> info, final SelectColumn selects, Serializable pk) {
final String sql = "SELECT " + info.getQueryColumns(null, selects) + " FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
return findDB(info, sql, true, selects);
}
@@ -1467,7 +1474,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
return findDB(info, sql, false, selects);
}
@@ -1536,7 +1543,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
protected <T> CompletableFuture<Serializable> findColumnCompose(final EntityInfo<T> info, String column, final Serializable defValue, final Serializable pk) {
final String sql = "SELECT " + info.getSQLColumn(null, column) + " FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
return findColumnDB(info, sql, true, column, defValue);
}
@@ -1568,7 +1575,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT " + info.getSQLColumn("a", column) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql);
return findColumnDB(info, sql, false, column, defValue);
}
@@ -1598,7 +1605,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
protected <T> CompletableFuture<Boolean> existsCompose(final EntityInfo<T> info, Serializable pk) {
final String sql = "SELECT COUNT(*) FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql);
return existsDB(info, sql, true);
}
@@ -1640,7 +1647,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (info.isLoggable(logger, Level.FINEST)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql);
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql);
return existsDB(info, sql, false);
}
@@ -1717,7 +1724,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
final List<T> list = queryList(clazz, SelectColumn.createIncludes(selectedColumn), flipper, node);
final List<T> list = queryList(clazz, SelectColumn.includes(selectedColumn), flipper, node);
final List<V> rs = new ArrayList<>();
if (list.isEmpty()) return rs;
final EntityInfo<T> info = loadEntityInfo(clazz);
@@ -1730,7 +1737,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T, V extends Serializable> CompletableFuture<List<V>> queryColumnListAsync(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return queryListAsync(clazz, SelectColumn.createIncludes(selectedColumn), flipper, node).thenApply((List<T> list) -> {
return queryListAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((List<T> list) -> {
final List<V> rs = new ArrayList<>();
if (list.isEmpty()) return rs;
final EntityInfo<T> info = loadEntityInfo(clazz);
@@ -1766,7 +1773,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
Sheet<T> sheet = querySheet(clazz, SelectColumn.createIncludes(selectedColumn), flipper, node);
Sheet<T> sheet = querySheet(clazz, SelectColumn.includes(selectedColumn), flipper, node);
final Sheet<V> rs = new Sheet<>();
if (sheet.isEmpty()) return rs;
rs.setTotal(sheet.getTotal());
@@ -1782,7 +1789,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
@Override
public <T, V extends Serializable> CompletableFuture<Sheet<V>> queryColumnSheetAsync(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return querySheetAsync(clazz, SelectColumn.createIncludes(selectedColumn), flipper, node).thenApply((Sheet<T> sheet) -> {
return querySheetAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((Sheet<T> sheet) -> {
final Sheet<V> rs = new Sheet<>();
if (sheet.isEmpty()) return rs;
rs.setTotal(sheet.getTotal());
@@ -2173,7 +2180,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final EntityCache<T> cache = info.getCache();
if (readcache && cache != null && cache.isFullLoaded()) {
if (node == null || node.isCacheUseable(this)) {
if (info.isLoggable(logger, Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createPredicate(cache)));
if (info.isLoggable(logger, Level.FINEST, " cache query predicate = ")) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createPredicate(cache)));
return CompletableFuture.completedFuture(cache.querySheet(needtotal, selects, flipper, node));
}
}

View File

@@ -99,7 +99,12 @@ public final class EntityCache<T> {
}
public void fullLoad() {
if (info.fullloader == null) return;
if (info.fullloader == null) {
this.list = new ConcurrentLinkedQueue();
this.map = new ConcurrentHashMap();
this.fullloaded = true;
return;
}
this.fullloaded = false;
ConcurrentHashMap newmap = new ConcurrentHashMap();
List<T> all = info.fullloader.apply(info.source, type);
@@ -437,7 +442,7 @@ public final class EntityCache<T> {
public int insert(T value) {
if (value == null) return 0;
final T rs = newReproduce.apply(this.creator.create(), value); //确保同一主键值的map与list中的对象必须共用。
T old = this.map.put(this.primary.get(rs), rs);
T old = this.map.putIfAbsent(this.primary.get(rs), rs);
if (old == null) {
this.list.add(rs);
return 1;

View File

@@ -138,6 +138,9 @@ public final class EntityInfo<T> {
//日志级别从LogLevel获取
private final int logLevel;
//日志控制
private final Map<Integer, String[]> excludeLogLevels;
//Flipper.sort转换成以ORDER BY开头SQL的缓存
private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>();
@@ -210,13 +213,34 @@ public final class EntityInfo<T> {
LogLevel ll = type.getAnnotation(LogLevel.class);
this.logLevel = ll == null ? Integer.MIN_VALUE : Level.parse(ll.value()).intValue();
Map<Integer, HashSet<String>> logmap = new HashMap<>();
for (LogExcludeLevel lel : type.getAnnotationsByType(LogExcludeLevel.class)) {
for (String onelevel : lel.levels()) {
int level = Level.parse(onelevel).intValue();
HashSet<String> set = logmap.get(level);
if (set == null) {
set = new HashSet<>();
logmap.put(level, set);
}
for (String key : lel.keys()) {
set.add(key);
}
}
}
if (logmap.isEmpty()) {
this.excludeLogLevels = null;
} else {
this.excludeLogLevels = new HashMap<>();
logmap.forEach((l, set) -> excludeLogLevels.put(l, set.toArray(new String[set.size()])));
}
//---------------------------------------------
Table t = type.getAnnotation(Table.class);
if (type.getAnnotation(VirtualEntity.class) != null) {
if (type.getAnnotation(VirtualEntity.class) != null || "memory".equalsIgnoreCase(source.getType())) {
this.table = null;
BiFunction<DataSource, Class, List> loader = null;
try {
loader = type.getAnnotation(VirtualEntity.class).loader().getDeclaredConstructor().newInstance();
VirtualEntity ve = type.getAnnotation(VirtualEntity.class);
if (ve != null) loader = ve.loader().getDeclaredConstructor().newInstance();
} catch (Exception e) {
logger.log(Level.SEVERE, type + " init @VirtualEntity.loader error", e);
}
@@ -874,6 +898,26 @@ public final class EntityInfo<T> {
return logger.isLoggable(l) && l.intValue() >= this.logLevel;
}
/**
* 判断日志级别
*
* @param logger Logger
* @param l Level
* @param str String
*
* @return boolean
*/
public boolean isLoggable(Logger logger, Level l, String str) {
boolean rs = logger.isLoggable(l) && l.intValue() >= this.logLevel;
if (this.excludeLogLevels == null || !rs || str == null) return rs;
String[] keys = this.excludeLogLevels.get(l.intValue());
if (keys == null) return rs;
for (String key : keys) {
if (str.contains(key)) return false;
}
return rs;
}
/**
* 将字段值序列化为可SQL的字符串
*

View File

@@ -5,12 +5,8 @@
*/
package org.redkale.source;
import java.io.*;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import java.sql.*;
import java.util.*;
import java.util.concurrent.*;
@@ -27,20 +23,18 @@ import static org.redkale.source.DataSources.*;
*/
public class PoolJdbcSource extends PoolSource<Connection> {
private static final Map<String, AbstractMap.SimpleEntry<WatchService, List<WeakReference<PoolJdbcSource>>>> maps = new HashMap<>();
protected final ConnectionPoolDataSource source;
private final ConnectionPoolDataSource source;
protected final ArrayBlockingQueue<PooledConnection> queue;
private final ArrayBlockingQueue<PooledConnection> queue;
protected final ConnectionEventListener listener;
private final ConnectionEventListener listener;
protected final String unitName;
private final String unitName;
protected final URL persistxml;
private final URL persistxml;
public PoolJdbcSource(String unitName, URL persistxml, String rwtype, ArrayBlockingQueue aqueue, Properties prop, Logger logger) {
super(rwtype, prop, logger);
public PoolJdbcSource(String unitName, URL persistxml, String rwtype, ArrayBlockingQueue aqueue, Semaphore semaphore, Properties prop, Logger logger) {
super(rwtype, semaphore, prop, logger);
this.unitName = unitName;
this.persistxml = persistxml;
this.source = createDataSource(prop);
@@ -68,12 +62,6 @@ public class PoolJdbcSource extends PoolSource<Connection> {
logger.log(Level.WARNING, "connectionErronOccurred [" + event.getSQLException().getSQLState() + "]", event.getSQLException());
}
};
try {
this.watch();
} catch (Exception e) {
logger.log(Level.WARNING, DataSource.class.getSimpleName() + " watch " + persistxml + " error", e);
}
}
private static ConnectionPoolDataSource createDataSource(Properties property) {
@@ -152,74 +140,14 @@ public class PoolJdbcSource extends PoolSource<Connection> {
return 0;
}
private void watch() throws IOException {
if (persistxml == null || unitName == null) return;
final String file = persistxml.getFile();
final File f = new File(file);
if (!f.isFile() || !f.canRead()) return;
synchronized (maps) {
AbstractMap.SimpleEntry<WatchService, List<WeakReference<PoolJdbcSource>>> entry = maps.get(file);
if (entry != null) {
entry.getValue().add(new WeakReference<>(this));
return;
}
final WatchService watcher = f.toPath().getFileSystem().newWatchService();
final List<WeakReference<PoolJdbcSource>> list = new CopyOnWriteArrayList<>();
Thread watchThread = new Thread() {
@Override
public void run() {
try {
while (!this.isInterrupted()) {
final WatchKey key = watcher.take();
long d; //防止文件正在更新过程中去读取
for (;;) {
d = f.lastModified();
Thread.sleep(2000L);
if (d == f.lastModified()) break;
}
final Map<String, Properties> m = loadPersistenceXml(new FileInputStream(file));
key.pollEvents().stream().forEach((event) -> {
if (event.kind() != ENTRY_MODIFY) return;
if (!((Path) event.context()).toFile().getName().equals(f.getName())) return;
for (WeakReference<PoolJdbcSource> ref : list) {
PoolJdbcSource pool = ref.get();
if (pool == null) continue;
try {
Properties property = m.get(unitName);
if (property == null) property = m.get(unitName + "." + pool.rwtype);
if (property != null) pool.change(property);
} catch (Exception ex) {
logger.log(Level.INFO, event.context() + " occur error", ex);
}
}
});
key.reset();
}
} catch (Exception e) {
logger.log(Level.WARNING, "DataSource watch " + file + " occur error", e);
}
}
};
f.getParentFile().toPath().register(watcher, ENTRY_MODIFY);
watchThread.setName("DataSource-Watch-" + maps.size() + "-Thread");
watchThread.setDaemon(true);
watchThread.start();
logger.log(Level.INFO, watchThread.getName() + " start watching " + file);
//-----------------------------------------------------------
list.add(new WeakReference<>(this));
maps.put(file, new AbstractMap.SimpleEntry<>(watcher, list));
}
}
@Override
public void change(Properties property) {
Method seturlm;
Class clazz = source.getClass();
String newurl = property.getProperty(JDBC_URL);
String newuser = property.getProperty(JDBC_USER);
String newpassword = property.getProperty(JDBC_PWD);
if (this.url.equals(newurl) && this.username.equals(newuser) && this.password.equals(newpassword)) return;
String newurl = property.getProperty(JDBC_URL, this.url);
String newuser = property.getProperty(JDBC_USER, this.username);
String newpassword = property.getProperty(JDBC_PWD, this.password);
if (Objects.equals(this.url, newurl) && Objects.equals(this.username, newuser) && Objects.equals(this.password, newpassword)) return;
try {
try {
seturlm = clazz.getMethod("setUrl", String.class);

View File

@@ -7,7 +7,7 @@ package org.redkale.source;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;
import static org.redkale.source.DataSources.*;
@@ -23,6 +23,8 @@ import static org.redkale.source.DataSources.*;
*/
public abstract class PoolSource<DBChannel> {
protected final AtomicLong closeCounter = new AtomicLong();
protected final AtomicLong usingCounter = new AtomicLong();
protected final AtomicLong creatCounter = new AtomicLong();
@@ -31,6 +33,8 @@ public abstract class PoolSource<DBChannel> {
protected final AtomicLong saveCounter = new AtomicLong();
protected final Semaphore semaphore;
protected final Logger logger;
protected final String rwtype; // "" 或 "read" 或 "write"
@@ -55,22 +59,26 @@ public abstract class PoolSource<DBChannel> {
protected String database;
protected String encoding;
protected Properties props;
protected Properties attributes = new Properties();
@SuppressWarnings("OverridableMethodCallInConstructor")
public PoolSource(String rwtype, Properties prop, Logger logger) {
public PoolSource(String rwtype, Semaphore semaphore, Properties prop, Logger logger) {
this.logger = logger;
this.rwtype = rwtype;
this.props = prop;
this.url = prop.getProperty(JDBC_URL);
this.username = prop.getProperty(JDBC_USER, "");
this.password = prop.getProperty(JDBC_PWD, "");
this.encoding = prop.getProperty(JDBC_ENCODING, "");
this.connectTimeoutSeconds = Integer.decode(prop.getProperty(JDBC_CONNECTTIMEOUT_SECONDS, "3"));
this.readTimeoutSeconds = Integer.decode(prop.getProperty(JDBC_READTIMEOUT_SECONDS, "3"));
this.writeTimeoutSeconds = Integer.decode(prop.getProperty(JDBC_WRITETIMEOUT_SECONDS, "3"));
this.maxconns = Math.max(8, Integer.decode(prop.getProperty(JDBC_CONNECTIONSMAX, "" + Runtime.getRuntime().availableProcessors() * 16)));
this.maxconns = Math.max(8, Integer.decode(prop.getProperty(JDBC_CONNECTIONS_LIMIT, "" + Runtime.getRuntime().availableProcessors() * 100)));
this.semaphore = semaphore == null ? new Semaphore(this.maxconns) : semaphore;
String dbtype0 = "";
{ //jdbc:mysql:// jdbc:microsoft:sqlserver:// 取://之前的到最后一个:之间的字符串
int pos = this.url.indexOf("://");
@@ -83,6 +91,7 @@ public abstract class PoolSource<DBChannel> {
pos = url0.indexOf(':');
if (pos > 0) dbtype0 = url0.substring(0, pos);
}
if ("mysqlx".equalsIgnoreCase(dbtype0)) dbtype0 = "mysql"; //MySQL X DevAPI
}
this.dbtype = dbtype0.toLowerCase();
parseAddressAndDbnameAndAttrs();
@@ -108,6 +117,8 @@ public abstract class PoolSource<DBChannel> {
if (!this.props.containsKey(JDBC_TABLENOTEXIST_SQLSTATES)) {
this.props.setProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42P01;3F000");
}
} else if ("mysql".equals(this.dbtype)) {
if (this.encoding.isEmpty()) this.encoding = attributes.getProperty("characterEncoding", "");
}
}
@@ -152,6 +163,10 @@ public abstract class PoolSource<DBChannel> {
return dbtype;
}
public final long getCloseCount() {
return closeCounter.longValue();
}
public final long getUsingCount() {
return usingCounter.longValue();
}

View File

@@ -9,7 +9,7 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.sql.*;
import java.util.Properties;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import org.redkale.net.AsyncConnection;
@@ -28,13 +28,20 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
//线程池
protected ThreadPoolExecutor executor;
//供supplyAsync->poll使用的线程池
protected ExecutorService pollExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 4, (r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
});
//TCP Channel组
protected AsynchronousChannelGroup group;
protected final ArrayBlockingQueue<AsyncConnection> connQueue;
public PoolTcpSource(String rwtype, ArrayBlockingQueue queue, Properties prop, Logger logger, ObjectPool<ByteBuffer> bufferPool, ThreadPoolExecutor executor) {
super(rwtype, prop, logger);
public PoolTcpSource(String rwtype, ArrayBlockingQueue queue, Semaphore semaphore, Properties prop, Logger logger, ObjectPool<ByteBuffer> bufferPool, ThreadPoolExecutor executor) {
super(rwtype, semaphore, prop, logger);
this.bufferPool = bufferPool;
this.executor = executor;
try {
@@ -48,7 +55,7 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
@Override
public void offerConnection(final AsyncConnection conn) {
if (conn == null) return;
if (connQueue.offer(conn)) {
if (conn.isOpen() && connQueue.offer(conn)) {
saveCounter.incrementAndGet();
usingCounter.decrementAndGet();
} else {
@@ -70,10 +77,10 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
@Override
public void change(Properties prop) {
String newurl = prop.getProperty(JDBC_URL);
String newuser = prop.getProperty(JDBC_USER, "");
String newpassword = prop.getProperty(JDBC_PWD, "");
if (this.url.equals(newurl) && this.username.equals(newuser) && this.password.equals(newpassword)) return;
String newurl = prop.getProperty(JDBC_URL, this.url);
String newuser = prop.getProperty(JDBC_USER, this.username);
String newpassword = prop.getProperty(JDBC_PWD, this.password);
if (Objects.equals(this.url, newurl) && Objects.equals(this.username, newuser) && Objects.equals(this.password, newpassword)) return;
this.url = newurl;
this.username = newuser;
this.password = newpassword;
@@ -95,28 +102,31 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
}
protected CompletableFuture<AsyncConnection> pollAsync(final int count) {
if (count >= 3) {
if (count >= 5) {
logger.log(Level.WARNING, "create datasource connection error");
CompletableFuture<AsyncConnection> future = new CompletableFuture<>();
future.completeExceptionally(new SQLException("create datasource connection error"));
return future;
}
AsyncConnection conn0 = connQueue.poll();
if (conn0 != null && conn0.isOpen()) {
cycleCounter.incrementAndGet();
usingCounter.incrementAndGet();
return CompletableFuture.completedFuture(conn0);
}
if (usingCounter.get() >= maxconns && count < 2) {
if (!semaphore.tryAcquire()) {
return CompletableFuture.supplyAsync(() -> {
try {
return connQueue.poll(3, TimeUnit.SECONDS);
return connQueue.poll(1, TimeUnit.SECONDS);
} catch (Exception t) {
return null;
}
}, executor).thenCompose((conn2) -> {
}, pollExecutor).thenCompose((conn2) -> {
if (conn2 != null && conn2.isOpen()) {
cycleCounter.incrementAndGet();
usingCounter.incrementAndGet();
return CompletableFuture.completedFuture(conn2);
}
return pollAsync(count + 1);
@@ -124,9 +134,14 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
}
return AsyncConnection.createTCP(group, this.servaddr, this.readTimeoutSeconds, this.writeTimeoutSeconds).thenCompose(conn -> {
conn.beforeCloseListener((c) -> usingCounter.decrementAndGet());
conn.beforeCloseListener((c) -> {
semaphore.release();
closeCounter.incrementAndGet();
usingCounter.decrementAndGet();
});
CompletableFuture<AsyncConnection> future = new CompletableFuture();
final ByteBuffer buffer = reqConnectBuffer(conn);
if (buffer == null) {
final ByteBuffer rbuffer = bufferPool.get();
conn.read(rbuffer, null, new CompletionHandler<Integer, Void>() {
@@ -193,6 +208,8 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
if (t == null) {
creatCounter.incrementAndGet();
usingCounter.incrementAndGet();
} else {
semaphore.release();
}
});
}

View File

@@ -140,6 +140,7 @@ public interface Creator<T> {
}
final List<String> fieldnames = new ArrayList<>();
new ClassReader(out.toByteArray()).accept(new SimpleClassVisitor(Opcodes.ASM6, fieldnames, constructorDesc), 0);
while (fieldnames.remove(" ")); //删掉空元素
if (fieldnames.isEmpty()) return null;
if (paramcount == fieldnames.size()) {
return getConstructorField(clazz, paramcount, fieldnames.toArray(new String[fieldnames.size()]));

View File

@@ -0,0 +1,46 @@
/*
* 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.util;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 等于level日志级别且包含keys字符串的日志才会被排除 <br>
*
* <blockquote><pre>
* &#64;LogExcludeLevel(levels = {"FINEST"}, keys = {"SET username ="})
* public class UserRecord {
* public int userid;
* public String username = "";
* }
*
* 这样当调用DataSource对UserRecord对象进行操作时拼接的SQL语句含"SET username ="字样的都会在FINEST日志级别过滤掉
* </pre></blockquote>
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({TYPE})
@Retention(RUNTIME)
@Repeatable(LogExcludeLevel.LogExcludeLevels.class)
public @interface LogExcludeLevel {
String[] levels();
String[] keys();
@Documented
@Target({TYPE})
@Retention(RUNTIME)
@interface LogExcludeLevels {
LogExcludeLevel[] value();
}
}

View File

@@ -5,7 +5,7 @@
*/
package org.redkale.util;
/**
/**
* <p>
* 详情见: https://redkale.org
*
@@ -17,7 +17,7 @@ public final class Redkale {
}
public static String getDotedVersion() {
return "1.9.3";
return "1.9.6";
}
public static int getMajorVersion() {

View File

@@ -70,6 +70,7 @@ public class SelectColumn implements Predicate<String> {
}
/**
* @deprecated
* class中的字段名
*
* @param columns 包含的字段名集合
@@ -81,6 +82,18 @@ public class SelectColumn implements Predicate<String> {
}
/**
* class中的字段名
*
* @param columns 包含的字段名集合
*
* @return SelectColumn
*/
public static SelectColumn includes(String... columns) {
return new SelectColumn(columns, false);
}
/**
* @deprecated
* class中的字段名
*
* @param cols 包含的字段名集合
@@ -93,6 +106,20 @@ public class SelectColumn implements Predicate<String> {
}
/**
* class中的字段名
*
* @param cols 包含的字段名集合
* @param columns 包含的字段名集合
*
* @return SelectColumn
*/
public static SelectColumn includes(String[] cols, String... columns) {
return new SelectColumn(Utility.append(cols, columns), false);
}
/**
* @deprecated
*
* class中的字段名
*
* @param columns 排除的字段名集合
@@ -104,6 +131,18 @@ public class SelectColumn implements Predicate<String> {
}
/**
* class中的字段名
*
* @param columns 排除的字段名集合
*
* @return SelectColumn
*/
public static SelectColumn excludes(String... columns) {
return new SelectColumn(columns, true);
}
/**
* @deprecated
* class中的字段名
*
* @param cols 排除的字段名集合
@@ -115,6 +154,19 @@ public class SelectColumn implements Predicate<String> {
return new SelectColumn(Utility.append(cols, columns), true);
}
/**
*
* class中的字段名
*
* @param cols 排除的字段名集合
* @param columns 排除的字段名集合
*
* @return SelectColumn
*/
public static SelectColumn excludes(String[] cols, String... columns) {
return new SelectColumn(Utility.append(cols, columns), true);
}
@Override
public boolean test(final String column) {
if (this.columns != null) {

View File

@@ -374,6 +374,24 @@ public final class Utility {
return min;
}
/**
* 将char数组用分隔符拼接成字符串
*
* @param array 数组
* @param delimiter 分隔符
*
* @return String
*/
public static String joining(final char[] array, final String delimiter) {
if (array == null || array.length == 0) return "";
StringBuilder sb = new StringBuilder();
for (char i : array) {
if (sb.length() > 0) sb.append(delimiter);
sb.append(i);
}
return sb.toString();
}
/**
* 将int数组用分隔符拼接成字符串
*
@@ -429,6 +447,23 @@ public final class Utility {
return sb.toString();
}
/**
* 将一个或多个char新元素添加到char数组结尾
*
* @param array 原数组
* @param objs 待追加数据
*
* @return 新数组
*/
public static char[] append(final char[] array, final char... objs) {
if (array == null || array.length == 0) return objs;
if (objs == null || objs.length == 0) return array;
final char[] news = new char[array.length + objs.length];
System.arraycopy(array, 0, news, 0, array.length);
System.arraycopy(objs, 0, news, array.length, objs.length);
return news;
}
/**
* 将一个或多个int新元素添加到int数组结尾
*
@@ -566,6 +601,22 @@ public final class Utility {
return false;
}
/**
* 判断指定值是否包含指定的数组中包含返回true
*
* @param values 集合
* @param value 单值
*
* @return boolean
*/
public static boolean contains(char[] values, char value) {
if (values == null) return false;
for (char v : values) {
if (v == value) return true;
}
return false;
}
/**
* 判断指定值是否包含指定的数组中包含返回true
*
@@ -1691,12 +1742,11 @@ public final class Utility {
conn.setRequestProperty(en.getKey(), en.getValue());
}
}
if (body != null) {
{
conn.setDoInput(true);
conn.setDoOutput(true);
conn.getOutputStream().write(body.getBytes(UTF_8));
conn.getOutputStream().write(body == null ? new byte[0] : body.getBytes(UTF_8));
}
conn.setUseCaches(false);
conn.connect();
int rs = conn.getResponseCode();
if (rs == 301 || rs == 302) {

View File

@@ -0,0 +1,40 @@
/*
* 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.test.rest;
import org.redkale.convert.json.JsonFactory;
/**
*
* @author zhangjx
*/
public class LoginBean {
private String account = "";
private String password = "";
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return JsonFactory.root().getConvert().convertTo(this);
}
}

View File

@@ -5,7 +5,7 @@
*/
package org.redkale.test.rest;
import org.redkale.service.Service;
import org.redkale.service.*;
/**
* 简单的定义UserService接口
@@ -18,4 +18,8 @@ public class UserService implements Service {
public UserInfo current(String sessionid) {
return new UserInfo();
}
public RetResult<UserInfo> login(LoginBean bean) {
return new RetResult<>(new UserInfo());
}
}

View File

@@ -10,6 +10,8 @@ import java.util.*;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Resource;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.test.rest.*;
/**
*
@@ -23,15 +25,27 @@ public class ChatWebSocket extends WebSocket<Integer, Object> {
@Resource
protected ChatService service;
@Resource
protected UserService userService;
protected UserInfo user;
@Override
protected CompletableFuture<String> onOpen(final HttpRequest request) {
//随机创建一个sessionid
return CompletableFuture.completedFuture(request.getSessionid(true));
LoginBean bean = request.getJsonParameter(LoginBean.class, "bean");
RetResult<UserInfo> ret = userService.login(bean);
if (ret.isSuccess()) { //登录成功
user = ret.getResult();
//随机创建一个sessionid
return CompletableFuture.completedFuture(request.getSessionid(true));
} else { //登录失败, 返回null
return send("{\"onLoginFailMessage\":" + ret + "}").thenApply(x -> null);
}
}
@Override
protected CompletableFuture<Integer> createUserid() {
return CompletableFuture.completedFuture(service.createUserid());
return CompletableFuture.completedFuture(user.getUserid());
}
/**