Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b69e7d02b | ||
|
|
02a10bf014 | ||
|
|
004b83172e | ||
|
|
fee4555cef | ||
|
|
758bd7de72 | ||
|
|
b2dd366640 | ||
|
|
934c82eadd | ||
|
|
c7ed6574cc | ||
|
|
2ea2667fa7 | ||
|
|
34ae2d38c5 | ||
|
|
a1c95544cb | ||
|
|
c6dc38c35c | ||
|
|
39203ab598 | ||
|
|
51a95a84aa | ||
|
|
8a8d45e642 | ||
|
|
52eb7dbc0c | ||
|
|
0e14b60f12 |
@@ -77,6 +77,7 @@
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<addMavenDescriptor>false</addMavenDescriptor>
|
||||
<manifest>
|
||||
<mainClass>org.redkale.boot.Application</mainClass>
|
||||
</manifest>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -241,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -89,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++] = '"';
|
||||
@@ -162,13 +162,13 @@ public class JsonWriter extends Writer {
|
||||
@Override
|
||||
public final void writeFieldName(String fieldName, Type fieldType, int fieldPos) {
|
||||
if (this.comma) writeTo(',');
|
||||
writeTo(true, fieldName);
|
||||
writeLatin1To(true, fieldName);
|
||||
writeTo(':');
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeSmallString(String value) {
|
||||
writeTo(true, value);
|
||||
writeLatin1To(true, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -314,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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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格式输出
|
||||
*
|
||||
@@ -637,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();
|
||||
@@ -681,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();
|
||||
@@ -719,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();
|
||||
@@ -736,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);
|
||||
}
|
||||
}
|
||||
@@ -749,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();
|
||||
@@ -772,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) {
|
||||
@@ -899,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);
|
||||
@@ -978,6 +1004,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
}
|
||||
}
|
||||
buffer.put(LINE);
|
||||
this.headWritedSize = buffer.position() - oldpos;
|
||||
this.headBuffer = buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -1003,7 +1031,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public HttpResponse skipHeader() {
|
||||
this.headsended = true;
|
||||
this.headWritedSize = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1210,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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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-rc2";
|
||||
return "2.0.0-rc3";
|
||||
}
|
||||
|
||||
public static int getMajorVersion() {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
@@ -1861,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) {
|
||||
@@ -1913,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) {
|
||||
@@ -1933,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) {
|
||||
|
||||
Reference in New Issue
Block a user