Compare commits
61 Commits
2.0.0.beta
...
2.0.0.rc3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b69e7d02b | ||
|
|
02a10bf014 | ||
|
|
004b83172e | ||
|
|
fee4555cef | ||
|
|
758bd7de72 | ||
|
|
b2dd366640 | ||
|
|
934c82eadd | ||
|
|
c7ed6574cc | ||
|
|
2ea2667fa7 | ||
|
|
34ae2d38c5 | ||
|
|
a1c95544cb | ||
|
|
c6dc38c35c | ||
|
|
39203ab598 | ||
|
|
51a95a84aa | ||
|
|
8a8d45e642 | ||
|
|
52eb7dbc0c | ||
|
|
0e14b60f12 | ||
|
|
d373ab7204 | ||
|
|
4f9a563ba7 | ||
|
|
852da19b1e | ||
|
|
ddfc040a53 | ||
|
|
df3ccb763a | ||
|
|
f42561ca93 | ||
|
|
580e28519a | ||
|
|
9ecc1d8f19 | ||
|
|
40629ed7b9 | ||
|
|
5790135add | ||
|
|
fd862ed6c6 | ||
|
|
33763af96c | ||
|
|
7c05df3cfb | ||
|
|
f471e2d4c5 | ||
|
|
d4fd093521 | ||
|
|
40003c7789 | ||
|
|
b94f99f338 | ||
|
|
bd21644571 | ||
|
|
5f3599d9b8 | ||
|
|
1e4a30bd70 | ||
|
|
e7dc5de9f2 | ||
|
|
ccb9cb28f5 | ||
|
|
4d9b72c922 | ||
|
|
a51ae13a39 | ||
|
|
dfca186688 | ||
|
|
fadd229a89 | ||
|
|
7acc69adc4 | ||
|
|
d88e4120a1 | ||
|
|
ef98edd91a | ||
|
|
f4548bbe34 | ||
|
|
11a5faca1d | ||
|
|
c37b0e8cb5 | ||
|
|
a20570a6eb | ||
|
|
5e3edb7e1d | ||
|
|
ad8f1d2da6 | ||
|
|
24b23c894f | ||
|
|
c551d5fb81 | ||
|
|
fba43894c1 | ||
|
|
22cc7e086c | ||
|
|
1791008729 | ||
|
|
90e15dd253 | ||
|
|
7db73c076c | ||
|
|
95ad6e99d9 | ||
|
|
0b2a5d0f61 |
@@ -1 +0,0 @@
|
||||
<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>
|
||||
@@ -16,10 +16,6 @@
|
||||
<directory>${project.basedir}/conf</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/libs</directory>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/logs</directory>
|
||||
<outputDirectory>logs</outputDirectory>
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<addMavenDescriptor>false</addMavenDescriptor>
|
||||
<manifest>
|
||||
<mainClass>org.redkale.boot.Application</mainClass>
|
||||
</manifest>
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||
charset: 文本编码, 默认: UTF-8
|
||||
backlog: 默认10K
|
||||
threads: 线程数, 默认: CPU核数*32
|
||||
threads: 线程数, 默认: CPU核数*2,最小8个
|
||||
maxconns:最大连接数, 小于1表示无限制, 默认: 0
|
||||
maxbody: request.body最大值, 默认: 64K
|
||||
bufferCapacity: ByteBuffer的初始化大小, TCP默认: 32K; (HTTP 2.0、WebSocket,必须要16k以上); UDP默认: 1350B
|
||||
|
||||
@@ -30,5 +30,7 @@ module org.redkale {
|
||||
exports org.redkale.util;
|
||||
exports org.redkale.watch;
|
||||
|
||||
uses org.redkale.source.SourceLoader;
|
||||
uses org.redkale.util.ResourceInjectLoader;
|
||||
}
|
||||
*/
|
||||
@@ -196,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.getConfPath(), "apidoc-template.html");
|
||||
File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html");
|
||||
InputStream in = null;
|
||||
if (doctemplate.isFile() && doctemplate.canRead()) {
|
||||
in = new FileInputStream(doctemplate);
|
||||
|
||||
@@ -57,12 +57,12 @@ public final class Application {
|
||||
public static final String RESNAME_APP_TIME = "APP_TIME";
|
||||
|
||||
/**
|
||||
* 当前进程的根目录, 类型:String、File、Path
|
||||
* 当前进程的根目录, 类型:String、File、Path、URI
|
||||
*/
|
||||
public static final String RESNAME_APP_HOME = "APP_HOME";
|
||||
|
||||
/**
|
||||
* 当前进程的配置目录,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、File、Path
|
||||
* 当前进程的配置目录,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、File、Path、URI
|
||||
*/
|
||||
public static final String RESNAME_APP_CONF = "APP_CONF";
|
||||
|
||||
@@ -143,7 +143,7 @@ public final class Application {
|
||||
private final File home;
|
||||
|
||||
//配置文件目录
|
||||
private final File confPath;
|
||||
private final URI confPath;
|
||||
|
||||
//日志
|
||||
private final Logger logger;
|
||||
@@ -176,16 +176,19 @@ public final class Application {
|
||||
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
|
||||
this.resourceFactory.register(RESNAME_APP_HOME, Path.class, root.toPath());
|
||||
this.resourceFactory.register(RESNAME_APP_HOME, File.class, root);
|
||||
this.resourceFactory.register(RESNAME_APP_HOME, URI.class, root.toURI());
|
||||
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.confPath = new File(confsubpath).getCanonicalFile();
|
||||
if (confsubpath.contains("://")) {
|
||||
this.confPath = new URI(confsubpath);
|
||||
} else if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||
this.confPath = new File(confsubpath).getCanonicalFile().toURI();
|
||||
} else {
|
||||
this.confPath = new File(this.home, confsubpath).getCanonicalFile();
|
||||
this.confPath = new File(this.home, confsubpath).getCanonicalFile().toURI();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String localaddr = config.getValue("address", "").trim();
|
||||
@@ -209,11 +212,12 @@ public final class Application {
|
||||
System.setProperty(RESNAME_APP_NODE, node);
|
||||
}
|
||||
//以下是初始化日志配置
|
||||
final File logconf = new File(confPath, "logging.properties");
|
||||
if (logconf.isFile() && logconf.canRead()) {
|
||||
final URI logConfURI = "file".equals(confPath.getScheme()) ? new File(new File(confPath), "logging.properties").toURI()
|
||||
: URI.create(confPath.toString() + (confPath.toString().endsWith("/") ? "" : "/") + "logging.properties");
|
||||
if (!"file".equals(confPath.getScheme()) || (new File(logConfURI).isFile() && new File(logConfURI).canRead())) {
|
||||
try {
|
||||
final String rootpath = root.getCanonicalPath().replace('\\', '/');
|
||||
FileInputStream fin = new FileInputStream(logconf);
|
||||
InputStream fin = logConfURI.toURL().openStream();
|
||||
Properties properties = new Properties();
|
||||
properties.load(fin);
|
||||
fin.close();
|
||||
@@ -301,7 +305,7 @@ public final class Application {
|
||||
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
||||
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||
return t;
|
||||
});
|
||||
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
|
||||
@@ -316,7 +320,7 @@ public final class Application {
|
||||
transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
||||
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||
return t;
|
||||
});
|
||||
try {
|
||||
@@ -375,7 +379,7 @@ public final class Application {
|
||||
return home;
|
||||
}
|
||||
|
||||
public File getConfPath() {
|
||||
public URI getConfPath() {
|
||||
return confPath;
|
||||
}
|
||||
|
||||
@@ -398,10 +402,14 @@ 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.confPath, "persistence.xml");
|
||||
final String confpath = this.confPath.toString();
|
||||
final String homepath = this.home.getCanonicalPath();
|
||||
final String confpath = this.confPath.getCanonicalPath();
|
||||
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
||||
if ("file".equals(this.confPath.getScheme())) {
|
||||
File persist = new File(new File(confPath), "persistence.xml");
|
||||
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
||||
} else {
|
||||
System.setProperty(DataSources.DATASOURCE_CONFPATH, confpath + (confpath.endsWith("/") ? "" : "/") + "persistence.xml");
|
||||
}
|
||||
String pidstr = "";
|
||||
try { //JDK 9+
|
||||
Class phclass = Class.forName("java.lang.ProcessHandle");
|
||||
@@ -425,13 +433,17 @@ 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(confPath, "/" + dfload) : new File(dfload);
|
||||
if (df.isFile()) {
|
||||
final URI df = (dfload.indexOf('/') < 0) ? URI.create(confpath + (confpath.endsWith("/") ? "" : "/") + dfload) : new File(dfload).toURI();
|
||||
if (!"file".equals(df.getScheme()) || new File(df).isFile()) {
|
||||
Properties ps = new Properties();
|
||||
InputStream in = new FileInputStream(df);
|
||||
ps.load(in);
|
||||
in.close();
|
||||
ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath)));
|
||||
try {
|
||||
InputStream in = df.toURL().openStream();
|
||||
ps.load(in);
|
||||
in.close();
|
||||
ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath)));
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "load properties(" + dfload + ") error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -558,9 +570,10 @@ public final class Application {
|
||||
}
|
||||
|
||||
public void restoreConfig() throws IOException {
|
||||
if (!"file".equals(this.confPath.getScheme())) return;
|
||||
synchronized (this) {
|
||||
File confFile = new File(this.confPath, "application.xml");
|
||||
confFile.renameTo(new File(this.confPath, "application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
|
||||
File confFile = new File(this.confPath.toString(), "application.xml");
|
||||
confFile.renameTo(new File(this.confPath.toString(), "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();
|
||||
@@ -571,7 +584,7 @@ public final class Application {
|
||||
final Application application = this;
|
||||
new Thread() {
|
||||
{
|
||||
setName("Application-Control-Thread");
|
||||
setName("Redkale-Application-SelfServer-Thread");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -742,7 +755,7 @@ public final class Application {
|
||||
Thread thread = new Thread() {
|
||||
{
|
||||
String host = serconf.getValue("host", "0.0.0.0").replace("0.0.0.0", "*");
|
||||
setName(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
|
||||
setName("Redkale-" + serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
|
||||
this.setDaemon(true);
|
||||
}
|
||||
|
||||
@@ -843,18 +856,20 @@ public final class Application {
|
||||
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
|
||||
System.setProperty(RESNAME_APP_HOME, home);
|
||||
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
||||
File appfile;
|
||||
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||
appfile = new File(confsubpath).getCanonicalFile();
|
||||
URI appconf;
|
||||
if (confsubpath.contains("://")) {
|
||||
appconf = URI.create(confsubpath + (confsubpath.endsWith("/") ? "" : "/") + "application.xml");
|
||||
} else if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||
appconf = new File(confsubpath, "application.xml").toURI();
|
||||
} else {
|
||||
appfile = new File(new File(home), confsubpath);
|
||||
appconf = new File(new File(home, confsubpath), "application.xml").toURI();
|
||||
}
|
||||
File appconf = new File(appfile, "application.xml");
|
||||
return new Application(singleton, load(new FileInputStream(appconf)));
|
||||
return new Application(singleton, load(appconf.toURL().openStream()));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Utility.midnight(); //先初始化一下Utility
|
||||
Thread.currentThread().setName("Redkale-Application-Main-Thread");
|
||||
//运行主程序
|
||||
final Application application = Application.create(false);
|
||||
if (System.getProperty("CMD") != null) {
|
||||
|
||||
@@ -133,7 +133,7 @@ public class LogFileHandler extends Handler {
|
||||
}
|
||||
|
||||
private void open() {
|
||||
final String name = "Logging-" + getClass().getSimpleName() + "-Thread";
|
||||
final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread";
|
||||
new Thread() {
|
||||
{
|
||||
setName(name);
|
||||
|
||||
@@ -35,7 +35,7 @@ public class FilterWatchService extends AbstractWatchService {
|
||||
@Resource
|
||||
protected Application application;
|
||||
|
||||
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
|
||||
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
|
||||
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
|
||||
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
||||
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
|
||||
|
||||
@@ -50,7 +50,7 @@ public class ServerWatchService extends AbstractWatchService {
|
||||
return new RetResult(rs);
|
||||
}
|
||||
|
||||
@RestMapping(name = "changeaddress", comment = "更改Server的监听地址和端口")
|
||||
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
|
||||
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
|
||||
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
|
||||
if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
|
||||
|
||||
@@ -30,8 +30,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
||||
protected Application application;
|
||||
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "setfield", auth = false, comment = "设置Service中指定字段的内容")
|
||||
public RetResult setfield(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@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) {
|
||||
@@ -65,8 +65,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
||||
}
|
||||
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "getfield", auth = false, comment = "查询Service中指定字段的内容")
|
||||
public RetResult getfield(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@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 = "";
|
||||
@@ -98,8 +98,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
||||
}
|
||||
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "runmethod", auth = false, comment = "调用Service中指定方法")
|
||||
public RetResult runmethod(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@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,
|
||||
@@ -169,28 +169,28 @@ public class ServiceWatchService extends AbstractWatchService {
|
||||
return dest;
|
||||
}
|
||||
|
||||
@RestMapping(name = "load", auth = false, comment = "动态增加Service")
|
||||
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
|
||||
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||
//待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "reload", auth = false, comment = "重新加载Service")
|
||||
@RestMapping(name = "reloadService", auth = false, comment = "重新加载Service")
|
||||
public RetResult reloadService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
//待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "stop", auth = false, comment = "动态停止Service")
|
||||
@RestMapping(name = "stopService", auth = false, comment = "动态停止Service")
|
||||
public RetResult stopService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
//待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "find", auth = false, comment = "查找Service")
|
||||
@RestMapping(name = "findService", auth = false, comment = "查找Service")
|
||||
public RetResult find(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
//待开发
|
||||
|
||||
@@ -25,13 +25,13 @@ public class ServletWatchService extends AbstractWatchService {
|
||||
@Resource
|
||||
protected TransportFactory transportFactory;
|
||||
//
|
||||
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
|
||||
// @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet")
|
||||
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||
// //待开发
|
||||
// return RetResult.success();
|
||||
// }
|
||||
//
|
||||
// @RestMapping(name = "stop", auth = false, comment = "动态停止Servlet")
|
||||
// @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet")
|
||||
// public RetResult stopServlet(String type) {
|
||||
// //待开发
|
||||
// return RetResult.success();
|
||||
|
||||
@@ -36,12 +36,15 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
||||
return writer;
|
||||
}
|
||||
|
||||
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||
writer.fieldFunc = fieldFunc;
|
||||
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
writer.objFieldFunc = objFieldFunc;
|
||||
writer.objExtFunc = objExtFunc;
|
||||
return writer;
|
||||
}
|
||||
|
||||
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> fieldFunc);
|
||||
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
|
||||
|
||||
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
|
||||
|
||||
public abstract boolean isBinary();
|
||||
|
||||
|
||||
@@ -133,6 +133,54 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
}
|
||||
|
||||
});
|
||||
try {
|
||||
Class sqldateClass = Class.forName("java.sql.Date");
|
||||
this.register(sqldateClass, new SimpledCoder<R, W, java.sql.Date>() {
|
||||
|
||||
@Override
|
||||
public void convertTo(W out, java.sql.Date value) {
|
||||
out.writeSmallString(value == null ? null : value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.sql.Date convertFrom(R in) {
|
||||
String t = in.readSmallString();
|
||||
return t == null ? null : java.sql.Date.valueOf(t);
|
||||
}
|
||||
|
||||
});
|
||||
Class sqltimeClass = Class.forName("java.sql.Time");
|
||||
this.register(sqltimeClass, new SimpledCoder<R, W, java.sql.Time>() {
|
||||
|
||||
@Override
|
||||
public void convertTo(W out, java.sql.Time value) {
|
||||
out.writeSmallString(value == null ? null : value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.sql.Time convertFrom(R in) {
|
||||
String t = in.readSmallString();
|
||||
return t == null ? null : java.sql.Time.valueOf(t);
|
||||
}
|
||||
|
||||
});
|
||||
Class timestampClass = Class.forName("java.sql.Timestamp");
|
||||
this.register(timestampClass, new SimpledCoder<R, W, java.sql.Timestamp>() {
|
||||
|
||||
@Override
|
||||
public void convertTo(W out, java.sql.Timestamp value) {
|
||||
out.writeSmallString(value == null ? null : value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.sql.Timestamp convertFrom(R in) {
|
||||
String t = in.readSmallString();
|
||||
return t == null ? null : java.sql.Timestamp.valueOf(t);
|
||||
}
|
||||
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,7 +759,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
encoder = new OptionalCoder(this, type);
|
||||
} else if (clazz == Object.class) {
|
||||
return (Encodeable<W, E>) this.anyEncoder;
|
||||
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
|
||||
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz
|
||||
|| java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
|
||||
Encodeable simpleCoder = null;
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
if (!Modifier.isStatic(method.getModifiers())) continue;
|
||||
|
||||
102
src/org/redkale/convert/ConvertField.java
Normal file
102
src/org/redkale/convert/ConvertField.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.convert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
|
||||
/**
|
||||
* newConvert参数中的Function返回结果的数据类
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class ConvertField implements Serializable {
|
||||
|
||||
protected String name;
|
||||
|
||||
protected Type type;
|
||||
|
||||
protected int position;
|
||||
|
||||
protected Object value;
|
||||
|
||||
public ConvertField() {
|
||||
}
|
||||
|
||||
public ConvertField(String name, Object value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ConvertField(String name, int position, Object value) {
|
||||
this.name = name;
|
||||
this.position = position;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ConvertField(String name, Type type, Object value) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ConvertField(String name, Type type, int position, Object value) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.position = position;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ConvertField[] ofArray(Object... items) {
|
||||
int len = items.length / 2;
|
||||
ConvertField[] rs = new ConvertField[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]);
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
@@ -164,9 +164,22 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
||||
return;
|
||||
}
|
||||
if (out.writeObjectB(value) < 0) {
|
||||
int maxPosition = 0;
|
||||
for (EnMember member : members) {
|
||||
maxPosition = member.getPosition();
|
||||
out.writeObjectField(member, value);
|
||||
}
|
||||
if (out.objExtFunc != null) {
|
||||
ConvertField[] extFields = out.objExtFunc.apply(value);
|
||||
if (extFields != null) {
|
||||
Encodeable<W, ?> anyEncoder = factory.getAnyEncoder();
|
||||
for (ConvertField en : extFields) {
|
||||
if (en == null) continue;
|
||||
maxPosition++;
|
||||
out.writeObjectField(en.getName(), en.getType(), Math.max(en.getPosition(), maxPosition), anyEncoder, en.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.writeObjectE(value);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
package org.redkale.convert;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.*;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
@@ -26,7 +26,10 @@ public abstract class Writer {
|
||||
protected Type specify;
|
||||
|
||||
//对某个字段值进行动态处理
|
||||
protected BiFunction<Attribute, Object, Object> fieldFunc;
|
||||
protected BiFunction<Attribute, Object, Object> objFieldFunc;
|
||||
|
||||
//对某个对象进行动态扩展字段值处理
|
||||
protected Function<Object, ConvertField[]> objExtFunc;
|
||||
|
||||
/**
|
||||
* 设置specify
|
||||
@@ -44,7 +47,7 @@ public abstract class Writer {
|
||||
}
|
||||
|
||||
protected boolean recycle() {
|
||||
this.fieldFunc = null;
|
||||
this.objFieldFunc = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -116,10 +119,10 @@ public abstract class Writer {
|
||||
@SuppressWarnings("unchecked")
|
||||
public void writeObjectField(final EnMember member, Object obj) {
|
||||
Object value;
|
||||
if (fieldFunc == null) {
|
||||
if (objFieldFunc == null) {
|
||||
value = member.attribute.get(obj);
|
||||
} else {
|
||||
value = fieldFunc.apply(member.attribute, obj);
|
||||
value = objFieldFunc.apply(member.attribute, obj);
|
||||
}
|
||||
if (value == null) return;
|
||||
if (tiny()) {
|
||||
@@ -129,11 +132,49 @@ public abstract class Writer {
|
||||
if (!((Boolean) value)) return;
|
||||
}
|
||||
}
|
||||
this.writeFieldName(member);
|
||||
Attribute attr = member.getAttribute();
|
||||
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
|
||||
member.encoder.convertTo(this, value);
|
||||
this.comma = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出一个对象的某个扩展字段
|
||||
*
|
||||
*
|
||||
* @param fieldName 字段名称
|
||||
* @param fieldType 字段类型
|
||||
* @param fieldPos 字段顺序
|
||||
* @param anyEncoder Encoder
|
||||
* @param value 写入的字段对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) {
|
||||
if (value == null) return;
|
||||
if (fieldType == null) fieldType = value.getClass();
|
||||
if (tiny() && fieldType instanceof Class) {
|
||||
Class clazz = (Class) fieldType;
|
||||
if (CharSequence.class.isAssignableFrom(clazz)) {
|
||||
if (((CharSequence) value).length() == 0) return;
|
||||
} else if (clazz == boolean.class || clazz == Boolean.class) {
|
||||
if (!((Boolean) value)) return;
|
||||
}
|
||||
}
|
||||
this.writeFieldName(fieldName, fieldType, fieldPos);
|
||||
anyEncoder.convertTo(this, value);
|
||||
this.comma = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出一个字段名
|
||||
*
|
||||
* @param member 字段
|
||||
*/
|
||||
public final void writeFieldName(final EnMember member) {
|
||||
Attribute attr = member.getAttribute();
|
||||
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出一个对象后的操作
|
||||
*
|
||||
@@ -191,9 +232,11 @@ public abstract class Writer {
|
||||
/**
|
||||
* 输出一个字段名
|
||||
*
|
||||
* @param member 字段的EnMember对象
|
||||
* @param fieldName 字段名称
|
||||
* @param fieldType 字段类型
|
||||
* @param fieldPos 字段顺序
|
||||
*/
|
||||
public abstract void writeFieldName(EnMember member);
|
||||
public abstract void writeFieldName(String fieldName, Type fieldType, int fieldPos);
|
||||
|
||||
/**
|
||||
* 写入一个boolean值
|
||||
|
||||
@@ -61,10 +61,15 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
|
||||
@Override
|
||||
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||
return newConvert(fieldFunc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
return new BsonConvert(getFactory(), tiny) {
|
||||
@Override
|
||||
protected <S extends BsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, fieldFunc);
|
||||
return fieldFunc(writer, fieldFunc, objExtFunc);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.redkale.convert.bson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.redkale.convert.*;
|
||||
import org.redkale.convert.ext.ByteSimpledCoder;
|
||||
@@ -43,7 +44,7 @@ public class BsonWriter extends Writer {
|
||||
}
|
||||
|
||||
protected BsonWriter(byte[] bs) {
|
||||
this.content = bs;
|
||||
this.content = bs == null ? new byte[0] : bs;
|
||||
}
|
||||
|
||||
public BsonWriter() {
|
||||
@@ -102,7 +103,7 @@ public class BsonWriter extends Writer {
|
||||
super.recycle();
|
||||
this.count = 0;
|
||||
this.specify = null;
|
||||
if (this.content.length > defaultSize) {
|
||||
if (this.content != null && this.content.length > defaultSize) {
|
||||
this.content = new byte[defaultSize];
|
||||
}
|
||||
return true;
|
||||
@@ -200,11 +201,10 @@ public class BsonWriter extends Writer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeFieldName(EnMember member) {
|
||||
Attribute attribute = member.getAttribute();
|
||||
public final void writeFieldName(String fieldName, Type fieldType, int fieldPos) {
|
||||
writeByte(BsonReader.SIGN_HASNEXT);
|
||||
writeSmallString(attribute.field());
|
||||
writeByte(BsonFactory.typeEnum(attribute.type()));
|
||||
writeSmallString(fieldName);
|
||||
writeByte(BsonFactory.typeEnum(fieldType));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.redkale.convert.*;
|
||||
*/
|
||||
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
||||
|
||||
public static final PatternSimpledCoder instance = new PatternSimpledCoder();
|
||||
public static final FileSimpledCoder instance = new FileSimpledCoder();
|
||||
|
||||
@Override
|
||||
public void convertTo(W out, File value) {
|
||||
|
||||
@@ -115,7 +115,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
int byteLength = quote ? 2 : 0;
|
||||
ByteBuffer bb = null;
|
||||
if (charset == null) {
|
||||
byteLength += encodeUTF8Length(chs, start, len);
|
||||
byteLength += Utility.encodeUTF8Length(chs, start, len);
|
||||
} else {
|
||||
bb = charset.encode(CharBuffer.wrap(chs, start, len));
|
||||
byteLength += bb.remaining();
|
||||
@@ -134,6 +134,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
} else if (c < 0x800) {
|
||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||
} else if (Character.isSurrogate(c)) { //连取两个
|
||||
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||
i++;
|
||||
} else {
|
||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||
@@ -155,7 +162,34 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
if (charset == null) { //UTF-8
|
||||
final int limit = start + len;
|
||||
for (int i = start; i < limit; i++) {
|
||||
buffer = putUTF8Char(buffer, chs[i]);
|
||||
char c = chs[i];
|
||||
if (c < 0x80) {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) c);
|
||||
} else if (c < 0x800) {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||
} else if (Character.isSurrogate(c)) { //连取两个
|
||||
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||
i++;
|
||||
} else {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (bb.hasRemaining()) {
|
||||
@@ -169,50 +203,18 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer putUTF8Char(ByteBuffer buffer, char c) {
|
||||
if (c < 0x80) {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) c);
|
||||
} else if (c < 0x800) {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||
} else {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private ByteBuffer nextByteBuffer() {
|
||||
this.buffers[this.index].flip();
|
||||
return this.buffers[++this.index];
|
||||
}
|
||||
|
||||
protected static int encodeUTF8Length(final char[] text, final int start, final int len) {
|
||||
char c;
|
||||
int size = 0;
|
||||
final char[] chars = text;
|
||||
final int limit = start + len;
|
||||
for (int i = start; i < limit; i++) {
|
||||
c = chars[i];
|
||||
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
protected static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) {
|
||||
char c;
|
||||
int size = 0;
|
||||
final char[] chars = text;
|
||||
final char[] chs = text;
|
||||
final int limit = start + len;
|
||||
for (int i = start; i < limit; i++) {
|
||||
c = chars[i];
|
||||
c = chs[i];
|
||||
switch (c) {
|
||||
case '\n': size += 2;
|
||||
break;
|
||||
@@ -225,7 +227,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
case '"': size += 2;
|
||||
break;
|
||||
default:
|
||||
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
|
||||
size += (c < 0x80 ? 1 : (c < 0x800 || Character.isSurrogate(c) ? 2 : 3));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -239,19 +241,39 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
* @param value String值
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(final boolean quote, final String value) {
|
||||
char[] chs = Utility.charArray(value);
|
||||
writeTo(-1, quote, chs, 0, chs.length);
|
||||
public void writeLatin1To(final boolean quote, final String value) {
|
||||
byte[] bs = Utility.byteArray(value);
|
||||
int expandsize = expand(bs.length + (quote ? 2 : 0));
|
||||
if (expandsize == 0) {// 只需要一个buffer
|
||||
final ByteBuffer buffer = this.buffers[index];
|
||||
if (quote) buffer.put((byte) '"');
|
||||
buffer.put(bs);
|
||||
if (quote) buffer.put((byte) '"');
|
||||
} else {
|
||||
ByteBuffer buffer = this.buffers[index];
|
||||
if (quote) {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) '"');
|
||||
}
|
||||
for (byte b : bs) {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put(b);
|
||||
}
|
||||
if (quote) {
|
||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||
buffer.put((byte) '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt(int value) {
|
||||
writeTo(false, String.valueOf(value));
|
||||
writeLatin1To(false, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(long value) {
|
||||
writeTo(false, String.valueOf(value));
|
||||
writeLatin1To(false, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -289,7 +311,8 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
if (expandsize == 0) { // 只需要一个buffer
|
||||
final ByteBuffer buffer = this.buffers[index];
|
||||
buffer.put((byte) '"');
|
||||
for (char c : chs) {
|
||||
for (int i = 0; i < chs.length; i++) {
|
||||
char c = chs[i];
|
||||
switch (c) {
|
||||
case '\n': buffer.put((byte) '\\').put((byte) 'n');
|
||||
break;
|
||||
@@ -307,6 +330,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
} else if (c < 0x800) {
|
||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||
} else if (Character.isSurrogate(c)) { //连取两个
|
||||
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||
i++;
|
||||
} else {
|
||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||
|
||||
@@ -48,10 +48,15 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
|
||||
@Override
|
||||
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||
return newConvert(fieldFunc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
return new JsonConvert(getFactory(), tiny) {
|
||||
@Override
|
||||
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, fieldFunc);
|
||||
return fieldFunc(writer, fieldFunc, objExtFunc);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,10 +26,7 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
|
||||
|
||||
static {
|
||||
instance.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
||||
instance.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
||||
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
||||
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
||||
|
||||
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
||||
|
||||
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
|
||||
@@ -38,6 +35,12 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
|
||||
private JsonFactory(JsonFactory parent, boolean tiny) {
|
||||
super(parent, tiny);
|
||||
if (parent == null) {
|
||||
this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
||||
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
||||
this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
||||
this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -87,19 +87,19 @@ class JsonStreamWriter extends JsonByteBufferWriter {
|
||||
* @param value String值
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(final boolean quote, final String value) {
|
||||
public void writeLatin1To(final boolean quote, final String value) {
|
||||
char[] chs = Utility.charArray(value);
|
||||
writeTo(quote, chs, 0, chs.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt(int value) {
|
||||
writeTo(false, String.valueOf(value));
|
||||
writeLatin1To(false, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(long value) {
|
||||
writeTo(false, String.valueOf(value));
|
||||
writeLatin1To(false, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.redkale.convert.json;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.redkale.convert.*;
|
||||
import org.redkale.util.*;
|
||||
@@ -88,7 +89,7 @@ public class JsonWriter extends Writer {
|
||||
* @param quote 是否加双引号
|
||||
* @param value 非null且不含需要转义的字符的String值
|
||||
*/
|
||||
public void writeTo(final boolean quote, final String value) {
|
||||
public void writeLatin1To(final boolean quote, final String value) {
|
||||
int len = value.length();
|
||||
expand(len + (quote ? 2 : 0));
|
||||
if (quote) content[count++] = '"';
|
||||
@@ -102,7 +103,7 @@ public class JsonWriter extends Writer {
|
||||
super.recycle();
|
||||
this.count = 0;
|
||||
this.specify = null;
|
||||
if (this.content.length > defaultSize) {
|
||||
if (this.content != null && this.content.length > defaultSize) {
|
||||
this.content = new char[defaultSize];
|
||||
}
|
||||
return true;
|
||||
@@ -159,15 +160,15 @@ public class JsonWriter extends Writer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeFieldName(EnMember member) {
|
||||
public final void writeFieldName(String fieldName, Type fieldType, int fieldPos) {
|
||||
if (this.comma) writeTo(',');
|
||||
writeTo(true, member.getAttribute().field());
|
||||
writeLatin1To(true, fieldName);
|
||||
writeTo(':');
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeSmallString(String value) {
|
||||
writeTo(true, value);
|
||||
writeLatin1To(true, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -313,17 +314,17 @@ public class JsonWriter extends Writer {
|
||||
|
||||
@Override
|
||||
public final void writeFloat(float value) {
|
||||
writeTo(false, String.valueOf(value));
|
||||
writeLatin1To(false, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeDouble(double value) {
|
||||
writeTo(false, String.valueOf(value));
|
||||
writeLatin1To(false, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeWrapper(StringWrapper value) {
|
||||
writeTo(false, String.valueOf(value));
|
||||
writeLatin1To(false, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import java.util.function.*;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import org.redkale.util.ObjectPool;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -118,7 +118,6 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
||||
|
||||
public abstract void read(CompletionHandler<Integer, ByteBuffer> handler);
|
||||
|
||||
|
||||
@Override
|
||||
public abstract int write(ByteBuffer src) throws IOException;
|
||||
|
||||
@@ -141,22 +140,40 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
||||
this.readBuffer = null;
|
||||
return rs;
|
||||
}
|
||||
// Thread thread = Thread.currentThread();
|
||||
// if (thread instanceof IOThread) {
|
||||
// return ((IOThread) thread).getBufferPool().get();
|
||||
// }
|
||||
return bufferSupplier.get();
|
||||
}
|
||||
|
||||
public void offerBuffer(Buffer buffer) {
|
||||
if (buffer == null) return;
|
||||
// Thread thread = Thread.currentThread();
|
||||
// if (thread instanceof IOThread) {
|
||||
// ((IOThread) thread).getBufferPool().accept((ByteBuffer) buffer);
|
||||
// return;
|
||||
// }
|
||||
bufferConsumer.accept((ByteBuffer) buffer);
|
||||
}
|
||||
|
||||
public void offerBuffer(Buffer... buffers) {
|
||||
if (buffers == null) return;
|
||||
Consumer<ByteBuffer> consumer = this.bufferConsumer;
|
||||
// Thread thread = Thread.currentThread();
|
||||
// if (thread instanceof IOThread) {
|
||||
// consumer = ((IOThread) thread).getBufferPool();
|
||||
// }
|
||||
for (Buffer buffer : buffers) {
|
||||
bufferConsumer.accept((ByteBuffer) buffer);
|
||||
consumer.accept((ByteBuffer) buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer pollWriteBuffer() {
|
||||
// Thread thread = Thread.currentThread();
|
||||
// if (thread instanceof IOThread) {
|
||||
// return ((IOThread) thread).getBufferPool().get();
|
||||
// }
|
||||
return bufferSupplier.get();
|
||||
}
|
||||
|
||||
@@ -189,7 +206,12 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
||||
}
|
||||
}
|
||||
if (this.readBuffer != null) {
|
||||
bufferConsumer.accept(this.readBuffer);
|
||||
Consumer<ByteBuffer> consumer = this.bufferConsumer;
|
||||
// Thread thread = Thread.currentThread();
|
||||
// if (thread instanceof IOThread) {
|
||||
// consumer = ((IOThread) thread).getBufferPool();
|
||||
// }
|
||||
consumer.accept(this.readBuffer);
|
||||
}
|
||||
if (attributes == null) return;
|
||||
try {
|
||||
|
||||
61
src/org/redkale/net/IOThread.java
Normal file
61
src/org/redkale/net/IOThread.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* 协议处理的IO线程类
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class IOThread extends Thread {
|
||||
|
||||
protected Thread localThread;
|
||||
|
||||
protected final ExecutorService executor;
|
||||
|
||||
protected ObjectPool<ByteBuffer> bufferPool;
|
||||
|
||||
public IOThread(ExecutorService executor, ObjectPool<ByteBuffer> bufferPool, Runnable runner) {
|
||||
super(runner);
|
||||
this.executor = executor;
|
||||
this.bufferPool = bufferPool;
|
||||
this.setDaemon(true);
|
||||
}
|
||||
|
||||
public void runAsync(Runnable runner) {
|
||||
executor.execute(runner);
|
||||
}
|
||||
|
||||
public ExecutorService getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public ObjectPool<ByteBuffer> getBufferPool() {
|
||||
return bufferPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.localThread = Thread.currentThread();
|
||||
super.run();
|
||||
}
|
||||
|
||||
public boolean inSameThread() {
|
||||
return this.localThread == Thread.currentThread();
|
||||
}
|
||||
|
||||
public boolean inSameThread(Thread thread) {
|
||||
return this.localThread == thread;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -60,7 +60,8 @@ public class PrepareRunner implements Runnable {
|
||||
@Override
|
||||
public void completed(Integer count, ByteBuffer buffer) {
|
||||
if (count < 1) {
|
||||
response.request.offerReadBuffer(buffer);
|
||||
buffer.clear();
|
||||
channel.setReadBuffer(buffer);
|
||||
channel.dispose();// response.init(channel); 在调用之前异常
|
||||
response.removeChannel();
|
||||
response.finish(true);
|
||||
@@ -84,7 +85,8 @@ public class PrepareRunner implements Runnable {
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, ByteBuffer buffer) {
|
||||
response.request.offerReadBuffer(buffer);
|
||||
buffer.clear();
|
||||
channel.setReadBuffer(buffer);
|
||||
channel.dispose();// response.init(channel); 在调用之前异常
|
||||
response.removeChannel();
|
||||
response.finish(true);
|
||||
@@ -97,7 +99,7 @@ public class PrepareRunner implements Runnable {
|
||||
channel.dispose();// response.init(channel); 在调用之前异常
|
||||
response.removeChannel();
|
||||
response.finish(true);
|
||||
if (te != null && context.logger.isLoggable(Level.FINEST)) {
|
||||
if (context.logger.isLoggable(Level.FINEST)) {
|
||||
context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +118,8 @@ public class PrepareRunner implements Runnable {
|
||||
if (buffer.hasRemaining()) {
|
||||
request.setMoredata(buffer);
|
||||
} else {
|
||||
response.request.offerReadBuffer(buffer);
|
||||
buffer.clear();
|
||||
channel.setReadBuffer(buffer);
|
||||
}
|
||||
preparer.prepare(request, response);
|
||||
} else {
|
||||
@@ -137,7 +140,8 @@ public class PrepareRunner implements Runnable {
|
||||
if (attachment.hasRemaining()) {
|
||||
request.setMoredata(attachment);
|
||||
} else {
|
||||
response.request.offerReadBuffer(attachment);
|
||||
attachment.clear();
|
||||
channel.setReadBuffer(attachment);
|
||||
}
|
||||
try {
|
||||
preparer.prepare(request, response);
|
||||
@@ -151,7 +155,8 @@ public class PrepareRunner implements Runnable {
|
||||
@Override
|
||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||
preparer.illRequestCounter.incrementAndGet();
|
||||
response.request.offerReadBuffer(attachment);
|
||||
attachment.clear();
|
||||
channel.setReadBuffer(attachment);
|
||||
response.finish(true);
|
||||
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, force to close channel ", exc);
|
||||
}
|
||||
@@ -175,19 +180,4 @@ public class PrepareRunner implements Runnable {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,6 @@ public abstract class Request<C extends Context> {
|
||||
|
||||
protected AsyncConnection channel;
|
||||
|
||||
protected ByteBuffer readBuffer;
|
||||
|
||||
/**
|
||||
* properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留;
|
||||
* properties 通常存放需要永久绑定在request里的一些对象
|
||||
@@ -67,23 +65,6 @@ public abstract class Request<C extends Context> {
|
||||
return rs;
|
||||
}
|
||||
|
||||
protected ByteBuffer pollReadBuffer() {
|
||||
ByteBuffer buffer = this.readBuffer;
|
||||
this.readBuffer = null;
|
||||
if (buffer == null) buffer = bufferPool.get();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected void offerReadBuffer(ByteBuffer buffer) {
|
||||
if (buffer == null) return;
|
||||
if (this.readBuffer == null) {
|
||||
buffer.clear();
|
||||
this.readBuffer = buffer;
|
||||
} else {
|
||||
bufferPool.accept(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
||||
*
|
||||
|
||||
@@ -27,18 +27,12 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
|
||||
protected final C context;
|
||||
|
||||
protected final ObjectPool<ByteBuffer> bufferPool;
|
||||
|
||||
protected final ObjectPool<Response> responsePool;
|
||||
|
||||
protected final R request;
|
||||
|
||||
protected AsyncConnection channel;
|
||||
|
||||
protected ByteBuffer writeHeadBuffer;
|
||||
|
||||
protected ByteBuffer writeBodyBuffer;
|
||||
|
||||
private volatile boolean inited = true;
|
||||
|
||||
protected Object output; //输出的结果对象
|
||||
@@ -49,8 +43,6 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
|
||||
protected Servlet<C, R, ? extends Response<C, R>> servlet;
|
||||
|
||||
private Supplier<ByteBuffer> bodyBufferSupplier;
|
||||
|
||||
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
|
||||
|
||||
@Override
|
||||
@@ -58,31 +50,21 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
if (attachment.hasRemaining()) {
|
||||
channel.write(attachment, attachment, this);
|
||||
} else {
|
||||
offerResponseBuffer(attachment);
|
||||
channel.offerBuffer(attachment);
|
||||
ByteBuffer data = request.removeMoredata();
|
||||
final boolean more = data != null && request.keepAlive;
|
||||
request.more = more;
|
||||
finish();
|
||||
if (more) new PrepareRunner(context, responsePool, request.channel, null, Response.this).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||
offerResponseBuffer(attachment);
|
||||
channel.offerBuffer(attachment);
|
||||
finish(true);
|
||||
}
|
||||
|
||||
private void offerResponseBuffer(ByteBuffer attachment) {
|
||||
if (writeHeadBuffer == null) {
|
||||
if (bufferPool.getRecyclerPredicate().test(attachment)) {
|
||||
writeHeadBuffer = attachment;
|
||||
}
|
||||
} else if (writeBodyBuffer == null) {
|
||||
if (bufferPool.getRecyclerPredicate().test(attachment)) {
|
||||
writeBodyBuffer = attachment;
|
||||
}
|
||||
} else {
|
||||
bufferPool.accept(attachment);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
|
||||
@@ -99,73 +81,36 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
if (index >= 0) {
|
||||
channel.write(attachments, index, attachments.length - index, attachments, this);
|
||||
} else {
|
||||
offerResponseBuffer(attachments);
|
||||
for (ByteBuffer attachment : attachments) {
|
||||
channel.offerBuffer(attachment);
|
||||
}
|
||||
ByteBuffer data = request.removeMoredata();
|
||||
final boolean more = data != null && request.keepAlive;
|
||||
request.more = more;
|
||||
finish();
|
||||
if (more) new PrepareRunner(context, responsePool, request.channel, null, Response.this).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, final ByteBuffer[] attachments) {
|
||||
offerResponseBuffer(attachments);
|
||||
for (ByteBuffer attachment : attachments) {
|
||||
channel.offerBuffer(attachment);
|
||||
}
|
||||
finish(true);
|
||||
}
|
||||
|
||||
private void offerResponseBuffer(ByteBuffer[] attachments) {
|
||||
int start = 0;
|
||||
if (writeHeadBuffer == null && attachments.length > start) {
|
||||
if (bufferPool.getRecyclerPredicate().test(attachments[start])) {
|
||||
writeHeadBuffer = attachments[start];
|
||||
start++;
|
||||
}
|
||||
}
|
||||
if (writeBodyBuffer == null && attachments.length > start) {
|
||||
if (bufferPool.getRecyclerPredicate().test(attachments[start])) {
|
||||
writeBodyBuffer = attachments[start];
|
||||
start++;
|
||||
}
|
||||
}
|
||||
for (int i = start; i < attachments.length; i++) {
|
||||
bufferPool.accept(attachments[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected Response(C context, final R request, ObjectPool<Response> responsePool) {
|
||||
this.context = context;
|
||||
this.request = request;
|
||||
this.bufferPool = request.bufferPool;
|
||||
this.responsePool = responsePool;
|
||||
this.writeHeadBuffer = bufferPool.get();
|
||||
this.writeBodyBuffer = bufferPool.get();
|
||||
this.bodyBufferSupplier = () -> {
|
||||
ByteBuffer buffer = writeBodyBuffer;
|
||||
if (buffer == null) return bufferPool.get();
|
||||
writeBodyBuffer = null;
|
||||
return buffer;
|
||||
};
|
||||
}
|
||||
|
||||
protected ByteBuffer pollWriteReadBuffer() {
|
||||
ByteBuffer buffer = this.writeHeadBuffer;
|
||||
this.writeHeadBuffer = null;
|
||||
if (buffer == null) buffer = bufferPool.get();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected ByteBuffer pollWriteBodyBuffer() {
|
||||
ByteBuffer buffer = this.writeBodyBuffer;
|
||||
this.writeBodyBuffer = null;
|
||||
if (buffer == null) buffer = bufferPool.get();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected Supplier<ByteBuffer> getBodyBufferSupplier() {
|
||||
return bodyBufferSupplier;
|
||||
}
|
||||
|
||||
protected void offerBuffer(ByteBuffer... buffers) {
|
||||
for (ByteBuffer buffer : buffers) {
|
||||
bufferPool.accept(buffer);
|
||||
channel.offerBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +223,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
public void finish(final byte[] bs) {
|
||||
if (!this.inited) return; //避免重复关闭
|
||||
if (this.context.bufferCapacity == bs.length) {
|
||||
ByteBuffer buffer = this.bufferPool.get();
|
||||
ByteBuffer buffer = channel.bufferSupplier.get();
|
||||
buffer.put(bs);
|
||||
buffer.flip();
|
||||
this.finish(buffer);
|
||||
@@ -289,33 +234,33 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
|
||||
public void finish(ByteBuffer buffer) {
|
||||
if (!this.inited) return; //避免重复关闭
|
||||
ByteBuffer data = this.request.removeMoredata();
|
||||
final AsyncConnection conn = this.channel;
|
||||
final boolean more = data != null && this.request.keepAlive;
|
||||
this.request.more = more;
|
||||
// ByteBuffer data = this.request.removeMoredata();
|
||||
// final boolean more = data != null && this.request.keepAlive;
|
||||
// this.request.more = more;
|
||||
conn.write(buffer, buffer, finishHandler);
|
||||
if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||
}
|
||||
|
||||
public void finish(boolean kill, ByteBuffer buffer) {
|
||||
if (!this.inited) return; //避免重复关闭
|
||||
if (kill) refuseAlive();
|
||||
ByteBuffer data = this.request.removeMoredata();
|
||||
final AsyncConnection conn = this.channel;
|
||||
final boolean more = data != null && this.request.keepAlive;
|
||||
this.request.more = more;
|
||||
// ByteBuffer data = this.request.removeMoredata();
|
||||
// final boolean more = data != null && this.request.keepAlive;
|
||||
// this.request.more = more;
|
||||
conn.write(buffer, buffer, finishHandler);
|
||||
if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||
}
|
||||
|
||||
public void finish(ByteBuffer... buffers) {
|
||||
if (!this.inited) return; //避免重复关闭
|
||||
final AsyncConnection conn = this.channel;
|
||||
ByteBuffer data = this.request.removeMoredata();
|
||||
final boolean more = data != null && this.request.keepAlive;
|
||||
this.request.more = more;
|
||||
// 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, this.responsePool, conn, data, null).run();
|
||||
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||
}
|
||||
|
||||
public void finish(boolean kill, ByteBuffer... buffers) {
|
||||
@@ -337,14 +282,14 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
if (buffer.hasRemaining()) {
|
||||
channel.write(buffer, attachment, this);
|
||||
} else {
|
||||
bufferPool.accept(buffer);
|
||||
channel.offerBuffer(buffer);
|
||||
if (handler != null) handler.completed(result, attachment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, A attachment) {
|
||||
bufferPool.accept(buffer);
|
||||
channel.offerBuffer(buffer);
|
||||
if (handler != null) handler.failed(exc, attachment);
|
||||
}
|
||||
|
||||
@@ -362,7 +307,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
bufferPool.accept(buffers[i]);
|
||||
channel.offerBuffer(buffers[i]);
|
||||
}
|
||||
if (index == 0) {
|
||||
channel.write(buffers, attachment, this);
|
||||
@@ -376,7 +321,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
||||
@Override
|
||||
public void failed(Throwable exc, A attachment) {
|
||||
for (ByteBuffer buffer : buffers) {
|
||||
bufferPool.accept(buffer);
|
||||
channel.offerBuffer(buffer);
|
||||
}
|
||||
if (handler != null) handler.failed(exc, attachment);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
||||
this.maxbody = parseLenth(config.getValue("maxbody"), 64 * 1024);
|
||||
int bufCapacity = parseLenth(config.getValue("bufferCapacity"), "UDP".equalsIgnoreCase(protocol) ? 1350 : 32 * 1024);
|
||||
this.bufferCapacity = "UDP".equalsIgnoreCase(protocol) ? bufCapacity : (bufCapacity < 8 * 1024 ? 8 * 1024 : bufCapacity);
|
||||
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 32);
|
||||
this.threads = config.getIntValue("threads", Math.max(8, Runtime.getRuntime().availableProcessors() * 2));
|
||||
this.bufferPoolSize = config.getIntValue("bufferPoolSize", this.threads * 4);
|
||||
this.responsePoolSize = config.getIntValue("responsePoolSize", this.threads * 2);
|
||||
this.name = config.getValue("name", "Server-" + protocol + "-" + this.address.getPort());
|
||||
@@ -153,7 +153,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
||||
final String n = name;
|
||||
this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||
Thread t = new WorkThread(executor, r);
|
||||
t.setName(n + "-ServletThread-" + f.format(counter.incrementAndGet()));
|
||||
t.setName("Redkale-" + n + "-ServletThread-" + f.format(counter.incrementAndGet()));
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -104,7 +104,8 @@ public class TcpAioProtocolServer extends ProtocolServer {
|
||||
|
||||
AsyncConnection conn = new TcpAioAsyncConnection(bufferPool, bufferPool, channel,
|
||||
context.getSSLContext(), null, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
||||
context.runAsync(new PrepareRunner(context, responsePool, conn, null, null));
|
||||
//context.runAsync(new PrepareRunner(context, responsePool, conn, null, null));
|
||||
new PrepareRunner(context, responsePool, conn, null, null).run();
|
||||
} catch (Throwable e) {
|
||||
context.logger.log(Level.INFO, channel + " accept error", e);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class TransportFactory {
|
||||
if (this.checkinterval < 2) this.checkinterval = 2;
|
||||
}
|
||||
this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
|
||||
final Thread t = new Thread(r, this.getClass().getSimpleName() + "-TransportFactoryTask-Thread");
|
||||
final Thread t = new Thread(r, "Redkale-" + this.getClass().getSimpleName() + "-Schedule-Thread");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
});
|
||||
@@ -162,7 +162,7 @@ public class TransportFactory {
|
||||
ExecutorService transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
||||
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||
return t;
|
||||
});
|
||||
AsynchronousChannelGroup transportGroup = null;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class HttpResourceServlet extends HttpServlet {
|
||||
|
||||
public WatchThread(File root) throws IOException {
|
||||
this.root = root;
|
||||
this.setName("HttpResourceServlet-Watch-Thread");
|
||||
this.setName("Redkale-HttpResourceServlet-Watch-Thread");
|
||||
this.setDaemon(true);
|
||||
this.watcher = this.root.toPath().getFileSystem().newWatchService();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
|
||||
protected static final byte[] connectAliveBytes = "Connection: keep-alive\r\n".getBytes();
|
||||
|
||||
private static final byte[] fillContentLengthBytes = ("Content-Length: \r\n").getBytes();
|
||||
|
||||
private static final ZoneId ZONE_GMT = ZoneId.of("GMT");
|
||||
|
||||
private static final Set<OpenOption> options = new HashSet<>();
|
||||
|
||||
private static final Map<Integer, String> httpCodes = new HashMap<>();
|
||||
@@ -103,8 +107,6 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
httpCodes.put(505, "HTTP Version Not Supported");
|
||||
}
|
||||
|
||||
private static final ZoneId ZONE_GMT = ZoneId.of("GMT");
|
||||
|
||||
private int status = 200;
|
||||
|
||||
private String contentType = "";
|
||||
@@ -113,9 +115,15 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
|
||||
private HttpCookie[] cookies;
|
||||
|
||||
private boolean headsended = false;
|
||||
private int headWritedSize = -1; //0表示跳过header,正数表示header的字节长度。
|
||||
|
||||
private ByteBuffer headBuffer;
|
||||
|
||||
private int headLenPos = -1;
|
||||
|
||||
private BiFunction<HttpResponse, ByteBuffer[], ByteBuffer[]> bufferHandler;
|
||||
|
||||
private Supplier<ByteBuffer> bodyBufferSupplier;
|
||||
//------------------------------------------------
|
||||
|
||||
private final String plainContentType;
|
||||
@@ -163,6 +171,11 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
this.hasRender = renders != null && !renders.isEmpty();
|
||||
this.onlyoneHttpRender = renders != null && renders.size() == 1 ? renders.get(0) : null;
|
||||
this.contentType = this.plainContentType;
|
||||
this.bodyBufferSupplier = () -> {
|
||||
if (headWritedSize >= 0 || bufferHandler != null) return channel.pollWriteBuffer(); //bufferHandler 需要cached的请求不能带上header
|
||||
if (contentLength < 0) contentLength = -2;
|
||||
return createHeader();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,12 +198,18 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
this.contentLength = -1;
|
||||
this.contentType = null;
|
||||
this.cookies = null;
|
||||
this.headsended = false;
|
||||
this.headWritedSize = -1;
|
||||
this.headBuffer = null;
|
||||
this.headLenPos = -1;
|
||||
this.header.clear();
|
||||
this.bufferHandler = null;
|
||||
return super.recycle();
|
||||
}
|
||||
|
||||
protected Supplier<ByteBuffer> getBodyBufferSupplier() {
|
||||
return bodyBufferSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(AsyncConnection channel) {
|
||||
super.init(channel);
|
||||
@@ -285,15 +304,6 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
return context.loadAsyncHandlerCreator(handlerClass).create(createAsyncHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ByteBuffer生成器
|
||||
*
|
||||
* @return ByteBuffer生成器
|
||||
*/
|
||||
public Supplier<ByteBuffer> getBufferSupplier() {
|
||||
return getBodyBufferSupplier();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象以JSON格式输出
|
||||
*
|
||||
@@ -390,7 +400,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
|
||||
this.header.addValue("retinfo", ret.getRetinfo());
|
||||
}
|
||||
finish(request.getJsonConvert().convertTo(getBodyBufferSupplier(), ret));
|
||||
Convert convert = ret == null ? null : ret.convert();
|
||||
if (convert == null || !(convert instanceof TextConvert)) convert = request.getJsonConvert();
|
||||
finish(convert.convertTo(getBodyBufferSupplier(), ret));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,6 +509,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
context.getLogger().log(Level.WARNING, "HttpServlet finish File occur, force to close channel. request = " + getRequest(), e);
|
||||
finish(500, null);
|
||||
}
|
||||
} else if (obj instanceof org.redkale.service.RetResult) {
|
||||
finishJson((org.redkale.service.RetResult) obj);
|
||||
} else if (obj instanceof HttpResult) {
|
||||
HttpResult result = (HttpResult) obj;
|
||||
if (result.getContentType() != null) setContentType(result.getContentType());
|
||||
@@ -506,7 +520,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
} else if (result.getResult() instanceof CharSequence) {
|
||||
finish(result.getResult().toString());
|
||||
} else {
|
||||
finish(result.getConvert() == null ? convert : result.getConvert(), result.getResult());
|
||||
Convert cc = result.convert();
|
||||
if (cc == null || !(cc instanceof TextConvert)) cc = convert;
|
||||
finish(cc, result.getResult());
|
||||
}
|
||||
} else {
|
||||
if (hasRender) {
|
||||
@@ -631,7 +647,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
public void finish(final String contentType, final byte[] bs) {
|
||||
if (isClosed()) return; //避免重复关闭
|
||||
final byte[] content = bs == null ? new byte[0] : bs;
|
||||
if (!this.headsended) {
|
||||
if (this.headWritedSize < 0) {
|
||||
this.contentType = contentType;
|
||||
this.contentLength = content.length;
|
||||
ByteBuffer headbuf = createHeader();
|
||||
@@ -675,7 +691,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
@Override
|
||||
public void finish(boolean kill, ByteBuffer buffer) {
|
||||
if (isClosed()) return; //避免重复关闭
|
||||
if (!this.headsended) {
|
||||
if (this.headWritedSize < 0) {
|
||||
this.contentLength = buffer == null ? 0 : buffer.remaining();
|
||||
ByteBuffer headbuf = createHeader();
|
||||
headbuf.flip();
|
||||
@@ -713,7 +729,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
if (bufs != null) buffers = bufs;
|
||||
}
|
||||
if (kill) refuseAlive();
|
||||
if (!this.headsended) {
|
||||
if (this.headWritedSize < 0) {
|
||||
long len = 0;
|
||||
for (ByteBuffer buf : buffers) {
|
||||
len += buf.remaining();
|
||||
@@ -730,6 +746,17 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
super.finish(kill, newbuffers);
|
||||
}
|
||||
} else {
|
||||
if (this.headLenPos > 0 && buffers[0] == headBuffer) {
|
||||
long contentlen = -this.headWritedSize;
|
||||
for (ByteBuffer buf : buffers) {
|
||||
contentlen += buf.remaining();
|
||||
}
|
||||
byte[] lenBytes = String.valueOf(contentlen).getBytes();
|
||||
int start = this.headLenPos - lenBytes.length;
|
||||
for (int i = 0; i < lenBytes.length; i++) {
|
||||
headBuffer.put(start + i, lenBytes[i]);
|
||||
}
|
||||
}
|
||||
super.finish(kill, buffers);
|
||||
}
|
||||
}
|
||||
@@ -743,7 +770,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
* @param handler 异步回调函数
|
||||
*/
|
||||
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler) {
|
||||
if (!this.headsended) {
|
||||
if (this.headWritedSize < 0) {
|
||||
if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining();
|
||||
ByteBuffer headbuf = createHeader();
|
||||
headbuf.flip();
|
||||
@@ -766,7 +793,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
* @param handler 异步回调函数
|
||||
*/
|
||||
public <A> void sendBody(ByteBuffer[] buffers, A attachment, CompletionHandler<Integer, A> handler) {
|
||||
if (!this.headsended) {
|
||||
if (this.headWritedSize < 0) {
|
||||
if (this.contentLength < 0) {
|
||||
int len = 0;
|
||||
if (buffers != null && buffers.length > 0) {
|
||||
@@ -849,7 +876,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
}
|
||||
this.contentLength = length;
|
||||
if (filename != null && !filename.isEmpty() && file != null) {
|
||||
addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
|
||||
if (this.header.getValue("Content-Disposition") == null) {
|
||||
addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
|
||||
}
|
||||
}
|
||||
this.contentType = MimeType.getByFilename(filename == null || filename.isEmpty() ? file.getName() : filename);
|
||||
if (this.contentType == null) this.contentType = "application/octet-stream";
|
||||
@@ -891,14 +920,19 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
|
||||
//Header大小不能超过一个ByteBuffer的容量
|
||||
protected ByteBuffer createHeader() {
|
||||
this.headsended = true;
|
||||
ByteBuffer buffer = this.pollWriteReadBuffer();
|
||||
ByteBuffer buffer = this.channel.pollWriteBuffer();
|
||||
int oldpos = buffer.position();
|
||||
if (this.status == 200) {
|
||||
buffer.put(status200Bytes);
|
||||
} else {
|
||||
buffer.put(("HTTP/1.1 " + this.status + " " + httpCodes.get(this.status) + "\r\n").getBytes());
|
||||
}
|
||||
if (this.contentLength >= 0) buffer.put(("Content-Length: " + this.contentLength + "\r\n").getBytes());
|
||||
if (this.contentLength >= 0) {
|
||||
buffer.put(("Content-Length: " + this.contentLength + "\r\n").getBytes());
|
||||
} else if (this.contentLength == -2) {
|
||||
buffer.put(fillContentLengthBytes);
|
||||
this.headLenPos = buffer.position() - 2; //去掉\r\n
|
||||
}
|
||||
if (!this.request.isWebSocket()) {
|
||||
if (this.contentType == this.jsonContentType) {
|
||||
buffer.put(this.jsonContentTypeBytes);
|
||||
@@ -970,6 +1004,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
}
|
||||
}
|
||||
buffer.put(LINE);
|
||||
this.headWritedSize = buffer.position() - oldpos;
|
||||
this.headBuffer = buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -995,7 +1031,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public HttpResponse skipHeader() {
|
||||
this.headsended = true;
|
||||
this.headWritedSize = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1202,7 +1238,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||
bufferPool.accept(attachment);
|
||||
channel.offerBuffer(attachment);
|
||||
finish(true);
|
||||
try {
|
||||
filechannel.close();
|
||||
|
||||
@@ -90,12 +90,11 @@ public class HttpResult<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@ConvertDisabled
|
||||
public Convert getConvert() {
|
||||
public Convert convert() {
|
||||
return convert;
|
||||
}
|
||||
|
||||
public void setConvert(Convert convert) {
|
||||
public void convert(Convert convert) {
|
||||
this.convert = convert;
|
||||
}
|
||||
|
||||
|
||||
@@ -860,7 +860,7 @@ public final class Rest {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (defmodulename.isEmpty() || (!pound && entrys.size() <= 6)) {
|
||||
if (defmodulename.isEmpty() || (!pound && entrys.size() <= 2)) {
|
||||
for (MappingEntry entry : entrys) {
|
||||
String suburl = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) + entry.name;
|
||||
urlpath += "," + suburl;
|
||||
|
||||
@@ -562,7 +562,7 @@ public abstract class WebSocketNode {
|
||||
protected CompletableFuture<Integer> sendOneUserMessage(final Object message, final boolean last, final Serializable userid) {
|
||||
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid));
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.finest("websocket want send message {userid:" + userid + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||
logger.finest("websocket want send message {userid:" + userid + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||
}
|
||||
CompletableFuture<Integer> localFuture = null;
|
||||
if (this.localEngine != null) localFuture = localEngine.sendLocalMessage(message, last, userid);
|
||||
@@ -595,8 +595,8 @@ public abstract class WebSocketNode {
|
||||
|
||||
protected CompletableFuture<Integer> sendOneAddrMessage(final InetSocketAddress sncpAddr, final Object message, final boolean last, final Serializable... userids) {
|
||||
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(sncpAddr, msg, last, userids));
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||
if (logger.isLoggable(Level.FINEST) && this.localEngine == null) { //只打印远程模式的
|
||||
logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||
}
|
||||
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
|
||||
return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids);
|
||||
@@ -918,7 +918,7 @@ public abstract class WebSocketNode {
|
||||
}
|
||||
|
||||
protected CompletableFuture<Integer> sendOneAddrAction(final InetSocketAddress sncpAddr, final WebSocketAction action, final Serializable... userids) {
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
if (logger.isLoggable(Level.FINEST) && this.localEngine == null) { //只打印远程模式的
|
||||
logger.finest("websocket want send action {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", action:" + action + " from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||
}
|
||||
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
|
||||
|
||||
@@ -349,7 +349,12 @@ public final class SncpClient {
|
||||
final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
|
||||
writer.writeTo(DEFAULT_HEADER);
|
||||
for (int i = 0; i < params.length; i++) { //params 可能包含: 3 个 boolean
|
||||
bsonConvert.convertTo(writer, CompletionHandler.class.isAssignableFrom(myparamclass[i]) ? CompletionHandler.class : myparamtypes[i], params[i]);
|
||||
BsonConvert bcc = bsonConvert;
|
||||
if (params[i] instanceof org.redkale.service.RetResult) {
|
||||
org.redkale.convert.Convert cc = ((org.redkale.service.RetResult) params[i]).convert();
|
||||
if (cc instanceof BsonConvert) bcc = (BsonConvert) cc;
|
||||
}
|
||||
bcc.convertTo(writer, CompletionHandler.class.isAssignableFrom(myparamclass[i]) ? CompletionHandler.class : myparamtypes[i], params[i]);
|
||||
}
|
||||
final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度
|
||||
final long seqid = System.nanoTime();
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
|
||||
public void finish(final int retcode, final BsonWriter out) {
|
||||
if (out == null) {
|
||||
final ByteBuffer buffer = pollWriteReadBuffer();
|
||||
final ByteBuffer buffer = channel.pollWriteBuffer();
|
||||
fillHeader(buffer, 0, retcode);
|
||||
finish(buffer);
|
||||
return;
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.redkale.service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.json.*;
|
||||
import org.redkale.util.Utility;
|
||||
|
||||
@@ -33,6 +34,8 @@ public class RetResult<T> {
|
||||
|
||||
protected Map<String, String> attach;
|
||||
|
||||
protected Convert convert;
|
||||
|
||||
public RetResult() {
|
||||
}
|
||||
|
||||
@@ -40,6 +43,11 @@ public class RetResult<T> {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public RetResult(Convert convert, T result) {
|
||||
this.convert = convert;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public RetResult(int retcode) {
|
||||
this.retcode = retcode;
|
||||
}
|
||||
@@ -55,6 +63,14 @@ public class RetResult<T> {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public Convert convert() {
|
||||
return convert;
|
||||
}
|
||||
|
||||
public void convert(Convert convert) {
|
||||
this.convert = convert;
|
||||
}
|
||||
|
||||
public static RetResult success() {
|
||||
return new RetResult();
|
||||
}
|
||||
|
||||
@@ -70,18 +70,17 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
}
|
||||
c = c1;
|
||||
} catch (SQLException se) {
|
||||
if (info.tableStrategy == null || !info.isTableNotExist(se)) throw se;
|
||||
synchronized (info.tables) {
|
||||
final String oldTable = info.table;
|
||||
if (info.getTableStrategy() == null || !info.isTableNotExist(se)) throw se;
|
||||
synchronized (info.disTableLock()) {
|
||||
final String catalog = conn.getCatalog();
|
||||
final String newTable = info.getTable(entitys[0]);
|
||||
final String tablekey = newTable.indexOf('.') > 0 ? newTable : (catalog + '.' + newTable);
|
||||
if (!info.tables.contains(tablekey)) {
|
||||
if (!info.containsDisTable(tablekey)) {
|
||||
try {
|
||||
Statement st = conn.createStatement();
|
||||
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
|
||||
st.execute(info.getTableCopySQL(newTable));
|
||||
st.close();
|
||||
info.tables.add(tablekey);
|
||||
info.addDisTable(tablekey);
|
||||
} catch (SQLException sqle) { //多进程并发时可能会出现重复建表
|
||||
if (newTable.indexOf('.') > 0 && info.isTableNotExist(se)) {
|
||||
Statement st;
|
||||
@@ -94,14 +93,14 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
}
|
||||
try {
|
||||
st = conn.createStatement();
|
||||
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
|
||||
st.execute(info.getTableCopySQL(newTable));
|
||||
st.close();
|
||||
info.tables.add(tablekey);
|
||||
info.addDisTable(tablekey);
|
||||
} catch (SQLException sqle2) {
|
||||
logger.log(Level.SEVERE, "create table2(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle2);
|
||||
logger.log(Level.SEVERE, "create table2(" + info.getTableCopySQL(newTable) + ") error", sqle2);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "create table(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle);
|
||||
logger.log(Level.SEVERE, "create table(" + info.getTableCopySQL(newTable) + ") error", sqle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,7 +113,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
c1 += cc;
|
||||
}
|
||||
c = c1;
|
||||
}
|
||||
}
|
||||
prestmt.close();
|
||||
//------------------------------------------------------------
|
||||
if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息
|
||||
@@ -143,7 +142,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
} catch (SQLException e) {
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) writePool.offerConnection(conn);
|
||||
}
|
||||
@@ -201,7 +200,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
} catch (SQLException e) {
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) writePool.offerConnection(conn);
|
||||
}
|
||||
@@ -222,7 +221,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
if (info.isTableNotExist(e)) return CompletableFuture.completedFuture(-1);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) writePool.offerConnection(conn);
|
||||
}
|
||||
@@ -243,7 +242,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
if (info.isTableNotExist(e)) return CompletableFuture.completedFuture(-1);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) writePool.offerConnection(conn);
|
||||
}
|
||||
@@ -296,7 +295,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
} catch (SQLException e) {
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) writePool.offerConnection(conn);
|
||||
}
|
||||
@@ -330,7 +329,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
} catch (SQLException e) {
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) writePool.offerConnection(conn);
|
||||
}
|
||||
@@ -339,12 +338,12 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
@Override
|
||||
protected <T, N extends Number> CompletableFuture<Map<String, N>> getNumberMapDB(EntityInfo<T> info, String sql, FilterFuncColumn... columns) {
|
||||
Connection conn = null;
|
||||
final Map map = new HashMap<>();
|
||||
try {
|
||||
conn = readPool.poll();
|
||||
//conn.setReadOnly(true);
|
||||
final Statement stmt = conn.createStatement();
|
||||
ResultSet set = stmt.executeQuery(sql);
|
||||
final Map map = new HashMap<>();
|
||||
if (set.next()) {
|
||||
int index = 0;
|
||||
for (FilterFuncColumn ffc : columns) {
|
||||
@@ -360,9 +359,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
stmt.close();
|
||||
return CompletableFuture.completedFuture(map);
|
||||
} catch (SQLException e) {
|
||||
if (info.getTableStrategy() != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(map);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) readPool.offerConnection(conn);
|
||||
}
|
||||
@@ -385,9 +385,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
stmt.close();
|
||||
return CompletableFuture.completedFuture(rs);
|
||||
} catch (SQLException e) {
|
||||
if (info.getTableStrategy() != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(defVal);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) readPool.offerConnection(conn);
|
||||
}
|
||||
@@ -396,11 +397,11 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
@Override
|
||||
protected <T, K extends Serializable, N extends Number> CompletableFuture<Map<K, N>> queryColumnMapDB(EntityInfo<T> info, String sql, String keyColumn) {
|
||||
Connection conn = null;
|
||||
Map<K, N> rs = new LinkedHashMap<>();
|
||||
try {
|
||||
conn = readPool.poll();
|
||||
//conn.setReadOnly(true);
|
||||
final Statement stmt = conn.createStatement();
|
||||
Map<K, N> rs = new LinkedHashMap<>();
|
||||
ResultSet set = stmt.executeQuery(sql);
|
||||
ResultSetMetaData rsd = set.getMetaData();
|
||||
boolean smallint = rsd == null ? false : rsd.getColumnType(1) == Types.SMALLINT;
|
||||
@@ -411,9 +412,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
stmt.close();
|
||||
return CompletableFuture.completedFuture(rs);
|
||||
} catch (SQLException e) {
|
||||
if (info.getTableStrategy() != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(rs);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) readPool.offerConnection(conn);
|
||||
}
|
||||
@@ -433,10 +435,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
ps.close();
|
||||
return CompletableFuture.completedFuture(rs);
|
||||
} catch (SQLException e) {
|
||||
if (info.tableStrategy != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(null);
|
||||
if (info.getTableStrategy() != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(null);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) readPool.offerConnection(conn);
|
||||
}
|
||||
@@ -460,10 +462,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
ps.close();
|
||||
return CompletableFuture.completedFuture(val == null ? defValue : val);
|
||||
} catch (SQLException e) {
|
||||
if (info.tableStrategy != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(defValue);
|
||||
if (info.getTableStrategy() != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(defValue);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) readPool.offerConnection(conn);
|
||||
}
|
||||
@@ -483,10 +485,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
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);
|
||||
if (info.getTableStrategy() != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(false);
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) readPool.offerConnection(conn);
|
||||
}
|
||||
@@ -557,10 +559,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
ps.close();
|
||||
return CompletableFuture.completedFuture(new Sheet<>(total, list));
|
||||
} catch (SQLException e) {
|
||||
if (info.tableStrategy != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(new Sheet<>());
|
||||
if (info.getTableStrategy() != null && info.isTableNotExist(e)) return CompletableFuture.completedFuture(new Sheet<>());
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
future.completeExceptionally(e);
|
||||
return future;
|
||||
return future;//return CompletableFuture.failedFuture(e);
|
||||
} finally {
|
||||
if (conn != null) readPool.offerConnection(conn);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package org.redkale.source;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URL;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import javax.xml.stream.*;
|
||||
import org.redkale.util.AnyValue;
|
||||
@@ -139,7 +139,7 @@ public final class DataSources {
|
||||
public static DataSource createDataSource(final String unitName) throws IOException {
|
||||
return createDataSource(unitName, System.getProperty(DATASOURCE_CONFPATH) == null
|
||||
? DataJdbcSource.class.getResource("/META-INF/persistence.xml")
|
||||
: new File(System.getProperty(DATASOURCE_CONFPATH)).toURI().toURL());
|
||||
: (System.getProperty(DATASOURCE_CONFPATH, "").contains("://") ? URI.create(System.getProperty(DATASOURCE_CONFPATH)).toURL() : new File(System.getProperty(DATASOURCE_CONFPATH)).toURI().toURL()));
|
||||
}
|
||||
|
||||
public static DataSource createDataSource(final String unitName, URL persistxml) throws IOException {
|
||||
|
||||
@@ -91,7 +91,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
} else if (s.length() == 2) {
|
||||
s = "0" + s;
|
||||
}
|
||||
t.setName(cname + "-Thread-" + s);
|
||||
t.setName("Redkale-"+cname + "-Thread-" + s);
|
||||
t.setUncaughtExceptionHandler(ueh);
|
||||
return t;
|
||||
});
|
||||
@@ -209,6 +209,8 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
@Override
|
||||
public void destroy(AnyValue config) {
|
||||
if (this.executor != null) this.executor.shutdownNow();
|
||||
if (readPool != null) readPool.close();
|
||||
if (writePool != null) writePool.close();
|
||||
}
|
||||
|
||||
@Local
|
||||
@@ -466,7 +468,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
public <T> int delete(Class<T> clazz, final Flipper flipper, FilterNode node) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return deleteCache(info, -1, flipper, node);
|
||||
return DataSqlSource.this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> {
|
||||
return this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -481,14 +483,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (isOnlyCache(info)) {
|
||||
return CompletableFuture.supplyAsync(() -> deleteCache(info, -1, flipper, node), getExecutor());
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> {
|
||||
if (isAsync()) return this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
deleteCache(info, rs, flipper, node);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.deleteCompose(info, flipper, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.deleteCompose(info, flipper, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -542,7 +544,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
public <T> int clearTable(Class<T> clazz, FilterNode node) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return clearTableCache(info, node);
|
||||
return DataSqlSource.this.clearTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
return this.clearTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -562,14 +564,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (isOnlyCache(info)) {
|
||||
return CompletableFuture.supplyAsync(() -> clearTableCache(info, node), getExecutor());
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.clearTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
if (isAsync()) return this.clearTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
clearTableCache(info, node);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.clearTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.clearTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -594,7 +596,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
public <T> int dropTable(Class<T> clazz, FilterNode node) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return dropTableCache(info, node);
|
||||
return DataSqlSource.this.dropTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
return this.dropTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -614,14 +616,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (isOnlyCache(info)) {
|
||||
return CompletableFuture.supplyAsync(() -> dropTableCache(info, node), getExecutor());
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.dropTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
if (isAsync()) return this.dropTableCompose(info, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
dropTableCache(info, node);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.dropTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.dropTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -812,7 +814,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
public <T> int updateColumn(Class<T> clazz, String column, Serializable colval, FilterNode node) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return updateCache(info, -1, column, colval, node);
|
||||
return DataSqlSource.this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> {
|
||||
return this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -827,14 +829,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (isOnlyCache(info)) {
|
||||
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, column, colval, node), getExecutor());
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> {
|
||||
if (isAsync()) return this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
updateCache(info, rs, column, colval, node);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.updateColumnCompose(info, column, colval, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, column, colval, node).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -886,7 +888,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (values == null || values.length < 1) return -1;
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return updateCache(info, -1, pk, values);
|
||||
return DataSqlSource.this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> {
|
||||
return this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -902,14 +904,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (isOnlyCache(info)) {
|
||||
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, pk, values), getExecutor());
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> {
|
||||
if (isAsync()) return this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
updateCache(info, rs, pk, values);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.updateColumnCompose(info, pk, values).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, pk, values).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -967,7 +969,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (values == null || values.length < 1) return -1;
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return updateCache(info, -1, node, flipper, values);
|
||||
return DataSqlSource.this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> {
|
||||
return this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -983,14 +985,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
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) -> {
|
||||
if (isAsync()) return this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
updateCache(info, rs, node, flipper, values);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.updateColumnCompose(info, node, flipper, values).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, node, flipper, values).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -1063,7 +1065,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
Class<T> clazz = (Class) entity.getClass();
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return updateCache(info, -1, false, entity, null, selects);
|
||||
return DataSqlSource.this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> {
|
||||
return this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -1080,14 +1082,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (isOnlyCache(info)) {
|
||||
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, false, entity, null, selects), getExecutor());
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> {
|
||||
if (isAsync()) return this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
updateCache(info, rs, false, entity, null, selects);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.updateColumnCompose(info, false, entity, null, selects).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, false, entity, null, selects).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -1102,7 +1104,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
Class<T> clazz = (Class) entity.getClass();
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (isOnlyCache(info)) return updateCache(info, -1, true, entity, node, selects);
|
||||
return DataSqlSource.this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> {
|
||||
return this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -1119,14 +1121,14 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (isOnlyCache(info)) {
|
||||
return CompletableFuture.supplyAsync(() -> updateCache(info, -1, true, entity, node, selects), getExecutor());
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> {
|
||||
if (isAsync()) return this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
updateCache(info, rs, true, entity, node, selects);
|
||||
}
|
||||
});
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.updateColumnCompose(info, true, entity, node, selects).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, true, entity, node, selects).join(), getExecutor()).whenComplete((rs, t) -> {
|
||||
if (t != null) {
|
||||
futureCompleteConsumer.accept(rs, t);
|
||||
} else {
|
||||
@@ -1601,7 +1603,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.find(selects, node);
|
||||
return DataSqlSource.this.findCompose(info, selects, node).join();
|
||||
return this.findCompose(info, selects, node).join();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1611,8 +1613,8 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) {
|
||||
return CompletableFuture.completedFuture(cache.find(selects, node));
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.findCompose(info, selects, node);
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.findCompose(info, selects, node).join(), getExecutor());
|
||||
if (isAsync()) return this.findCompose(info, selects, node);
|
||||
return CompletableFuture.supplyAsync(() -> this.findCompose(info, selects, node).join(), getExecutor());
|
||||
}
|
||||
|
||||
protected <T> CompletableFuture<T> findCompose(final EntityInfo<T> info, final SelectColumn selects, final FilterNode node) {
|
||||
@@ -1701,7 +1703,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
Serializable val = cache.findColumn(column, defValue, node);
|
||||
if (cache.isFullLoaded() || val != null) return val;
|
||||
}
|
||||
return DataSqlSource.this.findColumnCompose(info, column, defValue, node).join();
|
||||
return this.findColumnCompose(info, column, defValue, node).join();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1712,8 +1714,8 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
Serializable val = cache.findColumn(column, defValue, node);
|
||||
if (cache.isFullLoaded() || val != null) return CompletableFuture.completedFuture(val);
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.findColumnCompose(info, column, defValue, node);
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.findColumnCompose(info, column, defValue, node).join(), getExecutor());
|
||||
if (isAsync()) return this.findColumnCompose(info, column, defValue, node);
|
||||
return CompletableFuture.supplyAsync(() -> this.findColumnCompose(info, column, defValue, node).join(), getExecutor());
|
||||
}
|
||||
|
||||
protected <T> CompletableFuture<Serializable> findColumnCompose(final EntityInfo<T> info, String column, final Serializable defValue, final FilterNode node) {
|
||||
@@ -1773,7 +1775,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
boolean rs = cache.exists(node);
|
||||
if (rs || cache.isFullLoaded()) return rs;
|
||||
}
|
||||
return DataSqlSource.this.existsCompose(info, node).join();
|
||||
return this.existsCompose(info, node).join();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1784,8 +1786,8 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
||||
boolean rs = cache.exists(node);
|
||||
if (rs || cache.isFullLoaded()) return CompletableFuture.completedFuture(rs);
|
||||
}
|
||||
if (isAsync()) return DataSqlSource.this.existsCompose(info, node);
|
||||
return CompletableFuture.supplyAsync(() -> DataSqlSource.this.existsCompose(info, node).join(), getExecutor());
|
||||
if (isAsync()) return this.existsCompose(info, node);
|
||||
return CompletableFuture.supplyAsync(() -> this.existsCompose(info, node).join(), getExecutor());
|
||||
}
|
||||
|
||||
protected <T> CompletableFuture<Boolean> existsCompose(final EntityInfo<T> info, FilterNode node) {
|
||||
|
||||
@@ -89,16 +89,16 @@ public final class EntityInfo<T> {
|
||||
final String notcontainSQL;
|
||||
|
||||
//用于判断表不存在的使用, 多个SQLState用;隔开
|
||||
final String tablenotexistSqlstates;
|
||||
private final String tablenotexistSqlstates;
|
||||
|
||||
//用于复制表结构使用
|
||||
final String tablecopySQL;
|
||||
private final String tablecopySQL;
|
||||
|
||||
//用于存在database.table_20160202类似这种分布式表
|
||||
final Set<String> tables = new HashSet<>();
|
||||
private final Set<String> tables = new HashSet<>();
|
||||
|
||||
//分表 策略
|
||||
final DistributeTableStrategy<T> tableStrategy;
|
||||
private final DistributeTableStrategy<T> tableStrategy;
|
||||
|
||||
//根据主键查找单个对象的SQL, 含 ?
|
||||
private final String queryPrepareSQL;
|
||||
@@ -239,7 +239,7 @@ public final class EntityInfo<T> {
|
||||
}
|
||||
//---------------------------------------------
|
||||
Table t = type.getAnnotation(Table.class);
|
||||
if (type.getAnnotation(VirtualEntity.class) != null || "memory".equalsIgnoreCase(source.getType())) {
|
||||
if (type.getAnnotation(VirtualEntity.class) != null || (source == null || "memory".equalsIgnoreCase(source.getType()))) {
|
||||
this.table = null;
|
||||
BiFunction<DataSource, Class, List> loader = null;
|
||||
try {
|
||||
@@ -510,6 +510,18 @@ public final class EntityInfo<T> {
|
||||
return tableStrategy;
|
||||
}
|
||||
|
||||
public Object disTableLock() {
|
||||
return tables;
|
||||
}
|
||||
|
||||
public boolean containsDisTable(String tablekey) {
|
||||
return tables.contains(tablekey);
|
||||
}
|
||||
|
||||
public void addDisTable(String tablekey) {
|
||||
tables.add(tablekey);
|
||||
}
|
||||
|
||||
public String getTableNotExistSqlStates2() {
|
||||
return tablenotexistSqlstates;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@ public enum FilterExpress {
|
||||
NOTLIKE("NOT LIKE"),
|
||||
IGNORECASELIKE("LIKE"), //不区分大小写的 LIKE
|
||||
IGNORECASENOTLIKE("NOT LIKE"), //不区分大小写的 NOT LIKE
|
||||
LENGTH_EQUAL("="), //字符串值的长度
|
||||
LENGTH_LESSTHAN("<"), //字符串值的长度 <
|
||||
LENGTH_LESSTHANOREQUALTO("<="), //字符串值的长度 <=
|
||||
LENGTH_GREATERTHAN(">"), //字符串值的长度 >
|
||||
LENGTH_GREATERTHANOREQUALTO(">="), //字符串值的长度 >=
|
||||
|
||||
CONTAIN("CONTAIN"), //包含, 相当于反向LIKE
|
||||
NOTCONTAIN("NOT CONTAIN"), //不包含, 相当于反向LIKE
|
||||
|
||||
@@ -397,7 +397,10 @@ public class FilterNode { //FilterNode 不能实现Serializable接口, 否则
|
||||
if (express == NOTCONTAIN) return info.notcontainSQL.replace("${column}", info.getSQLColumn(talis, column)).replace("${keystr}", val);
|
||||
if (express == IGNORECASENOTCONTAIN) return info.notcontainSQL.replace("${column}", "LOWER(" + info.getSQLColumn(talis, column) + ")").replace("${keystr}", val);
|
||||
|
||||
if (express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL || express == IGNORECASELIKE || express == IGNORECASENOTLIKE) {
|
||||
if (express == LENGTH_EQUAL || express == LENGTH_LESSTHAN || express == LENGTH_LESSTHANOREQUALTO
|
||||
|| express == LENGTH_GREATERTHAN || express == LENGTH_GREATERTHANOREQUALTO) {
|
||||
sb.append("LENGTH(").append(info.getSQLColumn(talis, column)).append(')');
|
||||
} else if (express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL || express == IGNORECASELIKE || express == IGNORECASENOTLIKE) {
|
||||
sb.append("LOWER(").append(info.getSQLColumn(talis, column)).append(')');
|
||||
if (fk) val = "LOWER(" + info.getSQLColumn(talis, ((FilterKey) val0).getColumn()) + ')';
|
||||
} else {
|
||||
@@ -1406,6 +1409,81 @@ public class FilterNode { //FilterNode 不能实现Serializable接口, 否则
|
||||
return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(valstr2);
|
||||
}
|
||||
};
|
||||
case LENGTH_EQUAL:
|
||||
final int intval = ((Number) val).intValue();
|
||||
return new Predicate<T>() {
|
||||
|
||||
@Override
|
||||
public boolean test(T t) {
|
||||
Object rs = attr.get(t);
|
||||
return (rs == null && 0 == intval) || (rs != null && rs.toString().length() == intval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LENGTH(" + field + ") " + express.value() + ' ' + intval;
|
||||
}
|
||||
};
|
||||
case LENGTH_LESSTHAN:
|
||||
final int intval2 = ((Number) val).intValue();
|
||||
return new Predicate<T>() {
|
||||
|
||||
@Override
|
||||
public boolean test(T t) {
|
||||
Object rs = attr.get(t);
|
||||
return (rs == null && 0 < intval2) || (rs != null && rs.toString().length() < intval2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LENGTH(" + field + ") " + express.value() + ' ' + intval2;
|
||||
}
|
||||
};
|
||||
case LENGTH_LESSTHANOREQUALTO:
|
||||
final int intval3 = ((Number) val).intValue();
|
||||
return new Predicate<T>() {
|
||||
|
||||
@Override
|
||||
public boolean test(T t) {
|
||||
Object rs = attr.get(t);
|
||||
return (rs == null && 0 <= intval3) || (rs != null && rs.toString().length() <= intval3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LENGTH(" + field + ") " + express.value() + ' ' + intval3;
|
||||
}
|
||||
};
|
||||
case LENGTH_GREATERTHAN:
|
||||
final int intval4 = ((Number) val).intValue();
|
||||
return new Predicate<T>() {
|
||||
|
||||
@Override
|
||||
public boolean test(T t) {
|
||||
Object rs = attr.get(t);
|
||||
return (rs == null && 0 > intval4) || (rs != null && rs.toString().length() > intval4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LENGTH(" + field + ") " + express.value() + ' ' + intval4;
|
||||
}
|
||||
};
|
||||
case LENGTH_GREATERTHANOREQUALTO:
|
||||
final int intval5 = ((Number) val).intValue();
|
||||
return new Predicate<T>() {
|
||||
|
||||
@Override
|
||||
public boolean test(T t) {
|
||||
Object rs = attr.get(t);
|
||||
return (rs == null && 0 >= intval5) || (rs != null && rs.toString().length() >= intval5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LENGTH(" + field + ") " + express.value() + ' ' + intval5;
|
||||
}
|
||||
};
|
||||
case CONTAIN:
|
||||
return fk ? new Predicate<T>() {
|
||||
|
||||
|
||||
@@ -363,6 +363,9 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
|
||||
sb.append(col).append(' ').append(express.value());
|
||||
} else if (express == ISEMPTY || express == ISNOTEMPTY) {
|
||||
sb.append(col).append(' ').append(express.value()).append(" ''");
|
||||
} else if (express == LENGTH_EQUAL || express == LENGTH_LESSTHAN || express == LENGTH_LESSTHANOREQUALTO
|
||||
|| express == LENGTH_GREATERTHAN || express == LENGTH_GREATERTHANOREQUALTO) {
|
||||
sb.append("LENGTH(").append(col).append(") ").append(express.value()).append(" ?");
|
||||
} else {
|
||||
boolean lower = (express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL || express == IGNORECASELIKE
|
||||
|| express == IGNORECASENOTLIKE || express == IGNORECASECONTAIN || express == IGNORECASENOTCONTAIN);
|
||||
|
||||
@@ -38,6 +38,8 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
||||
//TCP Channel组
|
||||
protected AsynchronousChannelGroup group;
|
||||
|
||||
protected ScheduledThreadPoolExecutor scheduler;
|
||||
|
||||
protected final ArrayBlockingQueue<AsyncConnection> connQueue;
|
||||
|
||||
public PoolTcpSource(String rwtype, ArrayBlockingQueue queue, Semaphore semaphore, Properties prop, Logger logger, ObjectPool<ByteBuffer> bufferPool, ThreadPoolExecutor executor) {
|
||||
@@ -50,6 +52,42 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.connQueue = queue == null ? new ArrayBlockingQueue<>(this.maxconns) : queue;
|
||||
this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
|
||||
final Thread t = new Thread(r, "PoolSource-Scheduled-Thread");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
});
|
||||
this.scheduler.scheduleAtFixedRate(() -> {
|
||||
runPingTask();
|
||||
}, 60, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void runPingTask() {
|
||||
try {
|
||||
if (connQueue.isEmpty()) return;
|
||||
long time = System.currentTimeMillis() - 30 * 1000;
|
||||
AsyncConnection first = connQueue.peek();
|
||||
if (first == null || first.getLastReadTime() >= time || first.getLastWriteTime() >= time) return;
|
||||
pollAsync().whenComplete((conn, e) -> {
|
||||
if (e != null) return;
|
||||
if (conn.getLastReadTime() >= time || conn.getLastWriteTime() >= time) {//半分钟内已经用过
|
||||
offerConnection(conn);
|
||||
return;
|
||||
}
|
||||
CompletableFuture<AsyncConnection> future = sendPingCommand(conn);
|
||||
if (future == null) { //不支持ping
|
||||
offerConnection(conn);
|
||||
return;
|
||||
}
|
||||
future.whenComplete((conn2, e2) -> {
|
||||
if (e2 != null) return;
|
||||
offerConnection(conn2);
|
||||
runPingTask();
|
||||
});
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.FINEST, "PoolSource task ping failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -216,6 +254,7 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.scheduler.shutdownNow();
|
||||
connQueue.stream().forEach(x -> {
|
||||
CompletableFuture<AsyncConnection> future = null;
|
||||
try {
|
||||
@@ -232,5 +271,7 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract CompletableFuture<AsyncConnection> sendPingCommand(final AsyncConnection conn);
|
||||
|
||||
protected abstract CompletableFuture<AsyncConnection> sendCloseCommand(final AsyncConnection conn);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,14 @@ public class ByteBufferReader {
|
||||
this.bigEndian = this.currBuffer.order() == ByteOrder.BIG_ENDIAN;
|
||||
}
|
||||
|
||||
public ByteBufferReader append(ByteBuffer... buffs) {
|
||||
for (ByteBuffer buf : buffs) {
|
||||
Objects.requireNonNull(buf);
|
||||
}
|
||||
this.buffers = Utility.append(this.buffers, buffs);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static ByteBufferReader create(ByteBuffer buffer) {
|
||||
return new ByteBufferReader(buffer);
|
||||
}
|
||||
@@ -80,7 +88,30 @@ public class ByteBufferReader {
|
||||
}
|
||||
|
||||
public boolean hasRemaining() {
|
||||
return this.currBuffer.hasRemaining();
|
||||
boolean v = this.currBuffer.hasRemaining();
|
||||
if (v) return v;
|
||||
if (this.currIndex == this.buffers.length - 1) return false;
|
||||
for (int i = this.currIndex + 1; i < this.buffers.length; i++) {
|
||||
if (this.buffers[i].hasRemaining()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int remaining() {
|
||||
int v = this.currBuffer.remaining();
|
||||
for (int i = this.currIndex + 1; i < this.buffers.length; i++) {
|
||||
v += this.buffers[i].remaining();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
//提前预读一个字节
|
||||
public byte preget() {
|
||||
ByteBuffer buf = this.currBuffer;
|
||||
if (!buf.hasRemaining()) {
|
||||
buf = this.buffers[this.currIndex + 1];
|
||||
}
|
||||
return buf.get(buf.position());
|
||||
}
|
||||
|
||||
public byte get() {
|
||||
|
||||
@@ -85,6 +85,13 @@ public interface Creator<T> {
|
||||
creatorCacheMap.put(Stream.class, (params) -> new ArrayList<>().stream());
|
||||
creatorCacheMap.put(ConcurrentHashMap.class, (params) -> new ConcurrentHashMap<>());
|
||||
creatorCacheMap.put(CompletableFuture.class, (params) -> new CompletableFuture<>());
|
||||
creatorCacheMap.put(Map.Entry.class, new Creator<Map.Entry>() {
|
||||
@Override
|
||||
@ConstructorParameters({"key", "value"})
|
||||
public Map.Entry create(Object... params) {
|
||||
return new AbstractMap.SimpleEntry(params[0], params[1]);
|
||||
}
|
||||
});
|
||||
creatorCacheMap.put(AbstractMap.SimpleEntry.class, new Creator<AbstractMap.SimpleEntry>() {
|
||||
@Override
|
||||
@ConstructorParameters({"key", "value"})
|
||||
@@ -232,6 +239,8 @@ public interface Creator<T> {
|
||||
clazz = (Class<T>) ConcurrentHashMap.class;
|
||||
} else if (Collection.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ArrayList.class)) {
|
||||
clazz = (Class<T>) ArrayList.class;
|
||||
} else if (Map.Entry.class.isAssignableFrom(clazz) && (Modifier.isInterface(clazz.getModifiers()) || Modifier.isAbstract(clazz.getModifiers()) || !Modifier.isPublic(clazz.getModifiers()))) {
|
||||
clazz = (Class<T>) AbstractMap.SimpleEntry.class;
|
||||
}
|
||||
Creator creator = CreatorInner.creatorCacheMap.get(clazz);
|
||||
if (creator != null) return creator;
|
||||
|
||||
@@ -19,23 +19,25 @@ import java.util.logging.*;
|
||||
* @author zhangjx
|
||||
* @param <T> 对象池元素的数据类型
|
||||
*/
|
||||
public final class ObjectPool<T> implements Supplier<T>, Consumer<T> {
|
||||
public class ObjectPool<T> implements Supplier<T>, Consumer<T> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ObjectPool.class.getSimpleName());
|
||||
protected static final Logger logger = Logger.getLogger(ObjectPool.class.getSimpleName());
|
||||
|
||||
private final boolean debug;
|
||||
protected final boolean debug;
|
||||
|
||||
private final Queue<T> queue;
|
||||
protected Creator<T> creator;
|
||||
|
||||
private Creator<T> creator;
|
||||
protected int max;
|
||||
|
||||
private final Consumer<T> prepare;
|
||||
protected final Consumer<T> prepare;
|
||||
|
||||
private final Predicate<T> recycler;
|
||||
protected final Predicate<T> recycler;
|
||||
|
||||
private final AtomicLong creatCounter;
|
||||
protected final AtomicLong creatCounter;
|
||||
|
||||
private final AtomicLong cycleCounter;
|
||||
protected final AtomicLong cycleCounter;
|
||||
|
||||
protected final Queue<T> queue;
|
||||
|
||||
public ObjectPool(Class<T> clazz, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(2, clazz, prepare, recycler);
|
||||
@@ -62,12 +64,18 @@ public final class ObjectPool<T> implements Supplier<T>, Consumer<T> {
|
||||
}
|
||||
|
||||
public ObjectPool(AtomicLong creatCounter, AtomicLong cycleCounter, int max, Creator<T> creator, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(creatCounter, cycleCounter, Math.max(Runtime.getRuntime().availableProcessors() * 2, max),
|
||||
creator, prepare, recycler, new LinkedBlockingQueue<>(Math.max(Runtime.getRuntime().availableProcessors() * 2, max)));
|
||||
}
|
||||
|
||||
protected ObjectPool(AtomicLong creatCounter, AtomicLong cycleCounter, int max, Creator<T> creator, Consumer<T> prepare, Predicate<T> recycler, Queue<T> queue) {
|
||||
this.creatCounter = creatCounter;
|
||||
this.cycleCounter = cycleCounter;
|
||||
this.creator = creator;
|
||||
this.prepare = prepare;
|
||||
this.recycler = recycler;
|
||||
this.queue = new LinkedBlockingQueue<>(Math.max(Runtime.getRuntime().availableProcessors() * 2, max));
|
||||
this.queue = queue;
|
||||
this.max = max;
|
||||
this.debug = logger.isLoggable(Level.FINEST);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public final class Redkale {
|
||||
}
|
||||
|
||||
public static String getDotedVersion() {
|
||||
return "2.0.0-beta4";
|
||||
return "2.0.0-rc3";
|
||||
}
|
||||
|
||||
public static int getMajorVersion() {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.redkale.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
@@ -42,12 +43,22 @@ public final class ResourceFactory {
|
||||
|
||||
private final List<WeakReference<ResourceFactory>> chidren = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final ConcurrentHashMap<Type, ResourceLoader> loadermap = new ConcurrentHashMap();
|
||||
private final ConcurrentHashMap<Type, ResourceInjectLoader> injectLoaderMap = new ConcurrentHashMap();
|
||||
|
||||
private final ConcurrentHashMap<Type, ResourceLoader> resLoaderMap = new ConcurrentHashMap();
|
||||
|
||||
private final ConcurrentHashMap<Type, ConcurrentHashMap<String, ResourceEntry>> store = new ConcurrentHashMap();
|
||||
|
||||
private ResourceFactory(ResourceFactory parent) {
|
||||
this.parent = parent;
|
||||
if (parent == null) {
|
||||
ServiceLoader<ResourceInjectLoader> loaders = ServiceLoader.load(ResourceInjectLoader.class);
|
||||
Iterator<ResourceInjectLoader> it = loaders.iterator();
|
||||
while (it.hasNext()) {
|
||||
ResourceInjectLoader ril = it.next();
|
||||
this.injectLoaderMap.put(ril.annotationType(), ril);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,6 +576,7 @@ public final class ResourceFactory {
|
||||
try {
|
||||
list.add(src);
|
||||
Class clazz = src.getClass();
|
||||
final boolean diyloaderflag = !instance.injectLoaderMap.isEmpty();
|
||||
do {
|
||||
if (java.lang.Enum.class.isAssignableFrom(clazz)) break;
|
||||
final String cname = clazz.getName();
|
||||
@@ -586,6 +598,13 @@ public final class ResourceFactory {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag && diyloaderflag) {
|
||||
instance.injectLoaderMap.values().stream().forEach(iloader -> {
|
||||
Annotation ann = field.getAnnotation(iloader.annotationType());
|
||||
if (ann == null) return;
|
||||
iloader.load(this, src, ann, field, attachment);
|
||||
});
|
||||
}
|
||||
if (ns == null) continue;
|
||||
final String nsname = ns.getClass().getName();
|
||||
if (ns.getClass().isPrimitive() || ns.getClass().isArray()
|
||||
@@ -685,16 +704,21 @@ public final class ResourceFactory {
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Annotation> void register(final ResourceInjectLoader<T> loader) {
|
||||
if (loader == null) return;
|
||||
instance.injectLoaderMap.put(loader.annotationType(), loader);
|
||||
}
|
||||
|
||||
public void register(final ResourceLoader rs, final Type... clazzs) {
|
||||
if (clazzs == null || rs == null) return;
|
||||
for (Type clazz : clazzs) {
|
||||
loadermap.put(clazz, rs);
|
||||
resLoaderMap.put(clazz, rs);
|
||||
}
|
||||
}
|
||||
|
||||
private ResourceLoader findMatchLoader(Type ft, Field field) {
|
||||
ResourceLoader it = this.loadermap.get(ft);
|
||||
if (it == null && field != null) it = this.loadermap.get(field.getType());
|
||||
ResourceLoader it = this.resLoaderMap.get(ft);
|
||||
if (it == null && field != null) it = this.resLoaderMap.get(field.getType());
|
||||
if (it != null) return it;
|
||||
return parent == null ? null : parent.findMatchLoader(ft, field);
|
||||
}
|
||||
@@ -702,7 +726,7 @@ public final class ResourceFactory {
|
||||
private ResourceLoader findRegxLoader(Type ft, Field field) {
|
||||
if (field == null) return null;
|
||||
Class c = field.getType();
|
||||
for (Map.Entry<Type, ResourceLoader> en : this.loadermap.entrySet()) {
|
||||
for (Map.Entry<Type, ResourceLoader> en : this.resLoaderMap.entrySet()) {
|
||||
Type t = en.getKey();
|
||||
if (t == ft) return en.getValue();
|
||||
if (t instanceof Class && (((Class) t)).isAssignableFrom(c)) return en.getValue();
|
||||
|
||||
25
src/org/redkale/util/ResourceInjectLoader.java
Normal file
25
src/org/redkale/util/ResourceInjectLoader.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 自定义注入加载器
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <T> Annotation
|
||||
*/
|
||||
public interface ResourceInjectLoader<T extends Annotation> {
|
||||
|
||||
public void load(ResourceFactory factory, Object src, T annotation, Field field, Object attachment);
|
||||
|
||||
public Class<T> annotationType();
|
||||
}
|
||||
70
src/org/redkale/util/ThreadLocalObjectPool.java
Normal file
70
src/org/redkale/util/ThreadLocalObjectPool.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.*;
|
||||
|
||||
/**
|
||||
* 对象池
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <T> 对象池元素的数据类型
|
||||
*/
|
||||
public class ThreadLocalObjectPool<T> extends ObjectPool<T> {
|
||||
|
||||
public ThreadLocalObjectPool(Class<T> clazz, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(2, clazz, prepare, recycler);
|
||||
}
|
||||
|
||||
public ThreadLocalObjectPool(int max, Class<T> clazz, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(max, Creator.create(clazz), prepare, recycler);
|
||||
}
|
||||
|
||||
public ThreadLocalObjectPool(Creator<T> creator, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(2, creator, prepare, recycler);
|
||||
}
|
||||
|
||||
public ThreadLocalObjectPool(int max, Creator<T> creator, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(null, null, max, creator, prepare, recycler);
|
||||
}
|
||||
|
||||
public ThreadLocalObjectPool(int max, Supplier<T> creator, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(null, null, max, creator, prepare, recycler);
|
||||
}
|
||||
|
||||
public ThreadLocalObjectPool(AtomicLong creatCounter, AtomicLong cycleCounter, int max, Supplier<T> creator, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
this(creatCounter, cycleCounter, max, c -> creator.get(), prepare, recycler);
|
||||
}
|
||||
|
||||
public ThreadLocalObjectPool(AtomicLong creatCounter, AtomicLong cycleCounter, int max, Creator<T> creator, Consumer<T> prepare, Predicate<T> recycler) {
|
||||
super(creatCounter, cycleCounter, max, creator, prepare, recycler, new LinkedList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
T result = queue.poll();
|
||||
if (result == null) {
|
||||
if (creatCounter != null) creatCounter.incrementAndGet();
|
||||
result = this.creator.create();
|
||||
}
|
||||
if (prepare != null) prepare.accept(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(final T e) {
|
||||
if (e != null && recycler.test(e) && this.queue.size() < this.max) {
|
||||
if (cycleCounter != null) cycleCounter.incrementAndGet();
|
||||
queue.offer(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -83,7 +83,8 @@ public abstract class TypeToken<T> {
|
||||
if (type instanceof TypeVariable) return null;
|
||||
if (type instanceof GenericArrayType) return Array.newInstance(typeToClass(((GenericArrayType) type).getGenericComponentType()), 0).getClass();
|
||||
if (!(type instanceof ParameterizedType)) return null; //只能是null了
|
||||
return typeToClass(((ParameterizedType) type).getOwnerType());
|
||||
Type owner = ((ParameterizedType) type).getOwnerType();
|
||||
return typeToClass(owner == null ? ((ParameterizedType) type).getRawType() : owner);
|
||||
}
|
||||
|
||||
public static Type[] getGenericType(final Type[] types, final Type declaringClass) {
|
||||
|
||||
@@ -37,13 +37,13 @@ public final class Utility {
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
* public final class AnonymousArrayFunction implements java.util.function.Function<Object, char[]> {
|
||||
* public final class AnonymousCharArrayFunction implements java.util.function.Function<Object, char[]> {
|
||||
*
|
||||
* final sun.misc.Unsafe unsafe;
|
||||
*
|
||||
* final long fd;
|
||||
*
|
||||
* public AnonymousArrayFunction(Object obj, long fd) {
|
||||
* public AnonymousCharArrayFunction(Object obj, long fd) {
|
||||
* this.unsafe = (sun.misc.Unsafe) obj;
|
||||
* this.fd = fd;
|
||||
* }
|
||||
@@ -56,37 +56,80 @@ public final class Utility {
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
private static final String functionClassBinary = "cafebabe00000034002f0a00090022070023090008002409000800250a000200260700"
|
||||
+ "270a0008002807002907002a07002b010006756e736166650100114c73756e2f6d6973632f556e736166653b01000266640100014a0100063c69"
|
||||
+ "6e69743e010016284c6a6176612f6c616e672f4f626a6563743b4a2956010004436f646501000f4c696e654e756d6265725461626c650100124c"
|
||||
+ "6f63616c5661726961626c655461626c65010004746869730100294c6f72672f7265646b616c652f7574696c2f416e6f6e796d6f757341727261"
|
||||
+ "7946756e6374696f6e3b0100036f626a0100124c6a6176612f6c616e672f4f626a6563743b0100056170706c79010016284c6a6176612f6c616e"
|
||||
+ "672f4f626a6563743b295b43010001740100236f72672e6e65746265616e732e536f757263654c6576656c416e6e6f746174696f6e730100144c"
|
||||
+ "6a6176612f6c616e672f4f766572726964653b010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563"
|
||||
+ "743b0100095369676e61747572650100454c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f66756e6374696f6e2f46756e"
|
||||
+ "6374696f6e3c4c6a6176612f6c616e672f4f626a6563743b5b433e3b01000a536f7572636546696c6501001b416e6f6e796d6f75734172726179"
|
||||
+ "46756e6374696f6e2e6a6176610c000f002c01000f73756e2f6d6973632f556e736166650c000b000c0c000d000e0c002d002e0100025b430c00"
|
||||
+ "1800190100276f72672f7265646b616c652f7574696c2f416e6f6e796d6f7573417272617946756e6374696f6e0100106a6176612f6c616e672f"
|
||||
+ "4f626a65637401001b6a6176612f7574696c2f66756e6374696f6e2f46756e6374696f6e0100032829560100096765744f626a65637401002728"
|
||||
+ "4c6a6176612f6c616e672f4f626a6563743b4a294c6a6176612f6c616e672f4f626a6563743b0031000800090001000a00020010000b000c0000"
|
||||
+ "0010000d000e000000030001000f0010000100110000005c00030004000000122ab700012a2bc00002b500032a20b50004b10000000200120000"
|
||||
+ "001200040000000e0004000f000c0010001100110013000000200003000000120014001500000000001200160017000100000012000d000e0002"
|
||||
+ "000100180019000200110000004400040002000000102ab400032b2ab40004b60005c00006b00000000200120000000600010000001500130000"
|
||||
+ "001600020000001000140015000000000010001a00170001001b000000060001001c000010410018001d00020011000000300002000200000006"
|
||||
+ "2a2bb60007b00000000200120000000600010000000800130000000c000100000006001400150000001b000000060001001c00000002001e0000"
|
||||
+ "0002001f0020000000020021";
|
||||
private static final String functionCharClassBinary = "cafebabe00000034002d0a00090020070021090008002209000800230a00020024070025"
|
||||
+ "0a00080026070027070028070029010006756e736166650100114c73756e2f6d6973632f556e736166653b01000266640100014a0100063c696e69743e0"
|
||||
+ "10016284c6a6176612f6c616e672f4f626a6563743b4a2956010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c56617269"
|
||||
+ "61626c655461626c650100047468697301002d4c6f72672f7265646b616c652f7574696c2f416e6f6e796d6f757343686172417272617946756e6374696"
|
||||
+ "f6e3b0100036f626a0100124c6a6176612f6c616e672f4f626a6563743b0100056170706c79010016284c6a6176612f6c616e672f4f626a6563743b295b"
|
||||
+ "4301000174010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0100095369676e61747572650100454"
|
||||
+ "c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f66756e6374696f6e2f46756e6374696f6e3c4c6a6176612f6c616e672f4f626a65"
|
||||
+ "63743b5b433e3b01000a536f7572636546696c6501001f416e6f6e796d6f757343686172417272617946756e6374696f6e2e6a6176610c000f002a01000"
|
||||
+ "f73756e2f6d6973632f556e736166650c000b000c0c000d000e0c002b002c0100025b430c0018001901002b6f72672f7265646b616c652f7574696c2f41"
|
||||
+ "6e6f6e796d6f757343686172417272617946756e6374696f6e0100106a6176612f6c616e672f4f626a65637401001b6a6176612f7574696c2f66756e637"
|
||||
+ "4696f6e2f46756e6374696f6e0100032829560100096765744f626a656374010027284c6a6176612f6c616e672f4f626a6563743b4a294c6a6176612f6c"
|
||||
+ "616e672f4f626a6563743b0021000800090001000a00020010000b000c00000010000d000e000000030001000f0010000100110000005c0003000400000"
|
||||
+ "0122ab700012a2bc00002b500032a20b50004b10000000200120000001200040000001200040013000c0014001100150013000000200003000000120014"
|
||||
+ "001500000000001200160017000100000012000d000e0002000100180019000100110000004700040002000000132ab400032b2ab40004b60005c00006c"
|
||||
+ "00006b00000000200120000000600010000001900130000001600020000001300140015000000000013001a0017000110410018001b0001001100000030"
|
||||
+ "00020002000000062a2bb60007b00000000200120000000600010000000c00130000000c0001000000060014001500000002001c00000002001d001e000"
|
||||
+ "00002001f";
|
||||
|
||||
private static final Function<Object, char[]> strFunction;
|
||||
private static final Function<Object, char[]> strCharFunction;
|
||||
|
||||
private static final Function<Object, char[]> sbFunction;
|
||||
private static final Function<Object, char[]> sbCharFunction;
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
* public final class AnonymousByteArrayFunction implements java.util.function.Function<Object, byte[]> {
|
||||
*
|
||||
* final sun.misc.Unsafe unsafe;
|
||||
*
|
||||
* final long fd;
|
||||
*
|
||||
* public AnonymousByteArrayFunction(Object obj, long fd) {
|
||||
* this.unsafe = (sun.misc.Unsafe) obj;
|
||||
* this.fd = fd;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public byte[] apply(Object t) {
|
||||
* return (byte[]) unsafe.getObject(t, fd);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
private static final String functionByteClassBinary = "cafebabe00000034002d0a00090020070021090008002209000800230a00020024070025"
|
||||
+ "0a00080026070027070028070029010006756e736166650100114c73756e2f6d6973632f556e736166653b01000266640100014a0100063c696e69743e0"
|
||||
+ "10016284c6a6176612f6c616e672f4f626a6563743b4a2956010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c56617269"
|
||||
+ "61626c655461626c650100047468697301002d4c6f72672f7265646b616c652f7574696c2f416e6f6e796d6f757342797465417272617946756e6374696"
|
||||
+ "f6e3b0100036f626a0100124c6a6176612f6c616e672f4f626a6563743b0100056170706c79010016284c6a6176612f6c616e672f4f626a6563743b295b"
|
||||
+ "4201000174010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0100095369676e61747572650100454"
|
||||
+ "c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f66756e6374696f6e2f46756e6374696f6e3c4c6a6176612f6c616e672f4f626a65"
|
||||
+ "63743b5b423e3b01000a536f7572636546696c6501001f416e6f6e796d6f757342797465417272617946756e6374696f6e2e6a6176610c000f002a01000"
|
||||
+ "f73756e2f6d6973632f556e736166650c000b000c0c000d000e0c002b002c0100025b420c0018001901002b6f72672f7265646b616c652f7574696c2f41"
|
||||
+ "6e6f6e796d6f757342797465417272617946756e6374696f6e0100106a6176612f6c616e672f4f626a65637401001b6a6176612f7574696c2f66756e637"
|
||||
+ "4696f6e2f46756e6374696f6e0100032829560100096765744f626a656374010027284c6a6176612f6c616e672f4f626a6563743b4a294c6a6176612f6c"
|
||||
+ "616e672f4f626a6563743b0021000800090001000a00020010000b000c00000010000d000e000000030001000f0010000100110000005c0003000400000"
|
||||
+ "0122ab700012a2bc00002b500032a20b50004b10000000200120000001200040000001200040013000c0014001100150013000000200003000000120014"
|
||||
+ "001500000000001200160017000100000012000d000e0002000100180019000100110000004700040002000000132ab400032b2ab40004b60005c00006c"
|
||||
+ "00006b00000000200120000000600010000001900130000001600020000001300140015000000000013001a0017000110410018001b0001001100000030"
|
||||
+ "00020002000000062a2bb60007b00000000200120000000600010000000c00130000000c0001000000060014001500000002001c00000002001d001e000"
|
||||
+ "00002001f";
|
||||
|
||||
private static final Function<Object, byte[]> strByteFunction;
|
||||
|
||||
private static final Function<Object, byte[]> sbByteFunction;
|
||||
|
||||
private static final javax.net.ssl.SSLContext DEFAULTSSL_CONTEXT;
|
||||
|
||||
private static final javax.net.ssl.HostnameVerifier defaultVerifier = (s, ss) -> true;
|
||||
|
||||
static {
|
||||
Function<Object, char[]> strFunction0 = null;
|
||||
Function<Object, char[]> sbFunction0 = null;
|
||||
Function<Object, char[]> strCharFunction0 = null;
|
||||
Function<Object, char[]> sbCharFunction0 = null;
|
||||
Function<Object, byte[]> strByteFunction0 = null;
|
||||
Function<Object, byte[]> sbByteFunction0 = null;
|
||||
try {
|
||||
Field f = String.class.getDeclaredField("value");
|
||||
if (f.getType() == char[].class) { //JDK9及以上不再是char[]
|
||||
@@ -97,21 +140,40 @@ public final class Utility {
|
||||
final Method fm = usafe.getClass().getMethod("objectFieldOffset", Field.class);
|
||||
final long fd1 = (Long) fm.invoke(usafe, f);
|
||||
final long fd2 = (Long) fm.invoke(usafe, StringBuilder.class.getSuperclass().getDeclaredField("value"));
|
||||
byte[] bytes = hexToBin(functionClassBinary);
|
||||
byte[] bytes = hexToBin(functionCharClassBinary);
|
||||
Class<Attribute> creatorClazz = (Class<Attribute>) new ClassLoader() {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass("org.re" + "dkale.util.AnonymousArrayFunction", bytes);
|
||||
}.loadClass("org.re" + "dkale.util.AnonymousCharArrayFunction", bytes);
|
||||
|
||||
strFunction0 = (Function<Object, char[]>) creatorClazz.getDeclaredConstructor(Object.class, long.class).newInstance(usafe, fd1);
|
||||
sbFunction0 = (Function<Object, char[]>) creatorClazz.getDeclaredConstructor(Object.class, long.class).newInstance(usafe, fd2);
|
||||
strCharFunction0 = (Function<Object, char[]>) creatorClazz.getDeclaredConstructor(Object.class, long.class).newInstance(usafe, fd1);
|
||||
sbCharFunction0 = (Function<Object, char[]>) creatorClazz.getDeclaredConstructor(Object.class, long.class).newInstance(usafe, fd2);
|
||||
} else {
|
||||
Class unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
Field safeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||
safeField.setAccessible(true);
|
||||
final Object usafe = safeField.get(null);
|
||||
final Method fm = usafe.getClass().getMethod("objectFieldOffset", Field.class);
|
||||
final long fd1 = (Long) fm.invoke(usafe, f);
|
||||
final long fd2 = (Long) fm.invoke(usafe, StringBuilder.class.getSuperclass().getDeclaredField("value"));
|
||||
byte[] bytes = hexToBin(functionByteClassBinary);
|
||||
Class<Attribute> creatorClazz = (Class<Attribute>) new ClassLoader() {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass("org.re" + "dkale.util.AnonymousByteArrayFunction", bytes);
|
||||
|
||||
strByteFunction0 = (Function<Object, byte[]>) creatorClazz.getDeclaredConstructor(Object.class, long.class).newInstance(usafe, fd1);
|
||||
sbByteFunction0 = (Function<Object, byte[]>) creatorClazz.getDeclaredConstructor(Object.class, long.class).newInstance(usafe, fd2);
|
||||
}
|
||||
} catch (Throwable e) { //不会发生
|
||||
//e.printStackTrace();
|
||||
}
|
||||
strFunction = strFunction0;
|
||||
sbFunction = sbFunction0;
|
||||
strCharFunction = strCharFunction0;
|
||||
sbCharFunction = sbCharFunction0;
|
||||
strByteFunction = strByteFunction0;
|
||||
sbByteFunction = sbByteFunction0;
|
||||
|
||||
try {
|
||||
DEFAULTSSL_CONTEXT = javax.net.ssl.SSLContext.getInstance("SSL");
|
||||
@@ -610,6 +672,30 @@ public final class Utility {
|
||||
return news;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将int数组倒序
|
||||
*
|
||||
* @param array 原数组
|
||||
*
|
||||
* @return 新数组
|
||||
*/
|
||||
public static int[] reverseSort(final int[] array) {
|
||||
if (array == null || array.length == 0) return array;
|
||||
return Arrays.stream(array).boxed().sorted(Collections.reverseOrder()).mapToInt(x -> x).toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将long数组倒序
|
||||
*
|
||||
* @param array 原数组
|
||||
*
|
||||
* @return 新数组
|
||||
*/
|
||||
public static long[] reverseSort(final long[] array) {
|
||||
if (array == null || array.length == 0) return array;
|
||||
return Arrays.stream(array).boxed().sorted(Collections.reverseOrder()).mapToLong(x -> x).toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将元素从数组中删除
|
||||
*
|
||||
@@ -1837,8 +1923,8 @@ public final class Utility {
|
||||
|
||||
public static byte[] encodeUTF8(final String value) {
|
||||
if (value == null) return new byte[0];
|
||||
if (strFunction == null) return encodeUTF8(value.toCharArray());
|
||||
return encodeUTF8((char[]) strFunction.apply(value));
|
||||
if (strCharFunction == null) return encodeUTF8(value.toCharArray());
|
||||
return encodeUTF8((char[]) strCharFunction.apply(value));
|
||||
}
|
||||
|
||||
public static byte[] encodeUTF8(final char[] array) {
|
||||
@@ -1848,10 +1934,10 @@ public final class Utility {
|
||||
public static byte[] encodeUTF8(final char[] text, final int start, final int len) {
|
||||
char c;
|
||||
int size = 0;
|
||||
final char[] chars = text;
|
||||
final char[] chs = text;
|
||||
final int limit = start + len;
|
||||
for (int i = start; i < limit; i++) {
|
||||
c = chars[i];
|
||||
c = chs[i];
|
||||
if (c < 0x80) {
|
||||
size++;
|
||||
} else if (c < 0x800) {
|
||||
@@ -1865,14 +1951,14 @@ public final class Utility {
|
||||
final byte[] bytes = new byte[size];
|
||||
size = 0;
|
||||
for (int i = start; i < limit; i++) {
|
||||
c = chars[i];
|
||||
c = chs[i];
|
||||
if (c < 0x80) {
|
||||
bytes[size++] = (byte) c;
|
||||
} else if (c < 0x800) {
|
||||
bytes[size++] = (byte) (0xc0 | (c >> 6));
|
||||
bytes[size++] = (byte) (0x80 | (c & 0x3f));
|
||||
} else if (Character.isSurrogate(c)) { //连取两个
|
||||
int uc = Character.toCodePoint(c, chars[i + 1]);
|
||||
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||
bytes[size++] = (byte) (0xf0 | ((uc >> 18)));
|
||||
bytes[size++] = (byte) (0x80 | ((uc >> 12) & 0x3f));
|
||||
bytes[size++] = (byte) (0x80 | ((uc >> 6) & 0x3f));
|
||||
@@ -1889,14 +1975,28 @@ public final class Utility {
|
||||
|
||||
public static char[] charArray(String value) {
|
||||
if (value == null) return null;
|
||||
if (strFunction == null) return value.toCharArray();
|
||||
return strFunction.apply(value);
|
||||
if (strCharFunction == null) return value.toCharArray();
|
||||
return strCharFunction.apply(value);
|
||||
}
|
||||
|
||||
public static char[] charArray(StringBuilder value) {
|
||||
if (value == null) return null;
|
||||
if (sbFunction == null) return value.toString().toCharArray();
|
||||
return sbFunction.apply(value);
|
||||
if (sbCharFunction == null) return value.toString().toCharArray();
|
||||
return sbCharFunction.apply(value);
|
||||
}
|
||||
|
||||
//只能是单字节字符串
|
||||
public static byte[] byteArray(String latin1Value) {
|
||||
if (latin1Value == null) return null;
|
||||
if (strByteFunction == null) return latin1Value.getBytes();
|
||||
return strByteFunction.apply(latin1Value);
|
||||
}
|
||||
|
||||
//只能是单字节字符串
|
||||
public static byte[] byteArray(StringBuilder latin1Value) {
|
||||
if (latin1Value == null) return null;
|
||||
if (sbByteFunction == null) return latin1Value.toString().getBytes();
|
||||
return sbByteFunction.apply(latin1Value);
|
||||
}
|
||||
|
||||
public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] array) {
|
||||
@@ -1909,8 +2009,8 @@ public final class Utility {
|
||||
|
||||
public static int encodeUTF8Length(String value) {
|
||||
if (value == null) return -1;
|
||||
if (strFunction == null) return encodeUTF8Length(value.toCharArray());
|
||||
return encodeUTF8Length(strFunction.apply(value));
|
||||
if (strCharFunction == null) return encodeUTF8Length(value.toCharArray());
|
||||
return encodeUTF8Length(strCharFunction.apply(value));
|
||||
}
|
||||
|
||||
public static int encodeUTF8Length(final char[] text) {
|
||||
@@ -1920,10 +2020,10 @@ public final class Utility {
|
||||
public static int encodeUTF8Length(final char[] text, final int start, final int len) {
|
||||
char c;
|
||||
int size = 0;
|
||||
final char[] chars = text;
|
||||
final char[] chs = text;
|
||||
final int limit = start + len;
|
||||
for (int i = start; i < limit; i++) {
|
||||
c = chars[i];
|
||||
c = chs[i];
|
||||
if (c < 0x80) {
|
||||
size++;
|
||||
} else if (c < 0x800) {
|
||||
@@ -1956,13 +2056,13 @@ public final class Utility {
|
||||
//返回的ByteBuffer为扩展buffer,为null表示参数中的buffer足够存储数据
|
||||
public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] text, final int start, final int len) {
|
||||
char c;
|
||||
char[] chars = text;
|
||||
char[] chs = text;
|
||||
final int limit = start + len;
|
||||
int remain = buffer.remaining();
|
||||
final ByteBuffer buffer2 = remain >= bytesLength ? null : ByteBuffer.allocate(bytesLength - remain + 4); //最差情况buffer最后两byte没有填充
|
||||
ByteBuffer buf = buffer;
|
||||
for (int i = start; i < limit; i++) {
|
||||
c = chars[i];
|
||||
c = chs[i];
|
||||
if (c < 0x80) {
|
||||
if (buf.remaining() < 1) buf = buffer2;
|
||||
buf.put((byte) c);
|
||||
@@ -1972,7 +2072,7 @@ public final class Utility {
|
||||
buf.put((byte) (0x80 | (c & 0x3f)));
|
||||
} else if (Character.isSurrogate(c)) { //连取两个
|
||||
if (buf.remaining() < 4) buf = buffer2;
|
||||
int uc = Character.toCodePoint(c, chars[i + 1]);
|
||||
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||
buf.put((byte) (0xf0 | ((uc >> 18))));
|
||||
buf.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||
buf.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.redkale.test.convert;
|
||||
|
||||
import org.redkale.convert.ConvertField;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.util.Attribute;
|
||||
|
||||
@@ -15,44 +16,53 @@ import org.redkale.util.Attribute;
|
||||
public class BiFunctionConvertMain {
|
||||
|
||||
public static class GamePlayer {
|
||||
|
||||
public int userid;
|
||||
|
||||
public String username;
|
||||
|
||||
public int[] cards;
|
||||
}
|
||||
|
||||
public static class GameTable {
|
||||
|
||||
public int tableid;
|
||||
|
||||
public GamePlayer[] players;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
GamePlayer player1 = new GamePlayer();
|
||||
player1.userid= 1;
|
||||
player1.username="玩家1";
|
||||
player1.cards = new int[]{11,12,13,14,15};
|
||||
player1.userid = 1;
|
||||
player1.username = "玩家1";
|
||||
player1.cards = new int[]{11, 12, 13, 14, 15};
|
||||
GamePlayer player2 = new GamePlayer();
|
||||
player2.userid= 2;
|
||||
player2.username="玩家2";
|
||||
player2.cards = new int[]{21,22,23,24,25};
|
||||
player2.userid = 2;
|
||||
player2.username = "玩家2";
|
||||
player2.cards = new int[]{21, 22, 23, 24, 25};
|
||||
GamePlayer player3 = new GamePlayer();
|
||||
player3.userid= 3;
|
||||
player3.username="玩家3";
|
||||
player3.cards = new int[]{31,32,33,34,35};
|
||||
player3.userid = 3;
|
||||
player3.username = "玩家3";
|
||||
player3.cards = new int[]{31, 32, 33, 34, 35};
|
||||
GameTable table = new GameTable();
|
||||
table.tableid=100;
|
||||
table.players = new GamePlayer[]{player1,player2,player3};
|
||||
table.tableid = 100;
|
||||
table.players = new GamePlayer[]{player1, player2, player3};
|
||||
JsonConvert convert1 = JsonConvert.root();
|
||||
System.out.println(convert1.convertTo(table));
|
||||
JsonConvert convert2 = convert1.newConvert((Attribute t, Object u) -> {
|
||||
if(t.field().equals("cards") && u instanceof GamePlayer){
|
||||
int userid = ((GamePlayer)u).userid;
|
||||
if(userid == 3) return null; //玩家3的cards不输出
|
||||
if (t.field().equals("cards") && u instanceof GamePlayer) {
|
||||
int userid = ((GamePlayer) u).userid;
|
||||
if (userid == 3) return null; //玩家3的cards不输出
|
||||
return t.get(u);
|
||||
}
|
||||
return t.get(u);
|
||||
}, (Object u) -> {
|
||||
if (table != u) return null;
|
||||
//return new ConvertField[]{new ConvertField("extcol1", 30), new ConvertField("extcol2", "扩展字段值")};
|
||||
return ConvertField.ofArray("extcol1", 30, "extcol2", "扩展字段值");
|
||||
});
|
||||
System.out.println(convert2.convertTo(table));
|
||||
//{"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"cards":[31,32,33,34,35],"userid":3,"username":"玩家3"}],"tableid":100}
|
||||
//{"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"userid":3,"username":"玩家3"}],"tableid":100}
|
||||
//{"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"userid":3,"username":"玩家3"}],"tableid":100,"extcol1":30,"extcol2":"扩展字段值"}
|
||||
}
|
||||
}
|
||||
|
||||
67
test/org/redkale/test/util/ResourceInjectMain.java
Normal file
67
test/org/redkale/test/util/ResourceInjectMain.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.reflect.Field;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class ResourceInjectMain {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
ResourceFactory factory = ResourceFactory.root();
|
||||
factory.register(new CustomConfLoader());
|
||||
InjectBean bean = new InjectBean();
|
||||
factory.inject(bean);
|
||||
}
|
||||
|
||||
public static class CustomConfLoader implements ResourceInjectLoader<CustomConf> {
|
||||
|
||||
@Override
|
||||
public void load(ResourceFactory factory, Object src, CustomConf annotation, Field field, Object attachment) {
|
||||
try {
|
||||
field.set(src, new File(annotation.path()));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("对象是 src =" + src + ", path=" + annotation.path());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<CustomConf> annotationType() {
|
||||
return CustomConf.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class InjectBean {
|
||||
|
||||
@CustomConf(path = "conf/test.xml")
|
||||
public File conf;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Target({FIELD})
|
||||
@Retention(RUNTIME)
|
||||
public static @interface CustomConf {
|
||||
|
||||
String path();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user